CPP-STL

参考教程: cpp-STL - AlgorithmPark
基本上是转载,跟着写了一遍理思路。

1. vector 容器

头文件 #include<vector>

(1)构造

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<iostream>
#include<vector>
using namespace std;

vector<int>b;
vector<int>a(10);
vector<int>a(10,1);//10个整型元素的向量,每个值为1
vector<int>a(b);//用向量b给a赋值
vector<int>a(b.begin(),b.begin()+3);//将b中0-2个元素赋值给a
int c[7]={1,2,3,4,5,6,7};
vector<int>a(c,c+7);
vector<int>a{1,2,3,4,5,6,7};
vector<int>a={1,2,3,4,5,6,7};

(2)基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
void test01()//基本操作  
{
vector<int> a, b;
int i=0;
//b为向量,将b的0-2个元素赋值给向量a
a.assign(b.begin(), b.begin() + 3);

//a含有4个值为2的元素
a.assign(4, 2);

//返回a的最后一个元素
a.back();

//返回a的第一个元素
a.front();

//返回a的第i元素,当且仅当a存在
a[i];

//清空a中的元素
a.clear();

//判断a是否为空,空则返回true,非空则返回false
a.empty();

//删除a向量的最后一个元素
a.pop_back();

//删除a中第一个(从第0个算起)到第二个元素,也就是说删除的元素从a.begin()+1算起(包括它)一直到a.begin()+3(不包括它)结束
a.erase(a.begin() + 1, a.begin() + 3);

//在a的最后一个向量后插入一个元素,其值为5
a.push_back(5);

//在a的第一个元素(从第0个算起)位置(前面)插入数值5,
a.insert(a.begin() + 1, 5);

//在a的第一个元素(从第0个算起)位置(前面)插入3个数,其值都为5
a.insert(a.begin() + 1, 3, 5);

//d为数组,在a的第一个元素(从第0个元素算起)的位置(前面)插入b的第三个元素到第5个元素(不包括b+6)
int d[8];
a.insert(a.begin() + 1, d + 3, d + 6);

//返回a中元素的个数
a.size();

//返回a在内存中总共可以容纳的元素个数
a.capacity();

//将a的现有元素个数调整至10个,多则删,少则补,其值随机
a.resize(10);

//将a的现有元素个数调整至10个,多则删,少则补,其值为2
a.resize(10, 2);

//将a的容量扩充至100,
a.reserve(100);

//b为向量,将a中的元素和b中的元素整体交换
a.swap(b);

//b为向量,向量的比较操作还有 != >= > <= <
a == b;
}
assign 赋值
insert 插入
resize 调整
reserve 扩充

(3)反向迭代

1
2
3
4
5
6
7
8
void test02()
{
vector<int>a={1,2,3,4,5,6,7,8,9,10};
for(vector<int>::reverse_iterator iter=a.rbegin();iter!=a.rend();iter++)
{
cout<<*iter<<endl;//10 9 8 7 6 5 4 3 2 1
}
}

(4)插入

描述 函数签名
插入位置都在 pos 迭代器之前一个位置,返回的迭代器指向插入的第一个元素
在迭代器 pos 指定的位置之前插入一个新元素 elem,并返回表示新插入元素位置的迭代器 iterator insert(pos, elem)
在迭代器 pos 指定的位置之前插入 n 个元素 elem,并返回表示第一个新插入元素位置的迭代器 iterator insert(pos, n, elem)
在迭代器 pos 指定的位置之前,插入其他容器中位于 [first, last) 区域的所有元素,并返回表示第一个新插入元素位置的迭代器 iterator insert(pos, first, last)
在迭代器 pos 指定的位置之前,插入初始化列表(用大括号 {} 括起来的多个元素),中间有逗号隔开)中的所有的元素,并返回表示第一个新插入元素位置的迭代器 iterator insert(pos, initlist)
1
2
3
4
5
6
7
8
9
10
11
12
void test03()
{
        vector<int>a={1,2,3,4,5,6,7,8,9,10};
        vector<int>::iterator it1=a.begin()+4;
        vector<int>::iterator it2=a.insert(it1,{-1,-2,-3});
        cout<<*it2<<endl;//-1,并返回表示第一个新插入元素位置的迭代器
        for(auto k:a)
        {
                cout<<k<<" ";//1 2 3 4 -1 -2 -3 5 6 7 8 9 10
        }
        cout<<endl;
}

(5)

函数 说明
pop_back() 删除 vector 容器中最后一个元素,该容器的大小(size)会减 1,但容量 (capacity) 不会发生改变。
erase(pos) 删除 vector 容器中 pos 迭代器指定位置处的元素,并返回指向被删除元素下一个位置的迭代器。该容器的大小 (size) 会减 1,但容量 (capacity) 不会发生改变。
???swap(beg)、pop_back () 先调用 swap() 函数交换要删除的目标元素和容器最后一个元素的位置,然后使用 pop_back () 删除该目标元素。
erase(beg,end) 删除 vector 容器中位于迭代器 [beg, end) 指定区域内的所有元素,并返回指向被删除区域下一个位置元素的迭代器。该容器的大小 (size) 会减小,但容量 (capacity) 不会发生改变。
remove() 删除容器中所有和指定元素值相等的元素,并返回指向最后一个元素下一个位置的迭代器。值得一提的是,调用该函数不会改变容器的大小和容量。
clear() 删除 vector 容器中所有的元素,使其变成空的 vector 容器。该函数会改变 vector 的大小 (变为 0),但不是改变其容量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void test04()
{
        vector<int>a = { 1,2,3,4,5,6,6,6,6,7,8,9,10 };
        int size = a.size();
        ptrdiff_t cnt = count(a.begin(), a.end(), 6);//ptrdiff==long long,用于计算6出现的次数
        auto it = remove(a.begin(), a.end(), 6);//移除所有的6,不会改变容器的大小和容量,只是覆盖
        cout << *it << endl;//7,remove 返回的迭代器 it 指向 7,也就是第一个不为 6 的元素之后的新尾部。
        cout << cnt << endl;//4
        for (auto k : a)
        {
                cout << k << " ";//1 2 3 4 5 7 8 9 10 7 8 9 10
        }
        cout << endl;
        a.resize(size - cnt);//调整向量大小,除去末尾的6
        for (auto k : a)
        {
                cout << k << " ";//1 2 3 4 5 7 8 9 10
        }
}

2.deque 容器

头文件 #include<deque

(1)遍历容器

1
2
3
4
5
6
7
8
9
10
void printdeque(const deque<int>& d)
{
        for(deque<int>::const_iterator it=d.begin();it!=d.end();it++)
        //注意迭代器也要换成带const的
        {
                cout<<*it<<" ";
                //加const后容器中数据不可修改
        }
        cout<<endl;
}

(2)构造容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void test01()  
{
deque<int>d1;
for (int i = 0; i < 10; i++)
d1.push_front(i+1);
printdeque(d1);
//区间赋值
deque<int>d2(d1.begin(), d1.end());
printdeque(d2);
deque<int>d3(10, 100);
printdeque(d3);
deque<int>d4(d3);
printdeque(d4);
}

程序输出:

1
2
3
4
10 9 8 7 6 5 4 3 2 1  
10 9 8 7 6 5 4 3 2 1
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100

(3)赋值操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void test03()
{
deque<int>d1;
for(int i=0;i<10;i++)
{
d1.push_back(i+1);
}
printdeque(d1);
//operator=赋值
deuqe<int>d2;
d2=d1;
printdeque(d2);
//assign赋值
deque<int>d3;
d3.assgin(d1.begin(),d1.end());
printdeque(d3);
deque<int>d4;
d4.assign(10,100);
printdeque(d4);

}

程序输出:

1
2
3
4
1 2 3 4 5 6 7 8 9 10  
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
100 100 100 100 100 100 100 100 100 100

(4)插入和删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <deque>
using namespace std;

// 打印 deque 的内容
void printDeque(const deque<int>& d) {
for (int elem : d) {
cout << elem << " ";
}
if (d.empty()) {
cout << "(empty)";
}
cout << endl;
}

void testDequeOperations() {
deque<int> d;

// 1. 头部插入
d.push_front(10); // 在头部插入 10
d.push_front(20); // 在头部插入 20
d.push_front(30); // 在头部插入 30
printDeque(d); // 输出: 30 20 10

// 2. 尾部插入
d.push_back(40); // 在尾部插入 40
d.push_back(50); // 在尾部插入 50
printDeque(d); // 输出: 30 20 10 40 50

// 3. 任意位置插入
d.insert(d.begin() + 2, 100); // 在第三个位置插入 100
d.insert(d.end() - 1, 2, 200); // 在倒数第二个位置插入两个 200
printDeque(d); // 输出: 30 20 100 10 40 200 200 50

// 4. 头部删除
d.pop_front(); // 删除头部元素
printDeque(d); // 输出: 20 100 10 40 200 200 50

// 5. 尾部删除
d.pop_back(); // 删除尾部元素
printDeque(d); // 输出: 20 100 10 40 200 200

// 6. 任意位置删除
d.erase(d.begin() + 1); // 删除第二个位置上的元素
printDeque(d); // 输出: 20 10 40 200 200

// 删除一个范围内的元素
d.erase(d.begin() + 2, d.end() - 1); // 删除第三个到倒数第二个元素
printDeque(d); // 输出: 20 10 200

// 清空整个 deque
d.clear();
printDeque(d); // 输出: (empty)
}

