在学习c++提高-STL总结了笔记,并分享出来。
05-c++STLday11
目录:
一、常用容器
1、上节作业——评委打分
2、stack栈容器
3、queue队列容器
4、list容器
测试API、测试:删除自定义数据类型
5、set容器
(1)测试API
(2)pair对组的创建方式——两种
(3)测试排序规则
6、map容器
测试API
7、STL容器使用时机
二、总结
一、常用容器
1、上节作业——评委打分
有5名选手:选手ABCDE,10个评委分别对每一名选手打分,去除最高分,去除评委中最低分,取平均分。
//1. 创建五名选手,放到vector中
//2. 遍历vector容器,取出来每一个选手,执行for循环,可以把10个评分打分存到deque容器中
//3. sort算法对deque容器中分数排序,pop_back pop_front去除最高和最低分
//4. deque容器遍历一遍,累加分数,累加分数/d.size()
//5. person.score = 平均分
1 /*
2 create by wp
3 2020.06.16
4 文件功能...
5
6 func()...干嘛的 参数1....
7 */
8 #define _CRT_SECURE_NO_WARNINGS
9 #include<iostream>
10 using namespace std;
11 #include<vector>
12 #include<deque>
13 #include<algorithm>
14 #include<string>
15 #inlcude<ctime>
16 /*
17 有5名选手:选手ABCDE,10个评委分别对每一名选手打分,去除最高分,去除评委中最低分,取平均分。
18 //1. 创建五名选手,放到vector中
19 //2. 遍历vector容器,取出来每一个选手,执行for循环,可以把10个评分打分存到deque容器中
20 //3. sort算法对deque容器中分数排序,pop_back pop_front去除最高和最低分
21 //4. deque容器遍历一遍,累加分数,累加分数/d.size()
22 //5. person.score = 平均分
23 */
24
25 class Person
26 {
27 public:
28 Person(string name, int score)
29 {
30 this->m_Name = name;
31 this->m_Score = score;
32 }
33
34 string m_Name;//人名
35 int m_Score;//分数
36 };
37
38 void createPerson(vector<Person>& v)
39 {
40 string nameSeed = "ABCDE";
41 for(int i = 0; i < 5; i++)
42 {
43 string name = "选手";
44 name += nameSeed[i];
45
46 int score = 0;
47 Person p(name, score);
48
49 v.push_back(p);
50 }
51
52
53 }
54
55 void setScore(vector<Person>& v)
56 {
57 for(vector<Person>::iterator it = v.begin(); it != v.end(); it++)
58 {
59 //对5个人进行打分
60 deque<int>d;
61 for(int i = 0; i < 10; i++)
62 {
63 int score = rand() % 41 + 60;//60~100
64
65 d.push_back(score);
66 }
67 /*
68 //先测试看下打分
69 for(deque<int>::iterator dit = d.begin(); dit != d.end(); dit++)
70 {
71 cout << *dit << " ";
72 }
73 cout << endl;
74 */
75
76 //排序
77 sort(d.begin(), d.end());
78
79 //去除最高和最低
80 d.pop_back();//最高
81 d.pop_front();
82
83 int sum = 0;
84 for(deque<int>::iterator dit = d.begin(); dit != d.end(); dit++)
85 {
86 sum += *dit;
87 }
88
89 //平均分
90 int avg = sum / d.size();
91
92 it->m_Score = avg;
93 }
94
95 }
96
97 void showScore(vector<Person>& v)
98 {
99 for(vector<Person>::iterator it = v.begin(); it != v.end(); it++)
100 {
101 cout << "姓名:" << it->m_Name << "最终平均分:" << it->m_Score << endl;
102 }
103
104 }
105
106 void test01()
107 {
108 //为方便测试,最后设置随机数种子
109 srand(unsigned int)time(NULL);
110
111 //创建容器,存放选手
112 vector<Person>v;
113
114 //创建5名选手
115 createPerson(v);
116
117 /*
118 //测试
119 for(vector<Person>::iterator it = v.begin(); it != v.end(); it++)
120 {
121 cout << "姓名:" << (*it).m_Name << endl;
122 }
123 */
124
125 //打分
126 SetScore(v);
127
128 //展示平均分
129 showScore(v);
130 }
131
132 int main()
133 {
134 test01();
135
136 system("pause");
137 return EXIT_SUCCESS;
138 }
2、stack栈容器
stack容器基本概念
stack是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口,形式如图所示。stack容器允许新增元素,移除元素,取得栈顶元素,但是除了最顶端外,没有任何其他方法可以存取stack的其他元素。换言之,stack不允许有遍历行为。
有元素推入栈的操作称为:push,将元素推出stack的操作称为pop.
stack没有迭代器
Stack所有元素的进出都必须符合”先进后出”的条件,只有stack顶端的元素,才有机会被外界取用。Stack不提供遍历功能,也不提供迭代器。
测试API:
1 #define _CRT_SECURE_NO_WARNINGS
2 #include<iostream>
3 using namespace std;
4 //包含stack头文件
5 #include<stack>
6
7 /*
8 //stack构造函数
9 stack<T> stkT;//stack采用模板类实现, stack对象的默认构造形式:
10 stack(const stack &stk);//拷贝构造函数
11
12 //stack赋值操作
13 stack& operator=(const stack &stk);//重载等号操作符
14
15 //stack数据存取操作
16 push(elem);//向栈顶添加元素
17 pop();//从栈顶移除第一个元素
18 top();//返回栈顶元素
19
20 //stack大小操作
21 empty();//判断堆栈是否为空
22 size();//返回堆栈的大小
23
24 */
25
26
27 void test01()
28 {
29 stack<int>s;
30 //放入数据 push
31 s.push(10);
32 s.push(30);
33 s.push(20);
34 s.push(40);
35
36 while(s.size() != 0)
37 {
38 cout << "栈顶为:" << s.top() << endl;//40 20 30 10
39 //弹出栈顶元素
40 s.pop();
41 }
42 cout << "size = " << s.size() << endl;
43
44 }
45
46 int main()
47 {
48 test01();
49
50 system("pause");
51 return EXIT_SUCCESS;
52 }
3、queue队列容器
queue容器基本概念
Queue是一种先进先出(First In First Out,FIFO)的数据结构,它有两个出口,queue容器允许从一端新增元素,从另一端移除元素。
queue没有迭代器
Queue所有元素的进出都必须符合”先进先出”的条件,只有queue的顶端元素,才有机会被外界取用。Queue不提供遍历功能,也不提供迭代器。
测试API:
1 #define _CRT_SECURE_NO_WARNINGS
2 #include<iostream>
3 using namespace std;
4 //包含队列头文件
5 #include<queue>
6
7 /*
8 //queue构造函数
9 queue<T> queT;//queue采用模板类实现,queue对象的默认构造形式:
10 queue(const queue &que);//拷贝构造函数
11
12 //queue存取、插入和删除操作
13 push(elem);//往队尾添加元素
14 pop();//从队头移除第一个元素
15 back();//返回最后一个元素
16 front();//返回第一个元素
17
18 //queue赋值操作
19 queue& operator=(const queue &que);//重载等号操作符
20
21 //queue大小操作
22 empty();//判断队列是否为空
23 size();//返回队列的大小
24
25 */
26
27 void test01()
28 {
29 queue<int>q;
30 q.push(10);//往队尾添加元素
31 q.push(30);
32 q.push(20);
33 q.push(40);
34
35 while(!q.empty())
36 {
37 cout << "队头:" << q.front() << endl;//10 40 30 40 20 40 40 40
38 cout << "队尾:" << q.back() << endl;
39 //弹出队头
40 q.pop();
41 }
42 cout << "size:" << q.size() << endl;
43 }
44
45 int main()
46 {
47 test01();
48
49 system("pause");
50 return EXIT_SUCCESS;
51 }
4、list容器
list容器基本概念
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
相较于vector的连续线性空间,list就显得负责许多,它的好处是每次插入或者删除一个元素,就是配置或者释放一个元素的空间。因此,list对于空间的运用有绝对的精准,一点也不浪费。而且,对于任何位置的元素插入或元素的移除,list永远是常数时间。
List和vector是两个最常被使用的容器。
List容器是一个双向链表。
>采用动态存储分配,不会造成内存浪费和溢出
>链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
>链表灵活,但是空间和时间额外耗费较大
list容器的迭代器
List容器不能像vector一样以普通指针作为迭代器,因为其节点不能保证在同一块连续的内存空间上。List迭代器必须有能力指向list的节点,并有能力进行正确的递增、递减、取值、成员存取操作。所谓”list正确的递增,递减、取值、成员取用”是指,递增时指向下一个节点,递减时指向上一个节点,取值时取的是节点的数据值,成员取用时取的是节点的成员。
由于list是一个双向链表,迭代器必须能够具备前移、后移的能力,所以list容器提供的是Bidirectional Iterators.
List有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效。这在vector是不成立的,因为vector的插入操作可能造成记忆体重新配置,导致原有的迭代器全部失效,甚至List元素的删除,也只有被删除的那个元素的迭代器失效,其他迭代器不受任何影响。
list容器的数据结构
list容器不仅是一个双向链表,而且还是一个循环的双向链表。
测试API:
1 #define _CRT_SECURE_NO_WARNINGS
2 #include<iostream>
3 using namespace std;
4 #include<list>
5 #include<algorithm>
6 #include<string>
7
8 //list是双向循环链表
9 void test01()
10 {
11 list<int> myList;
12 for (int i = 0; i < 10; i ++){
13 myList.push_back(i);
14 }
15
16 list<int>::_Nodeptr node = myList._Myhead->_Next;
17
18 for (int i = 0; i < myList._Mysize * 2;i++){
19 cout << "Node:" << node->_Myval << endl;
20 node = node->_Next;
21 if (node == myList._Myhead){
22 node = node->_Next;
23 }
24 }
25
26 }
27
28 /*
29 //list构造函数
30 list<T> lstT;//list采用采用模板类实现,对象的默认构造形式:
31 list(beg,end);//构造函数将[beg, end)区间中的元素拷贝给本身。
32 list(n,elem);//构造函数将n个elem拷贝给本身。
33 list(const list &lst);//拷贝构造函数。
34
35 //list数据元素插入和删除操作
36 push_back(elem);//在容器尾部加入一个元素
37 pop_back();//删除容器中最后一个元素
38 push_front(elem);//在容器开头插入一个元素
39 pop_front();//从容器开头移除第一个元素
40 insert(pos,elem);//在pos位置插elem元素的拷贝,返回新数据的位置。
41 insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。
42 insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。
43 clear();//移除容器的所有数据
44 erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
45 erase(pos);//删除pos位置的数据,返回下一个数据的位置。
46 remove(elem);//删除容器中所有与elem值匹配的元素。
47
48 */
49
50 void printList(list<int>& L)
51 {
52 for(list<int>::iterator it = L.begin(); it != L.end(); it++)
53 {
54 cout << *it << " ";
55 }
56 cout << endl;
57 }
58
59 void test02()
60 {
61 list<int>L(10, 10);
62 list<int>L2(L.begin(), L.end());
63
64 printList(L);
65 printList(L2);
66 L2.push_back(100);
67
68 //逆向打印
69 for(list<int>::reverse_iterator it = L2.rbegin(); it != L2.rend(); it++)
70 {
71 cout << *it << " ";
72 }
73 cout << endl;
74
75 //list迭代器不支持随机访问
76 list<int>::iterator itBegin = L2.begin();
77 //itBegin = itBegin + 1;
78
79 //插入数据
80 list<int>L3;
81 L3.push_back(10);
82 L3.push_back(30);
83 L3.push_back(20);
84 L3.push_front(100);
85 L3.push_front(300);
86 L3.push_front(200);
87
88 printList(L3);//200 300 100 10 30 20
89
90 //删除两端的数据
91 L3.pop_front();//头删
92 L3.pop_back();//尾删
93 printList(L3);//300 100 10 30
94
95 L3.insert(L3.begin(), 1000);
96 printList(L3);//1000 300 100 10 30
97
98 //remove(elem);//删除容器中所有与elem值匹配的元素
99 L3.push_back(10);//1000 300 100 10 30 10
100 L3.remove(10);//参数,直接放值
101
102 printList(L3);//1000 300 100 30
103 }
104
105 /*
106 //list大小操作
107 size();//返回容器中元素的个数
108 empty();//判断容器是否为空
109 resize(num);//重新指定容器的长度为num,
110 若容器变长,则以默认值填充新位置。
111 如果容器变短,则末尾超出容器长度的元素被删除。
112 resize(num, elem);//重新指定容器的长度为num,
113 若容器变长,则以elem值填充新位置。
114 如果容器变短,则末尾超出容器长度的元素被删除。
115
116 //list赋值操作
117 assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
118 assign(n, elem);//将n个elem拷贝赋值给本身。
119 list& operator=(const list &lst);//重载等号操作符
120 swap(lst);//将lst与本身的元素互换。
121
122 //list数据的存取
123 front();//返回第一个元素。
124 back();//返回最后一个元素。
125
126 */
127
128 void test03()
129 {
130 list<int>L3;
131 L3.push_back(10);
132 L3.push_back(30);
133 L3.push_back(20);
134 L3.push_front(100);
135 L3.push_front(300);
136 L3.push_front(200);
137
138 cout << "大小:" << L3.size() << endl;
139 if(L3.empty())
140 {
141 cout << "L3为空" << endl;
142 }
143 else
144 {
145 cout << "L3不为空" << endl;
146 }
147
148 L3.resize(10);
149 printList(L3);//200 300 100 10 30 20 0 0 0 0
150
151 L3.resize(3);
152 printList(L3);//200 300 100
153
154 list<int> L4;
155 L4.assign(L3.begin(), L3.end());
156
157 cout << "front:" << L4.front() << endl;//200
158 cout << "back:" << L4.back() << endl;//100
159
160 }
161
162 /*
163 //list反转排序
164 reverse();//反转链表,比如lst包含1,3,5元素,运行此方法后,lst就包含5,3,1元素。
165 sort(); //list排序
166 */
167 bool myCompare(int v1, int v2)
168 {
169 return v1 > v2;
170 }
171
172 void test04()
173 {
174 list<int>L;
175
176 L.push_back(10);
177 L.push_back(20);
178 L.push_back(40);
179 L.push_back(30);
180
181 L.reverse();
182 printList(L);//30 40 20 10
183
184 //所有不支持随机访问的迭代器,不可以用系统提供的算法
185 //如果不支持用系统提供算法,那么这个类内部会提供
186 //sort(L.begin(), L.end());
187 L.sort();//从小到大
188
189 printList(L);
190
191 //从大到小
192 L.sort(myCompare);
193 printList(L);
194 }
195
196 //自定义数据类型
197 class Person
198 {
199 public:
200 Person(string name, int age, int height)
201 {
202 this->m_Name = time;
203 this->m_Age = age;
204 this->m_Height = height;
205 }
206
207
208 string m_Name;
209 int m_Age;
210 int m_Height;//身高
211 };
212
213 //Person排序规则:如果年龄相同,按照身高升序排序
214 bool myComparePerson(Person& p1, Person& p2)
215 {
216 /*
217 if(p1.m_Age > p2.m_Age)
218 {
219 return true;
220 }
221 return false;
222 */
223
224 if(p1.m_Age == p2.m_Age)
225 {
226 return p1.m_Height < p2.m_Height;
227 }
228 else
229 {
230 return p1.m_Age > p2.m_Age;
231 }
232 }
233
234 void test05()
235 {
236 list<Person>L;
237
238 Person p1("亚瑟", 10, 165);
239 Person p2("德玛西亚", 20, 170);
240 Person p3("火枪", 17, 177);
241 Person p4("德雷福斯", 19, 120);
242 Person p5("MT", 18, 200);
243 Person p6("狗蛋", 18, 166);
244 Person p7("狗剩", 18, 210);
245
246 L.push_back(p1);
247 L.push_back(p2);
248 L.push_back(p3);
249 L.push_back(p4);
250 L.push_back(p5);
251 L.push_back(p6);
252 L.push_back(p7);
253
254 //需求:打印数据时候,按照年龄的降序输出
255 //对于自定义数据类型,必须要指定排序规则
256 L.sort(myComparePerson);
257
258 for(list<Person>::iterator it = it = L.begin(); it != L.end(); it++)
259 {
260 cout << "姓名:" << it->m_Name << "年龄:" << *it.m_Age << "身高:" << it->m_Height << endl;
261 }
262 }
263
264
265
266
267 int main()
268 {
269 test01();
270
271 system("pause");
272 return EXIT_SUCCESS;
273 }
测试:删除自定义数据类型
1 #define _CRT_SECURE_NO_WARNINGS
2 #include<iostream>
3 using namespace std;
4 #include<list>
5 #include<algorithm>
6 #include<string>
7
8
9 //自定义数据类型
10 class Person
11 {
12 public:
13 Person(string name, int age, int height)
14 {
15 this->m_Name = time;
16 this->m_Age = age;
17 this->m_Height = height;
18 }
19
20 //重载 == 让remove可以删除自定义的Person类型
21 bool operator==(const Person& p)//必须加const
22 {
23 if(this->m_Name == p.m_Name && this->m_Age == p.m_Age && this->m_Height == p.m_Height)
24 {
25 return true;
26 }
27 return false;
28 }
29
30
31 string m_Name;
32 int m_Age;
33 int m_Height;//身高
34 };
35
36 //Person排序规则:如果年龄相同,按照身高升序排序
37 bool myComparePerson(Person& p1, Person& p2)
38 {
39 /*
40 if(p1.m_Age > p2.m_Age)
41 {
42 return true;
43 }
44 return false;
45 */
46
47 if(p1.m_Age == p2.m_Age)
48 {
49 return p1.m_Height < p2.m_Height;
50 }
51 else
52 {
53 return p1.m_Age > p2.m_Age;
54 }
55 }
56
57 void test01()
58 {
59 list<Person>L;
60
61 Person p1("亚瑟", 10, 165);
62 Person p2("德玛西亚", 20, 170);
63 Person p3("火枪", 17, 177);
64 Person p4("德雷福斯", 19, 120);
65 Person p5("MT", 18, 200);
66 Person p6("狗蛋", 18, 166);
67 Person p7("狗剩", 18, 210);
68
69 L.push_back(p1);
70 L.push_back(p2);
71 L.push_back(p3);
72 L.push_back(p4);
73 L.push_back(p5);
74 L.push_back(p6);
75 L.push_back(p7);
76
77 //需求:打印数据时候,按照年龄的降序输出
78 //对于自定义数据类型,必须要指定排序规则
79 L.sort(myComparePerson);
80
81 for(list<Person>::iterator it = it = L.begin(); it != L.end(); it++)
82 {
83 cout << "姓名:" << it->m_Name << "年龄:" << *it.m_Age << "身高:" << it->m_Height << endl;
84 }
85
86 cout << "----------" << endl;
87 //删除 狗蛋
88 L.remove(p6);
89 for(list<Person>::iterator it = it = L.begin(); it != L.end(); it++)
90 {
91 cout << "姓名:" << it->m_Name << "年龄:" << *it.m_Age << "身高:" << it->m_Height << endl;
92 }
93
94 }
95
96
97
98
99 int main()
100 {
101 test01();
102
103 system("pause");
104 return EXIT_SUCCESS;
105 }
5、set容器
set/multiset容器基本概念
set容器基本概念
Set的特性是。所有元素都会根据元素的键值自动被排序。Set的元素不像map那样可以同时拥有实值和键值,set的元素即是键值又是实值。Set不允许两个元素有相同的键值。
我们可以通过set的迭代器改变set元素的值吗?不行,因为set元素值就是其键值,关系到set元素的排序规则。如果任意改变set元素值,会严重破坏set组织。换句话说,set的iterator是一种const_iterator.
set拥有和list某些相同的性质,当对容器中的元素进行插入操作或者删除操作的时候,操作之前所有的迭代器,在操作完成之后依然有效,被删除的那个元素的迭代器必然是一个例外。
multiset容器基本概念
multiset特性及用法和set完全相同,唯一的差别在于它允许键值重复。set和multiset的底层实现是红黑树,红黑树为平衡二叉树的一种。
树的简单知识:
二叉树就是任何节点最多只允许有两个字节点。分别是左子结点和右子节点。
二叉树示意图
二叉搜索树,是指二叉树中的节点按照一定的规则进行排序,使得对二叉树中元素访问更加高效。二叉搜索树的放置规则是:任何节点的元素值一定大于其左子树中的每一个节点的元素值,并且小于其右子树的值。因此从根节点一直向左走,一直到无路可走,即得到最小值,一直向右走,直至无路可走,可得到最大值。那么在儿茶搜索树中找到最大元素和最小元素是非常简单的事情。下图为二叉搜索树:
上面我们介绍了二叉搜索树,那么当一个二叉搜索树的左子树和右子树不平衡的时候,那么搜索依据上图表示,搜索9所花费的时间要比搜索17所花费的时间要多,由于我们的输入或者经过我们插入或者删除操作,二叉树失去平衡,造成搜索效率降低。
所以我们有了一个平衡二叉树的概念,所谓的平衡不是指的完全平衡。
RB-tree(红黑树)为二叉树的一种。
(1)测试API:
1 #define _CRT_SECURE_NO_WARNINGS
2 #include<iostream>
3 using namespace std;
4 #include<set>
5 /*
6 //set构造函数
7 set<T> st;//set默认构造函数:
8 mulitset<T> mst; //multiset默认构造函数:
9 set(const set &st);//拷贝构造函数
10
11 //set赋值操作
12 set& operator=(const set &st);//重载等号操作符
13 swap(st);//交换两个集合容器
14
15 //set大小操作
16 size();//返回容器中元素的数目
17 empty();//判断容器是否为空
18
19 //set插入和删除操作
20 insert(elem);//在容器中插入元素。
21 clear();//清除所有元素
22 erase(pos);//删除pos迭代器所指的元素,返回下一个元素的迭代器。
23 erase(beg, end);//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
24 erase(elem);//删除容器中值为elem的元素。
25
26 */
27 void printSet(set<int>& s)
28 {
29 for(set<int>::iterator it = s.begin(); it != s.end(); it++)
30 {
31 cout << *it << " ";
32 }
33 cout << endl;
34 }
35
36
37 void test01()
38 {
39 set<int>s1;
40
41 //关联式容器,key进行排序,从小到大
42 s1.intsert(5);
43 s1.intsert(1);
44 s1.intsert(9);
45 s1.intsert(3);
46 s1.intsert(7);
47
48 printSet(s1);//1 3 5 7 9
49
50 if(s1.empty())
51 {
52 cout << "空" << endl;
53 }
54 else
55 {
56 cout << "size = " << s1.size() << endl;
57 }
58
59 s1.erase(s1.begin());// 3 5 7 9
60 printSet(s1);
61 s1.erase(3);//5 7 9
62 printSet(s1);
63
64 }
65
66 /*
67 //set查找操作
68 find(key);//查找键key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
69 count(key);//查找键key的元素个数
70 lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器。
71 upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器。
72 equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器。
73
74 */
75 void test02()
76 {
77 set<int>s1;
78 s1.intsert(5);
79 s1.intsert(1);
80 s1.intsert(9);
81 s1.intsert(3);
82 s1.intsert(7);
83
84 //对于set,没有value,key就是value
85
86 set<int>::iterator pos = s1.find(3);
87 //判断是否找到
88 if(pos != s1.end())
89 {
90 cout << "找到了,值为:" << *pos << endl;
91 }
92 else
93 {
94 cout << "未找到" << endl;
95 }
96
97 //count(key);//查找键key的元素个数,对于set而言,结果0或者1
98 int num = s1.count(1);
99 cout << "2的个数为:" << num << endl;
100
101 //lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器
102 set<int>::iterator it = s1.lower_bound(3);//10就是未找到
103 if(it != s1.end())
104 {
105 cout << "找到了,lower_bound(3)的值为:" << *it << endl;
106 }
107 else
108 {
109 cout << "未找到" << endl;
110 }
111 //upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器
112 set<int>::iterator it2 = s1.lower_bound(3);
113 if(it2 != s1.end())
114 {
115 cout << "找到了,lower_bound(3)的值为:" << *it2 << endl;
116 }
117 else
118 {
119 cout << "未找到" << endl;
120 }
121 //equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器
122 //上下限就是 lower_bound upper_bound
123 pair<set<int>::iterator, set<int>::iterator> ret = s1.equal_range(3);
124 //获取第一个值
125 if(ret.first != s1.end())
126 {
127 cout << "找到equal_range中的lower_bound的值:" << *(ret.first) << endl;
128 }
129 else
130 {
131 cout << "未找到" << endl;
132 }
133 //获取第二个值
134 if(ret.second != s1.end())
135 {
136 cout << "找到equal_range中的upper_bound的值:" << *(ret.second) << endl;
137 }
138 else
139 {
140 cout << "未找到" << endl;
141 }
142
143 }
144
145 int main()
146 {
147 test01();
148
149 system("pause");
150 return EXIT_SUCCESS;
151 }
(2)pair对组的创建方式——两种
对组(pair)将一对值组合成一个值,这一对值可以具有不同的数据类型,两个值可以分别用pair的两个公有属性first和second访问。
类模板:template <class T1, class T2> struct pair.
测试:
1 #define _CRT_SECURE_NO_WARNINGS
2 #include<iostream>
3 #include<string>
4 using namespace std;
5
6 //创建对组,使用对组pair不需要引用头文件
7 void test01()
8 {
9 //第一种括号
10 pair<string, int>p(string("Tom"), 100);
11
12 //取值
13 cout << "姓名:" << p.first << endl;
14 cout << "年龄:" << p.second << endl;
15
16 //第二种创建
17 pair<string, int> p2 = make_pair("Jerry", 200);
18 cout << "姓名:" << p2.first << endl;
19 cout << "年龄:" << p2.second << endl;
20
21 }
22
23 int main()
24 {
25 test01();
26
27 system("pause");
28 return EXIT_SUCCESS;
29 }
(3)测试排序规则:
1 #define _CRT_SECURE_NO_WARNINGS
2 #include<iostream>
3 using namespace std;
4 #include<set>
5 #include<string>
6
7 void printSet(set<int>& s)
8 {
9 for(set<int>::iterator it = s.begin(); it != s.end(); it++)
10 {
11 cout << *it << " ";
12 }
13 cout << endl;
14 }
15
16 //set容器,不允许插入重复的键值
17 void test01()
18 {
19 set<int>s1;
20
21 pair<set<int>::iterator, bool> ret = s1.intsert(10);
22
23
24 if(ret.second)
25 {
26 cout << "插入成功" << endl;
27 }
28 else
29 {
30 cout << "插入失败" << endl;
31 }
32 s1.intsert(10);
33
34
35 if(ret.second)
36 {
37 cout << "第二次插入成功" << endl;
38 }
39 else
40 {
41 cout << "第二次插入失败" << endl;
42 }
43
44 printSet(s1);//10
//multiset允许插入重复的值
multiset<int>mul;
mul.insert(10);
mul.insert(10);
45 }
46
47 //指定set排序规则,从大到小
48 //仿函数
49 class myCompare
50 {
51 public:
52 //重载()
53 bool operator()(int v1, int v2)
54 {
55 return v1 > v2;
56 }
57
58
59 };
60
61 //set容器排序
62 void test02()
63 {
64 set<int, myCompare>s1;
65
66 s1.insert(5);
67 s1.insert(1);
68 s1.insert(9);
69 s1.insert(3);
70 s1.insert(7);
71
72 //printSet(s1);
73
74 //从大到小排序
75 //在插入之前就指定排序规则
76
77 for(set<int, myCompare>::iterator it = s1.begin(); it != s1.end(); it++)
78 {
79 cout << *it << " ";
80 }
81 cout << endl;
82
83 }
84
85 //自定义数据类型
86 class Person
87 {
88 public:
89 Person(string name, int age)
90 {
91 this->m_Name = name;
92 this->m_Age = age;
93 }
94
95 string m_Name;
96 int m_Age;
97 };
98
99 class myComparePerson
100 {
101 public:
102 bool operator()(const Person& p1, const Person& p2)//必须加入const
103 {
104 if(p1.m_Age > p2.m_Age)//降序
105 {
106 return true;
107 }
108 return false;
109 }
110
111
112 };
113
114 void test03()
115 {
116 set<Person, myComparePerson> s1;
117
118 Person p1("大娃", 100);
119 Person p2("二娃", 90);
120 Person p3("六娃", 10);
121 Person p4("爷爷", 1000);
122
123 s1.insert(p1);
124 s1.insert(p2);
125 s1.insert(p3);
126 s1.insert(p4);
127
128 //插入自定义数据类型,一开始就指定排序规则
129
130 //显示
131 for(set<Person, myComparePerson>::iterator it = s1.begin(); it != s1.end(); it++)
132 {
133 cout << "姓名:" << (*it).m_Name << "年龄:" << (*it).m_Age << endl;
134 }
135 }
136
137
138
139
140
141
142 int main()
143 {
144 test01();
145
146 system("pause");
147 return EXIT_SUCCESS;
148 }
6、map容器
map/multimap基本概念
Map的特性是,所有元素都会根据元素的键值自动排序。Map所有的元素都是pair,同时拥有实值和键值,pair的第一元素被视为键值,第二元素被视为实值,map不允许两个元素有相同的键值。
我们可以通过map的迭代器改变map的键值吗?答案是不行,因为map的键值关系到map元素的排列规则,任意改变map键值将会严重破坏map组织。如果想要修改元素的实值,那么是可以的。
Map和list拥有相同的某些性质,当对它的容器元素进行新增操作或者删除操作时,操作之前的所有迭代器,在操作完成之后依然有效,当然被删除的那个元素的迭代器必然是个例外。
Multimap和map的操作类似,唯一区别multimap键值可重复。
Map和multimap都是以红黑树为底层实现机制。
测试API:
1 #define _CRT_SECURE_NO_WARNINGS
2 #include<iostream>
3 using namespace std;
4 //引入头文件
5 #include<map>
6
7 /*
8 //map构造函数
9 map<T1, T2> mapTT;//map默认构造函数:
10 map(const map &mp);//拷贝构造函数
11
12 //map赋值操作
13 map& operator=(const map &mp);//重载等号操作符
14 swap(mp);//交换两个集合容器
15
16 //map大小操作
17 size();//返回容器中元素的数目
18 empty();//判断容器是否为空
19
20 //map插入数据元素操作
21 map.insert(...); //往容器插入元素,返回pair<iterator,bool>
22 map<int, string> mapStu;
23 // 第一种 通过pair的方式插入对象
24 mapStu.insert(pair<int, string>(3, "小张"));
25 // 第二种 通过pair的方式插入对象
26 mapStu.inset(make_pair(-1, "校长"));
27 // 第三种 通过value_type的方式插入对象
28 mapStu.insert(map<int, string>::value_type(1, "小李"));
29 // 第四种 通过数组的方式插入值
30 mapStu[3] = "小刘";
31 mapStu[5] = "小王";
32
33 */
34
35
36 void test01()
37 {
38 map<int, int>m;
39 //插入值
40 //4种方式
41 //第一种
42 m.insert(pair<int, int>(1, 10));
43 //第二种 推荐
44 m.insert(make_pair(2,20));
45 //第三种
46 m.insert(map<int, int>::value_type(3, 30));
47 //第四种,如果保证key存在,那么可以通过[]访问
48 m[4] = 40;
49
50 for(map<int, int>::iterator it = m.begin(); it != m.end(); it++)
51 {
52 cout << "key = " << it->first << "value = " << it->second << endl;
53 }
54
55 //cout << m[5] << endl;
56
57 for(map<int, int>::iterator it = m.begin(); it != m.end(); it++)
58 {
59 cout << "key = " << it->first << "value = " << it->second << endl;
60 }
61
62 cout << m[4] << endl;
63
64 if(m.empty())
65 {
66 cout << "空" << endl;
67 }
68 else
69 {
70 cout << "size = " << m.size() << endl;
71 }
72
73 }
74
75 /*
76 //map删除操作
77 clear();//删除所有元素
78 erase(pos);//删除pos迭代器所指的元素,返回下一个元素的迭代器。
79 erase(beg,end);//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
80 erase(keyElem);//删除容器中key为keyElem的对组。
81
82 //map查找操作
83 find(key);//查找键key是否存在,若存在,返回该键的元素的迭代器;/若不存在,返回map.end();
84 count(keyElem);//返回容器中key为keyElem的对组个数。对map来说,要么是0,要么是1。对multimap来说,值可能大于1。
85 lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器。
86 upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器。
87 equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器。
88
89 */
90
91 void test02()
92 {
93 map<int, int>m;
94 m.insert(pair<int, int>(1, 10));
95 m.insert(make_pair(2,20));
96 m.insert(map<int, int>::value_type(3, 30));
97 m[4] = 40;
98
99 m.erase(1);
100 for(map<int, int>::iterator it = m.begin(); it != m.end(); it++)
101 {
102 cout << "key = " << it->first << "value = " << it->second << endl;
103 }
104
105 map<int, int>::iterator pos = m.find(2);
106 if(pos != m.end())
107 {
108 cout << "找到,key:" << pos->first << "value:" << pos->second << endl;
109 }
110 else
111 {
112 cout << "未找到" << endl;
113 }
114
115 int num = m.count(3);//map的count要么0,要么1
116 cout << "num = " << endl;
117
118 //lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器
119 map<int, int>::iterator ret = m.lower_bound(3);
120 if(ret != m.end())
121 {
122 cout << "lower_bound中key:" << ret->first << "value:" << ret->second << endl;
123 }
124 else
125 {
126 cout << "未找到" << endl;
127 }
128
129 //upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器
130 map<int, int>::iterator ret = m.upper_bound(3);
131 if(ret != m.end())
132 {
133 cout << "upper_bound中key:" << ret->first << "value:" << ret->second << endl;
134 }
135 else
136 {
137 cout << "未找到" << endl;
138 }
139
140 //equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器
141 pair<map<int, int>::iterator, map<int, int>::iterator> ret2 = m.equal_range(3);
142
143 if(ret2.first != m.end())
144 {
145 cout << "找到了equal_range中的lower_bound的key" << ret2.first->first << "value:" << ret2.first->second << endl;
146 }
147 else
148 {
149 cout << "未找到" << endl;
150 }
151
152 if(ret2.second != m.end())
153 {
154 cout << "找到了equal_range中的upper_bound的key" << ret2.second->first << "value:" << ret2.second->second << endl;
155 }
156 else
157 {
158 cout << "未找到" << endl;
159 }
160
161 }
162
163 //指定排序规则
164 class myCompare
165 {
166 public:
167 bool operator()(int v1, int v2)
168 {
169 return v1 > v2;
170 }
171 };
172
173
174 void test03()
175 {
176 //从大到小排序
177 map<int, int, myCompare>m;
178 m.insert(pair<int, int>(1, 10));
179 m.insert(make_pair(2,20));
180 m.insert(map<int, int>::value_type(3, 30));
181 m[4] = 40;
182
183 for(map<int, int, myCompare>::iterator it = m.begin(); it != m.end(); it++)
184 {
185 cout << "key = " << it->first << "value = " << it->second << endl;
186 }
187
188 }
189
190
191
192 int main()
193 {
194 test01();
195
196 system("pause");
197 return EXIT_SUCCESS;
198 }
7、STL容器使用时机
|
vector |
deque |
list |
set |
multiset |
map |
multimap |
典型内存结构 |
单端数组 |
双端数组 |
双向链表 |
二叉树 |
二叉树 |
二叉树 |
二叉树 |
可随机存取 |
是 |
是 |
否 |
否 |
否 |
对key而言:不是 |
否 |
元素搜寻速度 |
慢 |
慢 |
非常慢 |
快 |
快 |
对key而言:快 |
对key而言:快 |
元素安插移除 |
尾端 |
头尾两端 |
任何位置 |
- |
- |
- |
- |
》vector的使用场景:比如软件历史操作记录的存储,我们经常要查看历史记录,比如上一次的记录,上上次的记录,但却不会去删除记录,因为记录是事实的描述。
》deque的使用场景:比如排队购票系统,对排队者的存储可以采用deque,支持头端的快速移除,尾端的快速添加。如果采用vector,则头端移除时,会移动大量的数据,速度慢。
vector与deque的比较:
一:vector.at()比deque.at()效率高,比如vector.at(0)是固定的,deque的开始位置 却是不固定的。
二:如果有大量释放操作的话,vector花的时间更少,这跟二者的内部实现有关。
三:deque支持头部的快速插入与快速移除,这是deque的优点。
》list的使用场景:比如公交车乘客的存储,随时可能有乘客下车,支持频繁的不确实位置元素的移除插入。
》set的使用场景:比如对手机游戏的个人得分记录的存储,存储要求从高分到低分的顺序排列。
》map的使用场景:比如按ID号存储十万个用户,想要快速要通过ID查找对应的用户。二叉树的查找效率,这时就体现出来了。如果是vector容器,最坏的情况下可能要遍历完整个容器才能找到该用户。
二、总结
1 stack栈容器
1.1 先进后出
1.2 栈顶 top
1.3 压栈 push
1.4 弹出栈顶 pop
1.5 大小 size
1.6 为空 empty
2 queue 队列容器
2.1 先进先出
2.2 队头 front 队尾 back
2.3 入队 push
2.4 弹出队头 pop
2.5 大小 size
2.6 为空 empty
3 List容器
3.1 赋值、构造、大小、为空、删除 、添加
3.2 移除 remove( 10 ) 删除容器中所有与10 匹配的元素
3.3 双向循环链表
3.4 迭代器是不支持随机访问的
3.5 反转排序
3.5.1 reverse 反转
3.5.2 排序 成员函数 sort
3.5.3 默认排序 从小到大
3.5.4 自定义数据类型,必须指定排序规则
3.5.5 高级
3.6 remove删除list容器中自定义数据类型
4 set容器
4.1 关联式容器
4.2 插入数据自动排序 按照key
4.3 insert 插入值
4.4 erase 参数可以传值 或者 迭代器
4.5 find() 返回值 迭代器 找不到返回的 end()
4.6 count 计数 对于set而言 结果 就是 0 或者1
4.7 lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器。
4.8 upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器。
4.9 equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器。
4.10 对组 pair
4.10.1 第一个值 first
4.10.2 第二个值 second
4.10.3 默认括号
4.10.4 make_pair()
4.11 set插入返回值是 对组 < 迭代器, 是否成功标示>
4.12 指定set排序规则,利用仿函数
4.13 set插入自定义数据类型
5 map容器
5.1 每个元素 都是一个pair
5.2 对于map而言 key是不可以重复
5.3 multimap可以
5.4 4中插入方式
5.5 count 统计 map 0 或1 multimap可能大于1
5.6 排序规则自己指定
在学习c++提高-STL总结了笔记,并分享出来。