c++提高学习笔记——05-c++STLday11
在学习c++提高-STL总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。
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总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。
posted on 2020-06-16 09:11 Alliswell_WP 阅读(128) 评论(0) 编辑 收藏 举报