int main() {
testDequeOperations();
return 0;
}


}

(5)数据存取

1
2
3
4
5
6
7
deque d1;
d1[2];
d1.at(2);
//d1的第二个元素
d1.front();
d1.back();
//访问d1的首尾元素

3. stack 容器

头文件 #include<stack>
后进先出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void test01()
{
stack<int>s;
s.push(10);
s.push(20);
s.push(30);
s.push(40);
int n=s.size();
for(int i=0;i<n;i++)
{
cout<<s.top()<<" ";//40 30 20 10
s.pop();
//访问top后出栈
}
cout<<endl;
}

4. queue 容器

头文件 #include<queue>
先进先出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include<queue>
using namespace std;
void testqueue()
{
queue<int>q;
q.push(10);
q.push(20);
q.push(30);

//创建一个temp用于打印元素
queue<int>temp=q;
while(!q.empty())
{
cout<<temp.front()<<" ";//输出队首元素
q.pop();//弹出队首元素
}
cout<<endl;

//获取队首尾元素
cout<<q.front()<<q.back()<<endl;

cout<<q.empty()<<endl;
cout<<q.size()<<endl;

//清空队列
while(!q.empty())
{
q.pop();
}
}
int main()
{
testqueue();
return 0;
}

5. string 容器

(1)构造

1
2
3
4
5
6
7
8
9
10
11
12
void test01
{
string s1;
cout<<"s1="<<s1<<endl;
const char* str= "hello world!"//C风格的字符串str初始化为C++的string类型对象s2
string s2(str);
cout<<"s2="<<s2<<endl;
string s3(s2);
cout<<"s3="<<s3<<endl;
string s4(10,'b');//使用n个字符b初始化
cout<<"s4="<<s4<<endl;
}
1
2
3
4
s1=  
s2=hello world!
s3=hello world!
s4=bbbbbbbbbb

(2)赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void test01
{
string str1;
str1="hello world!";
cout<<"str1="<<str1<<endl;
string str2=str1;
cout<<"str2="<<str2<<endl;
string str4;
str4.assign("hello");
cout<<"str4="<<str4<<endl;
string str5;
str5.assign("hello",3);//将前3个字符赋值给str5
cout<<"str5="<<str5<<endl;
string str6;
str6.assign(str5);
string str7;
str7.assign(10,'w');
}

(3)拼接

1
2
3
4
5
6
7
8
9
10
11
string s1="你";
s1+="好";
string s2="我也爱C语言";
//s1.append("hello");
//s1.append("you",2);
//s1.append(s2); 、
s1.append(s2,4,7);
//从str2的第三个字符开始,截取4个加在末尾,第二个参数为起始字符的位置(位置从0开始计算),第三个参数为字符的长度
//中文字符占2个位置,英文字符占1个位置
cout<<"s1="<<s1<<endl;//你好爱C语言

  • "我"(索引 0,长度 1)占两个字节。
  • "也"(索引 1,长度 1)占两个字节。
  • "爱"(索引 2,长度 1)占两个字节。
  • "C"(索引 3,长度 1)占一个字节。
  • "语"(索引 4,长度 1)占两个字节。
  • "言"(索引 5,长度 1)占两个字节。

(4)查找和替换

1
2
3
4
5
6
string s="abcdefgdefg";
int pos1=s.find("de");
int pos2=s.find("df");//-1
int pos3=s.rfind("df");//rfind是最后一次出现的位置,find是第一次出现的位置
s.replace(1,3,"1111");//从1号位起3个替换为1111
//a1111efgdefg

(5)字符串比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void test01()  
{
string str1 = "hfllo";
string str2 = "hello";
if (str1.compare(str2) == 0)
{
cout << "str1等于str2" << endl;
}
else if (str1.compare(str2) > 0)
{
cout << "str1大于str2" << endl;
}
else
{
cout << "str1小于str2" << endl;
}
}//通过逐字符比较ASCII值,大于为1,小于为-1,等于为0,以第一个不一样的字符为准
1
str1大于str2
  • 数字 0-948-57
  • 大写字母 A-Z65-90
  • 小写字母 a-z97-122

(6)字符提取

1
2
3
4
5
6
string str = "hello";  
for (int i = 0; i < 5; i++)
cout << str[i] << " ";
cout << endl;
for (int i = 0; i < 5; i++)
cout << str.at(i) << " ";

(7)插入和删除

1
2
3
4
5
string s1="abcdefgh";
s1.insert(2,"xxx");//abxxxcdefgh
s1.erase(2,3);//删去从2开始的3个字符
s1.insert(2,3,'x');//abcdefgh
s1.insert(2,3,'x');//abxxxcdefgh

(8)子串

1
2
3
string s1="abd*cdf";
int pos=s1.find('*');
string s2=s1.substr(0,pos);//abd

