# vector
向量,变长数组(长度根据需要而自动改变的数组)
# 使用前
添加
#include <vector>
using namespace std;
# 定义
# 一维
vector <typename> name;
vector<int> name;
vector<double> name;
vector<char> name;
vector<node> name;//node是结构体类型
vector <vector <int> > name; //>>之间要加空格
# 二维
vector<typename> Arrayname[arraySize]; | |
vector<int> vi[100]; |
vector<vector<int> > name
和 vector<int> name[Size]
不同,后者的一维长度固定为 Size
# 访问
# 通过下标访问
vi[index]
# 通过迭代器进行访问
vector<typename>::iterator it;
vector<int>::iterator it;
vector<double>::iterator it;
使用 *it
访问 vector 里面的元素
# 常用函数
* push_back() 在vector后面添加一个元素 | |
* pop_back() 删除vector的尾元素 | |
* size() 获得vector()中元素的个数 | |
* clear() 清空vector中的所有元素 | |
* insert() 用来向vector的任意迭代器it处插入一个元素x | |
* erase() | |
erase(it) 删除迭代器为it处的元素 | |
erase(first, last) 删除[first, last)内的所有元素 |
上面的 insert 和 erase 是只能用迭代器的吗? 是的,可以输入看看代码提示
# set
集合,内部自动有序且不含重复元素的容器
# 使用前添加
#include <set>
using namespace std;
# 访问
只能通过迭代器访问
set<typename>::iterator it; | |
set<int>::iterator it; |
由于除开 vector 和 string 之外的 STL 容器都不支持 *(it+i) 的访问方式,因此只能按如下方式枚举
#include <stdio.h> | |
#include <set> | |
using namespace std; | |
int main(void) | |
{ | |
set<int> st; | |
st.insert(3); | |
st.insert(5); | |
st.insert(2); | |
st.insert(3); | |
for (set<int>::iterator it = st.begin(); it != st.end(); it++) | |
printf("%d ", *it); | |
return 0; | |
} |
set 内的元素自动递增排序,且自动去除了重复元素
# 常用函数
* insert(x) 将x插入set容器中,并自动递增排序和去重 | |
* find(value) 返回set中对应值为value的迭代器,如果没找到则返回s.end(),末尾迭代器的后一个迭代器 | |
* erase() | |
* st.erase(it) it为所需要删除元素的迭代器(删除单个元素) | |
* st.erase(value) value为所需要删除元素的值(删除单个元素) | |
* st.erase(first, second) first为所需要删除区间的起始迭代器,second为所需要删除区间的末尾迭代器的下一个地址 | |
* size() 获得set内元素的个数 | |
* clear() 清空set中的所有元素 | |
* count(u) 查询u在set中出现的次数(0或1) |
# string
# 使用前添加
#include <string> | |
using namespace std; |
# 定义
string str; | |
string str = "abcd"; // 可以在定义时直接初始化 |
# 访问
#### 通过下标
str[index] |
如果要读入和输出整个字符串,则只能用 cin 和 cout
#include <iostream> //cin 和 cout 在 iostream 头文件中 | |
#include <string> | |
using namespace std; | |
int main(void) | |
{ | |
string str; | |
cin >> str; | |
cout << str; | |
return 0; | |
} |
用 c_str()
将 string 类型转换为字符数组,用 printf 进行输出
#include <iostream> //cin 和 cout 在 iostream 头文件中 | |
#include <string> | |
using namespace std; | |
int main(void) | |
{ | |
string str = "abcd"; | |
printf("%s", str.c_str()); | |
return 0; | |
} |
# 通过迭代器
# 定义
string::iterator it; |
通过 * it 来访问 string 里的每一位
#include <iostream> | |
#include <string> | |
using namespace std; | |
int main(void) | |
{ | |
string str = "abcd"; | |
for (string::iterator it = str.begin(); it != str.end(); it++) | |
printf("%c", *it); | |
return 0; | |
} |
string 和 vector 一样,支持直接对迭代器进行加减某个数字,如 str.begin () + 3 的写法是可行的
# 常用函数
operator+= 将两个 string 直接拼接起来
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
string str1 = "abc", str2 = "xyz", str3;
str3 = str1 + str2; // 将 str1 和 str2 拼接起来,赋值给 str3
str1 += str2; // 将 str2 直接拼接到 str1 上
cout << str1 << endl;
cout << str3 << endl;
//abcxyz
return 0;
}
compare operator
两个 string 类型可以直接使用 ==、!=、<、<=、>、>= 比较大小,比较规则是字典序
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
string str1 = "aa", str2 = "aaa", str3 = "abc", str4 = "xyz";
if (str1 < str2)
cout << "ok1" << endl;
if (str1 != str3)
cout << "ok2" << endl;
if (str4 > str3)
cout << "ok3" << endl;
return 0;
}
length()/size()
str.size();
insert()
insert (pos, string) 在 pos 号位置插入字符串 string
string str1 = "abcxyz", str2 = "opa";
str1.insert(3, str2); // 往 str2 [3] 处插入 opq,这里 str2 直接写成 "opq" 也是可以的
//abcopqxyz
insert (it, it2, it3) it 为原字符串的欲插入位置,it2 和 it3 为待插入字符串的首尾迭代器,用来表示串 [it2, it3) 将被插在 it 的位置上
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
string str = "abcxyz", str2 = "opq";
str.insert(str.begin() + 3, str2.begin(), str2.end());
return 0;
}
erase()
- str.erase (it) 用于删除单个元素,it 为需要删除的元素的迭代器
- str.erase (first, last) first 为需要删除区间的起始迭代器,last 为需要删除区间的末尾迭代器的下一个地址
- str.erase (pos, length),pos 为需要开始删除的起始位置(整数),length 为删除的字符个数
clear () 清空 string 中的数据
substr (pos, len) 返回从 pos 位开始、长度为 len 的子串
string::npos
string::npos 是一个常数,其本身的值为 - 1,但由于是 unsigned_int 类型,因此实际上也可以认为是 unsigned_int 类型的最大值。string_npos 用以作为 find 函数失配时的返回值。
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
if (string::npos == -1)
cout << "-1 is true." << endl;
if (string::npos == 4294967295)
cout << "4294967295 is also true." << endl;
return 0;
}
find()
- str.find (str2) 当 str2 是 str 的子串(str 也可以是一个字符)时,返回其在 str 中第一次出现的位置(字符串中字符的位置编号从 0 开始);如果 str2 不是 str 的子串,那么返回 string::npos
- str.find (str2, pos) 从 str 的 pos 号位开始匹配 str2,返回值与上相同
replace()
- str.replace (pos, len, str2) 把 str 从 pos 号位开始、长度为 len 的子串替换为 str2
- str.replace (it1, it2, str2) 把 str 的迭代器 [it1, it2) 范围的子串替换为 str2
# 注:
可以直接将字符和 string 类型的字符串通过 +
拼接起来
string str; | |
str = '0' + str; |
但是,不能加上一个整数,以下两种都是错误的
str = '0' + 2 + str; | |
str = ('0' + 2) + str; |
应改为
str = char('0' + 2) + str; |
# map
map 可以将任何基本类型(包括 STL 容器)映射到任何基本类型(包括 STL 容器)
# 使用前添加
#include <map>
using namespace std;
# 定义
map<typename1, typename2> mp;
map<int, int> mp;
map<string, int> mp;
map<set<int>, string> mp;
# 访问
# 通过下标
map<char, int> mp;
mp['a'] = 20;
printf("%d", mp['a']);
# 通过迭代器
# 定义
map<typename1, typename2>::iterator it;
通过 it->first
访问键, it->second
访问值
# 代码
#include <stdio.h> | |
#include <map> | |
#include <iostream> | |
using namespace std; | |
int main(void) | |
{ | |
map<char, int> mp; | |
mp['a'] = 1; | |
mp['b'] = 2; | |
mp['c'] = 3; | |
for (map<char, int>::iterator it = mp.begin(); it != mp.end(); it++) | |
cout << it->first << it->second << endl; | |
} |
map 会以键从小到大的顺序自动排序
# 插入
#include <iostream> | |
#include <map> | |
#include <string> | |
using namespace std; | |
int main(void) | |
{ | |
map<int, string> mp; | |
mp.insert(make_pair(0, "zero")); | |
mp.insert(pair<int, string>(1, "one")); | |
mp[2] = "two"; | |
for (map<int, string>::iterator it = mp.begin(); it != mp.end(); it++) | |
{ | |
cout << it->first << " " << it->second << endl; | |
} | |
} |
以上三种用法,虽然都可以实现数据的插入,但是它们是有区别的,当然了第一种和第二种在效果上是完成一样的,用 insert 函数插入数据,在数据的 插入上涉及到集合的唯一性这个概念,即当 map 中有这个关键字时,insert 操作是不能在插入数据的,但是用数组方式就不同了,它可以覆盖以前该关键字对 应的值
# 常用函数
* find(key) 返回键为key的映射的迭代器 | |
* erase() | |
mp.erase(it) it为需要删除元素的迭代器 | |
mp.erase(key) key为欲删除的映射的键 | |
mp.erase(first, last) first为需要删除区间的起始迭代器,last为需要删除区间的末尾迭代器的下一个地址 | |
* size() 获得map中映射的对数 | |
* clear() 清空map中的所有元素 | |
* count(x) x为数对中的first,返回个数,即:有则返回1,没有则返回0 |
#include <iostream> | |
#include <map> | |
using namespace std; | |
map<int, int> mp; | |
int main() | |
{ | |
mp[1] = 0; | |
cout << mp.count(1) << endl; //1 | |
cout << mp.count(2) << endl; //0 | |
cout << mp.count(2) << endl; //0 | |
} |
# 注
如果有 map<int, int> mp
,但实现并没有存储 mp[0]
而直接输出时, mp[0]
为 0
如果有 map<string, string> mp
,但并没有存储 mp["s"]
而直接输出时, mp["s"]
为空字符串 ""
。
#include <iostream> | |
#include <string> | |
#include <map> | |
using namespace std; | |
int main(void) | |
{ | |
map<string, int> m; | |
cout << m["jjj"] << endl; | |
} | |
// 输出 0 |
# queue
# 使用前添加
#include <queue> | |
using namespace std; |
# 定义
queue<typename> name; |
# 常用函数
* push() 入队 | |
* front() 获得队首元素 | |
* back() 获得队尾元素 | |
* pop() 队首元素出队 |
# priority_queue
# 使用前添加
#include <queue> | |
using namespace std; |
# 定义
priority_queue<typename> name; |
# 访问
只能通过 top()
函数访问队首元素(也可以称为堆顶元素),即优先级最高的元素。
#include <iostream> | |
#include <queue> | |
using namespace std; | |
int main(void) | |
{ | |
priority_queue<int> q; | |
q.push(3); | |
q.push(4); | |
q.push(1); | |
cout << q.top() << endl; // 输出 4 | |
return 0; | |
} |
# 常用函数
* push() q.push(x)将x入队 | |
* top() q.top()获得队首元素 | |
* pop() q.pop()令队首元素(即堆顶元素)出队 | |
* empty() 检测优先队列是否为空,返回true则空,返回false则非空 | |
* size() 返回优先队列内元素的个数 |
# 元素优先级的设置
# 基本数据类型
(int、double、char 等),优先队列对它们的优先级设置一般是数字大的优先级越高(如果是 char 型,则是字典序最大的)。对基本数据类型来说,下面两种优先队列的定义时等价的(以 int 型为例,注意最后两个 > 之间有一个空格)
priority_queue<int> q; | |
priority_queue<int, vector<int>, less<int> > q; |
第二种定义方式的尖括号内多出了两个参数:一个是 vector <int>
,另一个是 less <int>
。其中 vector <int>
填写的是来承载底层数据结构堆(heap)的容器,如果第一个参数是 double 或 char 型,则此处填写的是 vector <double>
或 vector <char>
;而第三个参数 less <int>
则是对第一个参数的比较类,less <int>
表示数字大的优先级大,而 greater <int>
表示数字小的优先级越大。
如果想让优先队列总是把最小的元素放在队首,只需进行如下定义:
priority_queue<int, vector<int>, greater<int> > q; |
# 结构体
小于号的作用不变(return 中还是小于号),则数字大的优先级高
对水果的名称和价格建立一个结构体
struct fruit{ | |
string name; | |
int price; | |
} |
现在希望按水果的价格高的为优先级高,就需要重载(overload)小于号 “<”。重载是指对已有的运算符进行重新定义,也就是说,可以改变小于号的功能(例如把它重载为大于号的功能)。
struct fruit{ | |
string name; | |
int price; | |
friend bool operator < (fruit f1, fruit f2) | |
{ | |
return f1.price < f2.price; | |
} | |
} |
可以看到,fruit 结构体中增加了一个函数,其中 “friend” 为友元。后面的 bool operator < (fruit f1, fruit f2)
对 fruit 类型的操作符 <
进行了重载(重载大于号会编译错误,因为从数字上来说只需要重载小于号,即 f1> f2 等价于判断 f2 < f1,而 f1 == f2 则等价于判断!(f1 < f2) && !(f2 < f1),函数内部为 return f1.price < f2.price
,因此重载后小于号还是小于号的作用。此时就可以直接定义 fruit 类型的优先队列,其内部就是以价格高的水果为优先级高。
priority_queue<fruit> q; |
同理,如果想要以价格低的水果为优先级高,那么只需要把 return 中的小于号改为大于号即可。
#include <iostream> | |
#include <string> | |
#include <queue> | |
using namespace std; | |
struct fruit { | |
string name; | |
int price; | |
friend bool operator < (fruit f1, fruit f2) | |
{ | |
return f1.price > f2.price; | |
} | |
}f1, f2, f3; | |
int main(void) | |
{ | |
priority_queue<fruit> q; | |
f1.name = "桃子"; | |
f1.price = 3; | |
f2.name = "梨子"; | |
f2.price = 4; | |
f3.name = "苹果"; | |
f3.price = 1; | |
q.push(f1); | |
q.push(f2); | |
q.push(f3); | |
cout << q.top().name << " " << q.top().price << endl; | |
return 0; | |
} |
此处对小于号的重载与排序函数 sort 中的 cmp 函数有些相似,它们的参数都是两个变量,函数内部都是 return 了 true 或者 false。事实上,这两者的作用确实是类似的,只不过效果看上去似乎是 “相反的”。在排序中,如果是 return f1.price > f2.price
,那么则是按价格从高到低排序,但是在优先队列中却是把价格低的放到队首。原因在于,优先队列本身默认的规则就是优先级高的放在队首,因此把小于号重载为大于号的功能时只是把这个规则反向了一下。
跟 sort 中的 cmp 函数那样写在结构体外面:只需要把 friend 去掉,把小于号改成一对小括号,然后把重载的函数写在结构体外面,然后把重载的函数写在结构体外面,同时将其用 struct 包装起来,如下
struct cmp { | |
bool operator () (fruit f1, fruit f2) | |
{ | |
return f1.price > f2.price; | |
} | |
}; |
在这种情况下,需要用之前讲解的第二种定义方式来定义优先队列:
priority_queue<fruit, vector<fruit>, cmp> q; |
可以看到,此处只是把 greater<> 部分换成了 cmp
#include <iostream> | |
#include <string> | |
#include <queue> | |
using namespace std; | |
struct fruit { | |
string name; | |
int price; | |
}f1, f2, f3; | |
struct cmp { | |
bool operator () (fruit f1, fruit f2) | |
{ | |
return f1.price > f2.price; | |
} | |
}; | |
int main(void) | |
{ | |
priority_queue<fruit, vector<fruit>, cmp> q; | |
f1.name = "桃子"; | |
f1.price = 3; | |
f2.name = "梨子"; | |
f2.price = 4; | |
f3.name = "苹果"; | |
f3.price = 1; | |
q.push(f1); | |
q.push(f2); | |
q.push(f3); | |
cout << q.top().name << " " << q.top().price << endl; | |
return 0; | |
} |
最后指出,如果结构体内的数据较为庞大(例如出现了字符串或者数组),建议使用引用来提高效率,此时比较类的参数中需要加上 const
和 &
,如下所示:
friend bool operator < (const fruit & f1, const fruit & f2) | |
return f1.price < f2.price; | |
bool operator () (const fruit& f1, const fruit & f2) | |
return f1.price < f2.price; |
# 应用
- 可以采用从小到大的优先队列实现哈夫曼树的计数
# deque
# 使用前添加
#include <deque> | |
using namespace std; |
# 定义
deque<typename> name; | |
deque<int> d; |
# 常用函数
* begin() 返回指向容器中第一个元素的迭代器 | |
* end() 返回指向容器中最后一个元素所在位置后一个位置的迭代器 | |
* rbegin() 返回指向最后一个元素的迭代器 | |
* rend() 返回指向第一个元素所在位置的前一个位置的迭代器 | |
* size() 返回实际元素个数 | |
* empty() 判断容器中是否有元素,若无元素,则返回true,否则返回false | |
* front() 返回第一个元素的引用 | |
* back() 返回最后一个元素的引用 | |
* push_back() 在序列的尾部添加一个元素 | |
* push_front() 在序列的头部添加一个元素 | |
* pop_back() 移除容器尾部的元素 | |
* pop_front() 移除容器头部的元素 |
# stack
# 使用前添加
#include <stack> | |
using namespace std; |
# 定义
stack<typename> name; |
# 访问
只能通过 top()
访问栈顶元素
st.top() |
# 常用函数
* push() st.push(x)将x入栈 | |
* top() st.top()获得栈顶元素 | |
* pop() st.pop()弹出栈顶元素 | |
* empty() st.empty()检测stack内是否为空,返回true为空,返回false为非空 | |
* size() st.size()返回st内的元素个数 |
# pair
# 使用前添加
#include <utility> | |
using namespace std; |
注:由于 map 的内部实现中设计 pair,因此添加 map 头文件时会自动添加 utility 头文件,此时如果需要使用 pair,就不需要额外再去添加 utility 头文件了。因此,记不住 “utility” 拼写的读者可以偷懒的用 map 头文件来代替 utility 头文件。
# 定义
pair 有两个参数,分别对应 first 和 second 的数据类型,它们可以是任意的基本数据类型或容器
pair<typename1, typename2> name; |
pair<string, int> p; | |
pair<string, int> p("haha", 5);// 后面跟上填写有想要初始化的元素的小括号进行初始化 |
如果想要在代码中临时构建一个 pair,有如下两种方法
pair<string, int>("haha", 5)
make_pair("haha", 5)
# 访问
按结构体的方式去访问
#include <iostream> | |
#include <utility> | |
#include <string> | |
using namespace std; | |
int main(void) | |
{ | |
pair<string, int> p; | |
p.first = "haha"; | |
p.second = 5; | |
cout << p.first << " " << p.second << endl; | |
p = make_pair("xixi", 55); | |
cout << p.first << " " << p.second << endl; | |
p = pair<string, int>("heihei", 555); | |
cout << p.first << " " << p.second << endl; | |
return 0; | |
} |
# 常用函数
- 比较操作数 两个 pair 类型数据可以直接使用 ==、!=、<、<=、>、>= 比较大小,比较规则是先以 first 的大小作为标准,只有当 first 相等时才去判别 second 的大小
pair<int, int> p1(5, 10); | |
pair<int, int> p2(2, 5); | |
if(p1 < p2) printf("y"); |
# 用途
- 用来代替二元结构体及其构造函数
- 作为 map 的键值对来进行插入
#include <iostream> | |
#include <string> | |
#include <map> | |
using namespace std; | |
int main(void) | |
{ | |
map<string, int> mp; | |
mp.insert(make_pair("haha", 5)); | |
mp.insert(pair<string, int>("heihei", 10)); | |
for (map<string, int>::iterator it = mp.begin(); it != mp.end(); it++) | |
cout << it->first << " " << it->second << endl; | |
return 0; | |
} |
# algorithm 头文件下的常用函数
需要在头问下加一行 using namespace std;
才能正常使用
# max ()、min () 和 abs ()
max (x, y) 和 min (x, y) 分别返回 x 和 y 中的最大值和最小值,且参数必须是两个(可以是浮点数)。如果想返回三个数 x、y 和 z 的最大值,可以使用 max (x, max (y, z)) 的写法。
abs (x) 返回 x 的绝对值。注意:x 必须是整数,浮点型的绝对值请用 math 头文件下的 fabs。
# swap()
swap (x, y) 用来交换 x 和 y 的值
# reverse()
reverse (it, it2) 可以将数组指针在 [it, it2) 之间的元素或容器的迭代器在 [it, it2) 范围内的元素进行反转。
# fill()
fill () 可以把数组或容器中的某一段区间赋为相同的值。和 memset 不同,这里的赋值可以是数组类型对应范围中的任意值。
#include <iostream> | |
#include <algorithm> | |
using namespace std; | |
int main(void) | |
{ | |
int a[5] = {1, 2, 3, 4, 5}; | |
fill(a, a + 5, 233); // 将 a [0]~a [4] 均赋值为 233 | |
for(int i = 0; i < 5, i++) | |
cout << a[i] << " "; | |
} | |
/* | |
a 为起始元素的地址,5 为元素 | |
*/ |
# sort()
使用方式
sort(首元素地址(必填), 尾元素地址的下一个地址(必填), 比较函数(非必填)); |
如果不写比较函数,则默认对前面给出的区间进行递增排序。
# unique()
功能是将数组中相邻的重复元素去除。然而其本质是将重复的元素移动到数组的末尾,最后再将迭代器末尾指向第一个重复元素的下标(最后一个元素的下一个元素)。
unique 函数可以去除数组中相邻重复项。例如:
输入数组 a[]={1,2,3,4,4,5,6,6,6,7,8,6,7,8}
。
输出数组 a[]={1,2,3,4,5,6,7,8,6,7,8}
。
注意:想要实现完全去重功能,需要在执行 unique 函数之前先对数组进行排序。
#include<bits/stdc++.h>
using namespace std;
const int N = 100000;
int a[N+5];
int main()
{
int n;
while (cin>>n)
{
for (int i = 0;i < n;++i)
{
scanf("%d",&a[i]);
}
sort(a,a+n);
n = unique(a,a+n) - a; //n为元素个数
for (int i = 0;i < n;++i)
{
printf("%d ",a[i]);
}
puts("");
}
return 0;
}
# 实现基本比较函数 cmp
# 基本数据类型数组的排序
若比较函数不填,则默认从小到大的顺序排序。
如果想要从大到小来排序,则要使用比较函数 cmp 来 “告诉” sort 何时要交换元素(让元素的大小比较关系反过来)。
#include <stdio.h> | |
#include <iostream> | |
#include <algorithm> | |
using namespace std; | |
bool cmp(int a, int b) | |
{ | |
return a > b; // 可以理解为当 a > b 时把 a 放在 b 前面 | |
} | |
int main(void) | |
{ | |
int a[] = { 3, 1, 4, 2 }; | |
sort(a, a + 4, cmp); | |
for (int i = 0; i < 4; i++) | |
cout << a[i] << " "; | |
return 0; | |
} |
对 double 和 char 型的数组排序只需要把上面的 int 改成 double 或者 char 即可。
记忆方法:如果要把数据从小到大排序,那么就用”<“,因为”a < b“就是左小右大;如果要把数据从大到小排列,那么就用”>“,因为”a > b“就是左大右小。
# 结构体数组的排序
如果想将 ssd 数组按照 x 从大到小排序(即进行一级排序),则代码如下:
#include <stdio.h> | |
#include <iostream> | |
#include <algorithm> | |
using namespace std; | |
struct node { | |
int x, y; | |
}ssd[10]; | |
bool cmp(node a, node b) | |
{ | |
return a.x > b.x; // 按 x 值从大到小对结构体数组排序 | |
} | |
int main(void) | |
{ | |
ssd[0].x = 2; | |
ssd[0].y = 2; | |
ssd[1].x = 1; | |
ssd[1].y = 3; | |
ssd[2].x = 3; | |
ssd[2].y = 1; | |
sort(ssd, ssd + 3, cmp); | |
for (int i = 0; i < 3; i++) | |
cout << ssd[i].x << " " << ssd[i].y << endl; | |
} |
而如果想先按 x 从大到小排序,但当 x 相等的情况下,按照 y 的大小从小到大来排序(即进行二级排序),那么 cmp 的写法是:
bool cmp(node a, node b) | |
{ | |
if(a.x != b.x) | |
return a.x > b.x; | |
else | |
return a.y < b.y; | |
} |
# 容器的排序
在 STL 标准容器中,只有 vector、string、deque 是可以使用 sort 的。这是因为像 set、map 这种容器是用红黑树实现的,元素本身有序,故不允许使用 sort 排序。
以 vector 为例:
#include <stdio.h> | |
#include <iostream> | |
#include <vector> | |
#include <algorithm> | |
using namespace std; | |
bool cmp(int a, int b) // 因为 vector 中的元素为 int 型,因此仍然是 int 的比较 | |
{ | |
return a > b; | |
} | |
int main(void) | |
{ | |
vector<int> v; | |
v.push_back(3); | |
v.push_back(1); | |
v.push_back(2); | |
sort(v.begin(), v.end(), cmp); | |
for (int i = 0; i < 3; i++) | |
cout << v[i] << " "; | |
} |
string 的排序
#include <stdio.h> | |
#include <iostream> | |
#include <string> | |
#include <algorithm> | |
using namespace std; | |
int main(void) | |
{ | |
string str[3] = { "bbbb", "cc", "aaa" }; | |
sort(str, str + 3); // 将 string 型数组按字典序从小到大输出 | |
for (int i = 0; i < 3; i++) | |
cout << str[i] << endl; | |
return 0; | |
} |
如果上面这个例子中,需要按字符串长度从小到大排序,可以这样写:
#include <stdio.h> | |
#include <iostream> | |
#include <string> | |
#include <algorithm> | |
using namespace std; | |
bool cmp(string str1, string str2) | |
{ | |
return str1.length() < str2.length(); | |
} | |
int main(void) | |
{ | |
string str[3] = { "bbbb", "cc", "aaa" }; | |
sort(str, str + 3, cmp); // 将 string 型数组按字典序从小到大输出 | |
for (int i = 0; i < 3; i++) | |
cout << str[i] << endl; | |
return 0; | |
} |
# lower_bound () 和 upper_bound ()
lower_bound () 和 upper_bound () 需要用在一个有序数组或容器中。
lower_bound (first, last, val) 用来寻找在数组或容器的 [first, last) 范围内第一个值大于等于 val 元素的位置,如果是数组,则返回该位置的指针;如果是容器,则返回该位置的迭代器。
upper_bound (first, last, val) 用来寻找在数组或容器的 [first, last) 范围内第一个值大于 val 元素的位置,如果是数组,则返回该位置的指针;如果是容器,则返回该位置的迭代器。
显然,如果数组或容器中没有需要寻找的元素,则 lower_bound () 和 upper_bound () 均返回可以插入该元素的位置的指针或迭代器(即假设存在该元素时,该元素应当在的位置)。
#include <stdio.h> | |
#include <algorithm> | |
using namespace std; | |
int main(void) | |
{ | |
int a[10] = { 1, 2, 2, 3, 3, 3, 5, 5, 5, 5 }; | |
// 寻找 - 1 | |
int* lowerPos = lower_bound(a, a + 10, -1); | |
int* upperPos = upper_bound(a, a + 10, -1); | |
printf("%d, %d\n", lowerPos - a, upperPos - a); | |
// 寻找 1 | |
lowerPos = lower_bound(a, a + 10, 1); | |
upperPos = upper_bound(a, a + 10, 1); | |
printf("%d, %d\n", lowerPos - a, upperPos - a); | |
// 寻找 3 | |
lowerPos = lower_bound(a, a + 10, 3); | |
upperPos = upper_bound(a, a + 10, 3); | |
printf("%d, %d\n", lowerPos - a, upperPos - a); | |
// 寻找 6 | |
lowerPos = lower_bound(a, a + 10, 6); | |
upperPos = upper_bound(a, a + 10, 6); | |
printf("%d, %d\n", lowerPos - a, upperPos - a); | |
return 0; | |
} |
显然,如果只是想获得欲查元素的下标,就可以不使用临时指针,而直接令返回值减去数组首地址即可: