STL顺序容器的基本操作
容器主要分为:顺序容器和关联容器
顺序容器和关联容器,顺序容器主要有:vector、list、deque等。其中vector表示一段连续的内存地址,基于数组的实现,list表示非连续的内存,基于链表实现。deque双向队列与vector类似,但是对于首元素提供删除和插入的双向支持。关联容器主要有map和set。map是key-value形式的,set是单值。map和set只能存放唯一的key值,multimap和multiset可以存放多个相同的key值, 还有unorder_multimap等。
顺序容器
vector
/*
* 什么是vector, vector的特点
* vector类似一个动态数组,是一段地址连续的空间
* vector和array的区别:vector支持动态空间调整,随着元素的增加,大小会改变
*/
// 初始化: vector<int> v; vector<int> v2(10); // 可以容纳10个int vector<int> v3(10, 2); // 10个2 vector<int> v4(v2); int arr[4] = {1,2,3,4}; vector<int> v5(arr, arr+4); // 其他操作, 是vector容器自带的函数,不包含全局的算法(find查找,remove_if删除等) // 添加元素 vec.push_back(3); // 在最后添加元素 insert(); /* iterator insert( iterator loc, const TYPE &val ); void insert( iterator loc, size_type num, const TYPE &val ); void insert( iterator loc, input_iterator start, input_iterator end ); insert() 函数有以下三种用法: 在指定位置loc前插入值为val的元素,返回指向这个元素的迭代器, 在指定位置loc前插入num个值为val的元素 在指定位置loc前插入区间[start, end)的所有元素 . */ // 删: // erase iterator erase( iterator loc ); iterator erase( iterator start, iterator end ); // erase函数要么删作指定位置loc的元素,要么删除区间[start, end)的所有元素. // 返回值是指向删除的最后一个元素的下一位置的迭代器.例如: vec.clear(); // 清空容器 vec.pop_back(); // 移除尾部元素,无返回值 // 查 vec.back(); // 返回最有一个元素的引用 vec.begin(); // 返回当前容器首元素的迭代器 vec.end(); // 尾后迭代器 vec.rbegin(); // rbegin函数返回指向当前vector末尾的逆迭代器 vec.rend(); // rend()函数返回指向当前vector起始位置的逆迭代器. 类似与begin和end 其他 vec.empty(); // 判断是否为空 vec.capacity(); // 返回当前vector在重新进行内存分配以前所能容纳的元素数量. // reserve()函数为当前vector预留至少共容纳size个元素的空间 // void resize( size_type size, TYPE val ); vec.resize(); // resize() 函数改变当前vector的大小为size,且对新创建的元素赋值val vec.size(); // 返回当前所容纳的元素个数 // vec.swap(vec2) // vec和vec2交换 // 遍历: void print(vector<int>& vec) { for (int i = 0; i < vec.size(); i++) cout << vec[i] << " "; for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++) { cout << *it << " "; } for (auto item : vec) { cout << item << " "; } cout << endl; }
deque
支持随机访问和快速插入和删除
// 双向队列和向量很相似,但是它允许在容器头部快速插入和删除(就像在尾部一样)。
// 就是比vector多了两个方法:
push_front()
pop_back()
// 具体使用方法参考vector
#include <iostream> #include <algorithm> #include <deque> using namespace std; void printDeq(deque<int> &d1) { cout << "deque迭代器遍历:"; for (deque<int>::iterator it = d1.begin(); it != d1.end(); it++) { cout << *it << " "; } cout << endl << endl; } void test41() { deque<int> d1; d1.push_back(1); d1.push_back(3); d1.push_back(5); d1.push_front(-11); d1.push_front(-33); d1.push_front(-55); printDeq(d1); cout <<"头部元素:" << d1.front() << endl; cout <<"尾部元素:" << d1.back() <<endl; d1.pop_front(); // 弹出头部元素 d1.pop_back(); // 弹出尾部元素 cout << "弹出头部,和尾部之后: "; printDeq(d1); // 查找-33在数组下标的值 deque<int>::iterator it = find(d1.begin(),d1.end(), -33); if (it != d1.end()) { // 计算下标 cout <<"-33的数组下标是" << distance(d1.begin(), it) << endl; } else { cout <<"未找到"<<endl; } } int main40() { test41(); return 0; }
list
list,list是stl实现的双向链表,
与向量vector想比,它允许快速的插入和删除,但是随机访问却是比较慢
结构图:
优点:随意插入和删除,替换元素效率极高
缺点:查找慢(不能随机访问:就是只能从头开始遍历)
不建议想里面插入数据,效率太低
/ 其他操作 // 初始化,创建 list<int> lst1; //创建空list list<int> lst2(3); //创建含有三个元素的list list<int> lst3(3,2); //创建含有三个元素为2的list list<int> lst4(lst2); //使用lst2初始化lst4 list<int> lst5(lst2.begin(),lst2.end()); //同lst4 // 增 lst1.assign(lst2.begin(),lst2.end()); //分配值,3个值为0的元素 lst1.push_front(1); // 1加到list的首部 lst1.push_back(10); //末尾添加值 lst1.insert(); //返回值是一个迭代器,指向被插入的元素。 iterator insert( iterator pos, const TYPE &val ); // 插入元素val到位置pos void insert( iterator pos, size_type num, const TYPE &val ); // 插入num个元素val到pos之前 void insert( iterator pos, input_iterator start, input_iterator end ); // 插入start到end之间的元素到pos的位置 // 删 lst1.pop_back(); // 删除链表的最后一个元素。 lst1.pop_front(); // 删除连链表第一个元素 lst1.remove(1); // 删除链表中所有的1 void lst1.remove_if( UnPred pr)// 以一元谓词pr为判断元素的依据,遍历整个链表。如果pr返回true则删除该元素。 lst1.erase() iterator erase( iterator pos ); iterator erase( iterator start, iterator end ); erase()函数删除以pos指示位置的元素, 或者删除start和end之间的元素。 返回值是一个迭代器,指向最后一个被删除元素的下一个元素。 lst1.clear() // 清除所有元素 // 改 lst1.reverse(); // 将所有的list倒转 lst1.swap(list2); // 1和2交换 lst1.unique(); // 删除重复的元素 void unique(); void unique( BinPred pr ); unique()函数删除链表中所有重复的元素。如果指定pr,则使用pr来判定是否删除。 // 查 lst1.begin(); // 返回list的首元素的迭代器 lst1.end(); // 返回list尾后迭代器 lst1.front(); // 返回一个指向首元素的引用 lst.back() // 返回一个引用,指向list的最后一个元素。 lst1.rbegin(); // 返回一个逆向迭代器,指向链表的末尾。 rend和begin和end用法类似 // 其他 lst1.empty(); // 判断是否为空 true为空 lst1.max_size(); //max_size()函数返回链表能够储存的元素数目。 lst1.merge() void merge( list &lst ); void merge( list &lst, Comp compfunction ); merge()函数把自己和lst链表连接在一起,产生一个整齐排列的组合链表。如果指定compfunction,则将指定函数作为比较的依据。 lst1.resize(); void resize( size_type num, TYPE val )// resize()函数把list的大小改变到num。被加入的多余的元素都被赋值为val lst1.size(); // 返回链表的元素数量 lst1.sort(); // 排序 void sort(); void sort( Comp compfunction ); sort()函数为链表排序,默认是升序。如果指定compfunction的话,就采用指定函数来判定两个元素的大小。 // 遍历: // list不能随机访问 就是 it++正确,但是不能it+2 it = l.begin(); it++; it++; it++; // 此时it指向第4个元素,元素为3 l.insert(it, 100); // 在3前面插入100 for (auto it = lst1.begin(); it != lst1.end(); it++) cout << *it << " "; for (auto it : lst1) cout << it << " "; // 加上&可以修改值 for (auto& it : lst1) cout << it << " ";
stack
不允许遍历
C++ Stack(堆栈) 是一个容器类的改编,为程序员提供了堆栈的全部功能,——也就是说实现了一个先进后出(FILO)的数据结构。
stack<int> s; s.push(1); // 在栈顶添加元素 s.push(2); s.top(); // 返回栈顶元素 s.pop(); //删除栈顶元素 s.empty(); // 判断栈空 s.size(); // 判断栈中元素数量
// // Created by lk on 18-6-3. // #include <iostream> #include <stack> #include <cstring> #include <algorithm> using namespace std; // 出栈 void printStack(stack<int> &sta) { while(!sta.empty()) { cout << sta.top() << " "; // 获取栈顶元素 sta.pop(); // 出栈 } } void test51() { stack<int> s; // 入栈 for(int i = 0; i != 10; i++) { s.push(i+1); } printStack(s); } // 栈模型 // 栈的算法 和数据类型的分离 // teacher节点 class Teacher { private: int age; char name[32]; public: Teacher() { age = 0; strcpy(name, ""); } Teacher(char *name, int age) { this->age = age; strcpy(this->name, name); } void print() { cout << "name: " << name << "age: " << age << endl; } friend ostream& operator<<(ostream &out, Teacher &obj) { out << " name: " << obj.name << " age: " << obj.age << endl; return out; } }; // 存放类 类型 void test52() { Teacher t1("t1", 31), t2("t2", 32), t3("t3", 33); stack<Teacher> Stack_Tea; Stack_Tea.push(t1); Stack_Tea.push(t2); Stack_Tea.push(t3); while(!Stack_Tea.empty()) { // Teacher重载了<<所以可以 cout<< cout <<Stack_Tea.top(); Stack_Tea.pop(); } } // 存放 类指针 类型 void test53() { Teacher t1("t1", 31), t2("t2", 32), t3("t3", 33); stack<Teacher*> Stack_Tea; Stack_Tea.push(&t1); Stack_Tea.push(&t2); Stack_Tea.push(&t3); // 出栈 while(!Stack_Tea.empty()) { cout << (* Stack_Tea.top()); // Stack_Tea.top() 就是&t1 Stack_Tea.pop(); } } int main() { // test51(); test52(); // test53(); return 0; }
queue
队列,栈都不能提前分配空间,需要进栈出栈, 不能遍历,
队和栈是两种封装好的数据结构
back() 返回最后一个元素
empty() 如果队列空则返回真
front() 返回第一个元素
pop() 删除第一个元素
push() 在末尾加入一个元素
size() 返回队列中元素的个数
// // Created by lk on 18-6-3. // #include <iostream> #include <queue> #include <cstring> using namespace std; // 队列的基本类型 void test61() { queue<int> q; // 队列,栈都不能提前分配空间,需要进栈出栈 // 入队 q.push(1); q.push(3); q.push(5); cout << "队头元素:" << q.front() << endl; // 返回队头元素,不是删除,栈的是删除 cout <<"队的大小:" << q.size() <<endl; cout << "队尾元素:" << q.back() << endl; // 出队 cout <<"出队: "; while(!q.empty()) { cout << q.front() << " "; q.pop(); // 删除队头元素 } } // 队列的算法 和数据类型分离 // teacher 节点 class Teacher { private: int age; char name[32]; public: Teacher() { age = 0; strcpy(name, ""); } Teacher(char *name, int age) { this->age = age; strcpy(this->name, name); } void print() { cout << "name: " << name << " age: " << age << endl; } friend ostream& operator<<(ostream &out, Teacher &obj) { out << "\tname: " << obj.name << " age: " << obj.age << endl; return out; } }; // 存放类 类型 void test62() { Teacher t1("t1", 31), t2("t2", 32), t3("t3", 33); queue<Teacher> queue_Tea; // 队列里面存放的是 Teacher的数据类型 queue_Tea.push(t1); // 入队 queue_Tea.push(t2); queue_Tea.push(t3); cout << "老师节点的出队:\n"; while(!queue_Tea.empty()) { cout << queue_Tea.front() << "\n"; queue_Tea.pop(); // 出队 } } // 存放指针类型 // 类似栈 。。。 int main() { // test61(); test62(); return 0; }
关联容器
https://www.cnblogs.com/xiaokang01/p/9130699.html