(9)其他

  1. string s; // 生成一个空字符串s
  2. string s(str); // 拷贝构造函数生成str的复制品
  3. string s(str, stridx); // 将字符串str内”始于位置stridx”的部分当作字符串的初值
  4. string s(str, stridx, strlen); // 将字符串str内”始于stridx且长度顶多strlen”的部分作为字符串的初值
  5. string s(cstr); // 将C字符串(以NULL结束)作为s的初值
  6. string s(chars, chars_len); // 将C字符串前chars_len个字符作为字符串s的初值。
  7. string s(num, ‘c’); // 生成一个字符串,包含num个c字符
  8. string s(“value”); string s = “value”; // 将s初始化为一个字符串字面值副本
  9. string s(begin, end); // 以区间begin/end(不包含end)内的字符作为字符串s的初值
  10. s.~string(); //销毁所有字符,释放内存

string s;

  1. s.empty(); // s为空串 返回true
  2. s.size(); // 返回s中字符个数 类型应为:string::size_type
  3. s[n]; // 从0开始相当于下标访问
  4. s1+s2; // 把s1和s2连接成新串 返回新串
  5. s1=s2; // 把s1替换为s2的副本
  6. v1 == v2; // 比较,相等返回true
  7. !=, <, <=, >, >= 惯有操作 任何一个大写字母都小于任意的小写字母
1
2
3
string s("abc");
s.size();
strlen(s.c_str());
1
2
3
4
5
6
7
//把string字符串转化为C风格的字符串  
string s = "abcdefg";
char str[1000];
strcpy(str, s.c_str());
str[0] = 'p';
str[5] = 'u'; //pbcdeug
}

6. set 容器和 multiset 容器

#include<set>
set不允许容器中有重复的元素
multiset允许容器中有重复的元素
其他操作基本一致

(1)遍历容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<iostream>
#include<set>
using namespace std;
void printset(const set<int>&s)
{
if(s.empty())
{
cout<<"set数组为空"<<endl;
return;
}
for(set<int>::const_iterator it=s.begin();it!=s.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
}
void printmultiset(const multiset<int>&m)
{
if(m.empty())
{
cout<<"multiset数组为空"<<endl;
return;
}
for(multiset<int>::const_iterator it=m.begin();it!=m.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
}

(2)插入和删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
set<int>s;
s.insert(10);
s.insert(20);
s.insert(30);
s.insert(40);
s.insert(50);
s.insert(60);
s.insert(70);
s.insert(80);
s.insert(90);
s.insert(100);
s.insert(110);
s.insert(120);
printset(s);//10 20 30 40 50 60 70 80 90 100 110 120
set<int>::iterator it=s.begin();
set<int>::iterator it2;
it2=s.erase(++++it);//删除30.删除迭代器所指元素,返回下一个元素的迭代器
printset(s);//10 20 40 50 60 70 80 90 100 110 120
set<int>::iterator it1=s.end();
s.erase(it2,----it1);//删除区间[it2,----it1)的所有元素,返回下一个元素的迭代器
printset(s);
s.erase(110);
printset(s);//10 20 120
s.clear();//清空set容器
printset(s);//set数组为空

(2)查找和统计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
set<int>s;
s.insert(10);
s.insert(20);
s.insert(30);
s.insert(40);
s.insert(30);
s.insert(60);
s.insert(70);
s.insert(80);
s.insert(70);
s.insert(100);
s.insert(110);
s.insert(120);
printset(s);
set<int>::()iterator it1;
//查找
it1=s.find(70);//若存在,返回该键的元素的迭代器,若不存在,返回set.end()
if(it1!=s.end()) cout<<*it<<endl;
else cout<<"未找到元素"<<endl;
//统计
int num=s.count(30);
cout<<num<<endl;//对于set而言,统计结果只有0和1

程序输出:

1
2
3
10 20 30 40 60 70 80 100 110 120  
70
1

(4)set 与 multiset

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
set<int>s;
s.insert(20);
s.insert(20);
s.insert(30);
s.insert(40);
s.insert(30);
s.insert(60);
s.insert(70);
s.insert(80);
s.insert(70);
s.insert(100);
s.insert(110);
s.insert(120);
printset(s);
pair<set<int>::iterator,bool>ret =s.insert(10);
//insert()方法返回一个pair类型,pair<set<int>::iterator,bool>ret,这个first是迭代器,指向插入元素的位置,second是布尔值,表示是否插入成功
if(ret.second) cout<<"第一次插入成功"<<endl;
else cout<<"第一次插入失败"<<endl;
pair<set<int>::iterator,bool>ret1 =s.insert(10);
if(ret1.second) cout<<"第二次插入成功"<<endl;
else cout<<"第二次插入失败"<<endl;

输出:

1
2
3
20 30 40 60 70 80 100 110 120  
第一次插入成功
第二次插入失败

7. map 和 multimap 容器

头文件 #include<map>
map 中所有元素都是 pair, 第一个元素为 key (键值), 起到索引作用, 第二个元素为 value(实值)
所有元素都有根据元素键值自动排序

map/multimap属于关联式容器,底层结构是用二叉树实现
优点:可以根据key值快速找到value值
map和multimap区别:
map不允许容器中有重复key值元素
multimap允许容器中有重复key值元素

(1)遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include<iostream>
#include<map>
using namespace std;
void printmap(const map<int,int>&m)
{
if(m.empty())
{
cout<<"map容器为空"<<endl;
return;
}
for(map<int,int>::const_iterator it=m.begin();it!=m.end();it++)
{
cout<<"学号:"<<(*it).first<<" 分数:"<<(*it).second<<endl;
}
cout<<endl;
}
void test01()
{
map<int,int>m;
m.insert(pair<int,int>(1,60));
m.insert(pair<int,int>(2,95));
m.insert(pair<int,int>(4,73));
m.insert(pair<int,int>(3,81));
printmap(m);//按照key值自动排序
map<int,int>m2(m);//拷贝构造
printmap(m2);
map<int,int>m3;
m3=m2;
printmap(m3);
}

(2)大小和转换

1
2
3
4
map<int,int>ma;
ma.size();//size()大小
map<int,int>ma1;
ma.swap(ma1);//swap()转换

(3)插入和删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
map<int,int>m;
m.insert(pair<int,int>(1,60));
m.insert(pair<int,int>(3,95));
m.insert(pair<int,int>(4,73));
m.insert(pair<int,int>(5,81));

m.insert(make_pair(2,10));
m.insert(map<int,int>::value_type(6,30));
m[7]=40;//这种插数方法和其他的不同在于可以修改已经插入的key对应的value
printmap(m);

m.erase(m.begin(),++++m.begin());
printmap(m);
m.erase(4);//按照key删除
printmap(m);
m.clear();
printmap(m);

程序输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
学号:1 分数:60  
学号:2 分数:10
学号:3 分数:95
学号:4 分数:73
学号:5 分数:81
学号:6 分数:30
学号:7 分数:40

学号:3 分数:95
学号:4 分数:73
学号:5 分数:81
学号:6 分数:30
学号:7 分数:40

学号:3 分数:95
学号:5 分数:81
学号:6 分数:30
学号:7 分数:40

(4)查找和统计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
map<int,int>m;
m.insert(pair<int, int>(1,60));
m.insert(pair<int, int>(3, 95));
m.insert(pair<int, int>(4, 73));
m.insert(pair<int, int>(5, 81));
m.insert(pair<int, int>(2, 84));
map<int,int>::iterator it;
it=m.find(4);
if(it!=m.end())
{
cout<<it->second<<endl;//73
//与cout << (*it).second << endl;等价
}
else{
cout<<"编号不存在"<<endl;
}
cout<<m.count(4)<<endl;//1

8. priority_queue

头文件 #include<queue>

priority_queue 是一个元素有序排列的队列,默认队列头部元素优先级最高。因为是一个队列,只能访问第一个元素,这也意味着优先级最高的元素总是第一个被处理。它能够实现常数时间的(默认)最大元素查找,对数代价的插入与释出

(1)构造

1
2
priority_queue<int>pq1;
priority_queue<int,vector<int>,greater<int>>pq2;
  • priority_queue 有三个模板参数:元素类型(T),底层容器类型(Container,默认为 vector<T>),以及比较方式(Compare,默认为 std::less<T>)。
  • 默认构造的 priority_queue (priority_queue<int>) 是一个最大堆,其中最大的元素在堆顶。
  • 通过使用 std::greater<int> 作为比较对象 (priority_queue<int, vector<int>, greater<int>>),你可以创建一个最小堆,其中最小的元素在堆顶。

(2)元素访问

top () 访问栈顶元素

1
2
3
4
5
6
7
8
9
10
11
12
#include<iostream>
#include<queue>
using namespace std;
int main()
{
priority_queue<int,vector<int>,less<int>>pq1;
pq1.push(10);
pq1.push(40);
pq1.push(20);
cout<<pq1.top()<<endl;//40
return 0;
}

(3)容量

empty ()
size ()

(4)修改器

push 插入元素并排序
pop 删除队首元素并排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<iostream>
#include<queue>
using namespace std;
int main()
{
priority_queue<int>pq1;
pq1.push(10);
pq1.push(40);
pq1.push(20);
pq1.push(30);
while(!pq1.empty())
{
cout<<pq1.top()<<" ";
pq1.pop();
}//40 30 20 10
//如果是priority_queue<int,vector<int>,greater<int>>pq1;则10 20 30 40
return 0;
}

9. STL 常用算法

下面基本上都需要 #include<algorithm> 头文件

(1)for_each 和 transform

1
2
3
4
5
6
7
8
9
10
vector<int>v;
for(int i=0;i<10;i++)
{
v.push_back(i+1);
}
vector<int>vtarget;
vtarget.resize(v.size());
transform(v.begin(), v.end(), vtarget.begin(), Transform());
for_each(vtarget.begin(), vtarget.end(), myprint());
//101 102 103 104 105 106 107 108 109 110
  • v.begin(), v.end():表示要转换的输入范围是 v 的起始到末尾。
  • vtarget.begin():表示转换后的结果要放到 vtarget 中,从其开始位置存储。
  • Transform():这是一个函数对象仿函数,用于指定要对输入范围的每个元素执行的操作。
    假定的 Transform

Transform 需要是一个函数对象,类似于:

1
2
3
4
5
6
struct Transform {
int operator()(int val) const
{
return val + 100;
}
};
  • 该类重载了 operator(),使得 Transform 类的对象能够像函数一样被调用。
  • transform 函数中,每次调用 Transform() 时,都会对输入的元素执行 val + 100 的操作。
  • 因此,v 中的每个元素 1, 2, ..., 10 将被转换为 101, 102, ..., 110,并存储在 vtarget 中。
  • for_each 是 C++ 标准库中的另一个算法,用于对范围内的每个元素执行某个操作。
  • 这行代码的参数:
    • vtarget.begin(), vtarget.end():表示对 vtarget 的所有元素执行操作。
    • myprint():这是另一个函数对象,用于指定对每个元素要执行的操作。
      假定的 myprint

myprint 需要是一个函数对象,类似于:

1
2
3
4
5
6
struct myprint {
void operator()(int val) const {
cout << val << " ";
}
};

  • 该类重载了 operator(),使得 myprint 类的对象可以像函数一样被调用。
函数 说明
find 查找元素
find_if 按条件查找元素
adjacent_find 查找相邻重复元素
binary_search 二分查找法
count 统计元素个数
count_if 按条件统计元素个数

(2)find

  • find 用于查找指定元素
  • 如果在指定的范围内找到了目标元素,它会返回指向该元素的迭代器
  • 如果找不到目标元素,则返回一个**结束迭代器 (end())**,表示目标元素不在该范围内。
    函数原型
    1
    iterator find(iterator beg, iterator end, const T& value);
  • iterator beg: 开始迭代器,表示查找范围的起点(包括 beg)。
  • iterator end: 结束迭代器,表示查找范围的终点(不包括 end 本身)。
  • value: 要查找的目标值,函数将在 [beg, end) 范围内寻找该值。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    vector<int>v;
    for(int i=0;i<10;i++)
    {
    v.push_back(i+1);
    }
    vector<int>::iterator it=find(v.begin(),v.end(),5);
    if(it==v.end())
    {
    cout<<"未找到"<<endl;
    }
    else
    {
    cout<<"找到:"<<*it<<endl;
    }

(3)find_if

功能描述:
按条件查找元素
函数原型: find_if(iterator beg, iterator end, _Pred);
按值查找元素,找到返回指定位置选代器,找不到返回结束选代器位置
beg开始迭代器
end结束迭代器
_Pred 函数或者谓词(返回bool类型的仿函数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class mycompare  
{
public:
bool operator()(int a)
{
return a > 5;
}
};
void test01()
{
vector<int>v;
for (int i = 0; i < 10; i++)
v.push_back(i + 1);
vector<int>::iterator it = find_if(v.begin(), v.end(), mycompare());
if (it == v.end())
cout << "未找到" << endl;
else
cout << "找到" << *it << endl;//找到6
}

查找指定的元素,查到返回true,否则返回false
注意:在无序序列中不可用,因为结果会出错
降序也不行,只能用于升序序列

1
2
3
4
5
vector<int>v={0,1,2,3,4,5,6,7,8};  
if (binary_search(v.begin(), v.end(), 6))
cout << "找到了" << endl;
else
cout << "未找到" << endl;

(5)adjacent_find

查找相邻重复元素,返回相邻元素的第一个位置的迭代器

1
2
3
4
5
6
vector<int>v={0,2,0,3,1,4,3,3,2};  
vector<int>::iterator pos = adjacent_find(v.begin(), v.end());
if (pos == v.end())
cout << "未找到" << endl;
else
cout << *pos << endl;//输出3

(6)count

统计元素个数

1
2
3
vector<int>v={0,1,2,3,5,3,3,6,8};  
int cou = count(v.begin(), v.end(), 3);
cout << cou << endl;

(7)count_if

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class greaterfive  
{
public:
bool operator()(int a)
{
return a > 5;
}
};
void test01()
{
vector<int>v={0,1,2,7,5,6,3,6,8};
int cou = count_if(v.begin(), v.end(), greaterfive());
cout << cou << endl; //4
}

(8)sort 排序算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void myprint(int val)  
{
cout << val << " ";
}
void test01()
{
vector<int>v={10,30,50,20,40,90};
for_each(v.begin(), v.end(), myprint); //10 30 50 20 40 90
cout << endl;
sort(v.begin(), v.end());
for_each(v.begin(), v.end(), myprint); //10 20 30 40 50 90
cout << endl;
sort(v.begin(), v.end(), greater<int>()); //greater<int>() 表示 "大于",因此 sort 函数会将较大的元素排在前面,形成降序排列。
for_each(v.begin(), v.end(), myprint); //90 50 40 30 20 10
cout << endl;
}

(9)random_shuffle

1
2
3
srand((unsigned int)time(NULL));  //设置随机数种子
vector<int>v={0,1,2,3,4,5,6,7,8,9};
random_shuffle(v.begin(), v.end());//随机打乱v的排序

在 C++11 及更高版本中,推荐使用 std::shuffle 替代 random_shuffle

1
2
3
4
5
6
7
8
9
10
11
#include <algorithm> // for std::shuffle
#include <random> // for std::default_random_engine

int main() {
std::vector<int> v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
std::random_device rd; // 用于获取随机种子
std::default_random_engine rng(rd()); // 随机数生成器
std::shuffle(v.begin(), v.end(), rng);
return 0;
}

(10)merge

可以把两个有序序列合在一起,形成一个新的有序序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void myprint(int val)  
{
cout << val << " ";
}
void test01()
{
vector<int>v1;
vector<int>v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i + 1);
}
vector<int>vTarget;//目标容器
vTarget.resize(v1.size() + v2.size());
merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
for_each(vTarget.begin(), vTarget.end(), myprint); //0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10
cout << endl;
}

(11)reverse

逆序

1
2
3
4
5
6
7
8
9
10
11
12
13
void myprint(int val)
{
cout<<val<<endl;
}
void test()
{
vector<int>v={10,30,40,50,20};
for_each(v.begin(),v.end(),myprint);//10 30 40 50 20
cout<<endl;
reverse(v.begin(),v.end());
for_each(v.begin(),v.end(),myprint);//20 50 40 30 10
cout<<endl;
}

(12)copy

将容器内指定范围的元素拷贝到另一容器中
注意:新容器需要预留空间

1
2
3
4
5
6
7
8
9
10
11
12
13
void mypriny(int val)
{
cout<<val<<endl;
}
void test()
{
vector<int>v={10,30,40,50,20};
vector<int>v2;
v2.resize(v.size());
copy(v.begin(),v.end(),v2.begin());
for_each(v2.begin(),v2.end(),myprint);//10 30 40 50 20
cout<<endl;
}

(13)replace 和 replace_if

replace将容器内指定范围的旧元素修改为新元素
replace_if将区间内满足条件替换成指定元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void myprint(int val)  
{
cout << val << " ";
}
//compare是一个仿函数(函数对象)。通过重载 operator(),使得 compare 类的对象可以像函数一样被调用。
class compare
{
public:
bool operator()(int a)
{
return a >= 40;
}
};
void test01()
{
vector<int>v={10,30,40,30,20,10,30,40,50,20};
for_each(v.begin(), v.end(), myprint); //10 30 40 30 20 10 30 40 50 20
cout << endl;
replace(v.begin(), v.begin() + 4, 30, 300); //[v.begin(), v.begin() + 4)所有值为 30 的元素替换为 300
for_each(v.begin(), v.end(), myprint); //10 300 40 300 20 10 30 40 50 20
cout << endl;
replace_if(v.begin(), v.end(), compare(), 66);
for_each(v.begin(), v.end(), myprint); //10 66 66 66 20 10 30 66 66 20
cout << endl;
}

(14)swap

交换

1
2
3
4
5
6
vector<int>v={10,30,40,30,20,10,30,40,50,20};  
vector<int>v1;
for (int i = 0; i < 10; i++) v1.push_back(i + 1);
swap(v, v1);
for_each(v.begin(), v.end(), myprint);
cout << endl;

(15)accumulate 和 fill

#include<numeric>

accumulate计算容器元素累计总和
fill向容器中添加元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void myprint(int val)  
{
cout << val << " ";
}
void test01()
{
vector<int>v{10,30,40,30,20,10,30,40,50,20};
for_each(v.begin(), v.end(), myprint);
cout << endl;
int total=accumulate(v.begin(), v.end(), 0);
//第三个参数表示起始累加值,0表示最后结果加0
cout << total << endl;
}
void test02()
{
vector<int>v;
v.resize(10);
for_each(v.begin(), v.end(), myprint);
cout << endl;
fill(v.begin(), v.end() - 2, 6);
for_each(v.begin(), v.end(), myprint);
cout << endl;
}

输出:

1
2
3
4
10 30 40 30 20 10 30 40 50 20  
2800
0 0 0 0 0 0 0 0 0
6 6 6 6 6 6 6 6 0 0

(16)交集,并集,差集

set_intersection求两个容器的交集
set_union并集
set_difference差集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <vector>
#include <algorithm> // for set_intersection, set_union, set_difference
using namespace std;

void printVector(const vector<int>& v) {
for (int val : v) {
cout << val << " ";
}
cout << endl;
}

int main() {
// 两个有序的 vector 容器
vector<int> v1 = {1, 2, 3, 4, 5, 6};
vector<int> v2 = {4, 5, 6, 7, 8, 9};

vector<int> result; // 用于存储结果

// 求交集
result.resize(min(v1.size(), v2.size())); // 交集的最大可能大小为两个容器的最小值
auto it = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), result.begin());
result.resize(it - result.begin()); // 调整结果大小为实际交集元素的大小
cout << "Intersection of v1 and v2: ";
printVector(result); // 输出交集

// 求并集
result.clear();
result.resize(v1.size() + v2.size()); // 并集的最大可能大小为两个容器的和
it = set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), result.begin());
result.resize(it - result.begin()); // 调整结果大小为实际并集元素的大小
cout << "Union of v1 and v2: ";
printVector(result); // 输出并集

// 求差集 v1 - v2
result.clear();
result.resize(v1.size()); // 差集的最大可能大小为第一个容器的大小
it = set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), result.begin());
result.resize(it - result.begin()); // 调整结果大小为实际差集元素的大小
cout << "Difference of v1 and v2 (v1 - v2): ";
printVector(result); // 输出差集

// 求差集 v2 - v1
result.clear();
result.resize(v2.size()); // 差集的最大可能大小为第二个容器的大小
it = set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), result.begin());
result.resize(it - result.begin()); // 调整结果大小为实际差集元素的大小
cout << "Difference of v2 and v1 (v2 - v1): ";
printVector(result); // 输出差集

return 0;
}

(17)next_premutation

全排列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
vector<int>vec;  
for (int i = 0; i < 3; i++)
{
vec.emplace_back(i + 1); //emplace_back(i + 1)是一个更有效的插入方式(类似于 push_back),用来在容器末尾直接构造元素。
}
for (auto k : vec)
cout << k << " ";
cout << endl;
while (next_permutation(vec.begin(), vec.end()))
{
for (auto k : vec)
cout << k << " ";
cout << endl;
}
  • next_permutation 是 C++ <algorithm> 头文件中的一个函数,用于生成从当前排列组合的下一个字典序排列。
  • 如果当前的排列组合已经是最大的排列组合,则 next_permutation 会返回 false,否则返回 true
  • 需要注意,next_permutation 只能在有序的容器上工作,因此 vec 必须按升序(或其他顺序)排列才能生成所有排列组合。
    输出:
    1
    2
    3
    4
    5
    6
    1 2 3  
    1 3 2
    2 1 3
    2 3 1
    3 1 2
    3 2 1

(18)lower_bound 和 upper_bound

lower_bound( )和upper_bound( )都是利用二分查找的方法在一个排好序的数组中进行查找的。

在从小到大的排序数组中,lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

也可以用于vector容器,返回值是迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <algorithm>
using namespace std;

int cmd(int a, int b) {
return a > b;
}

int main() {
int num[6] = { 1, 2, 4, 7, 15, 34 };

// 默认的排序是从小到大,因此这里其实是多余的操作
sort(num, num + 6); // 按从小到大排序

// 使用 lower_bound 查找第一个大于或等于 7 的位置
int pos1 = lower_bound(num, num + 6, 7) - num;
// lower_bound 返回的迭代器减去 num 的起始地址,得到相应的位置索引。
cout << pos1 << " " << num[pos1] << endl; // 输出:3 7

// 使用 upper_bound 查找第一个大于 7 的位置
int pos2 = upper_bound(num, num + 6, 7) - num;
cout << pos2 << " " << num[pos2] << endl; // 输出:4 15

// 按从大到小排序
sort(num, num + 6, cmd); // cmd 定义为从大到小排序

// 使用 lower_bound 查找第一个小于或等于 7 的位置
int pos3 = lower_bound(num, num + 6, 7, greater<int>()) - num;
cout << pos3 << " " << num[pos3] << endl; // 输出:2 7

// 使用 upper_bound 查找第一个小于 7 的位置
int pos4 = upper_bound(num, num + 6, 7, greater<int>()) - num;
cout << pos4 << " " << num[pos4] << endl; // 输出:3 4

return 0;
}

作者

zyh

发布于

2024-10-03

更新于

2024-10-03

许可协议

评论