【C++】STL 总结

一、vector容器

1、vector容器实现机理

       vector 是可变大小的动态数组,属于顺序容器,在内存中是连续存储的,因此可以支持快速随机访问;此外 vector/string 通常会分配比新空间更大的内存空间(具体实现细节与编译器的版本有关),器会将多分配的剩余空间作为备用,用来存储新的元素。这样,就不需要每次增加新元素都重新分配容器的内存空间,提高性能;

       基于上述机制的vector内存扩张操作通常要比list,deque要好的多,因此在能用vector的前提下,尽量多使用vector;

2、vector容器常见方法

empty();                 //判断容器是否为空
size();                  //返回容器中元素的个数
capacity();              //容器的容量

push_back(ele);          //尾部插入元素ele
pop_back();              //删除最后一个元素

insert(const_iterator pos, ele);                 //迭代器指向位置pos插入元素ele
insert(const_iterator pos, int count,ele);       //迭代器指向位置pos插入count个元素ele

erase(const_iterator pos);                       //删除迭代器指向的元素
erase(const_iterator start, const_iterator end); //删除迭代器从start到end之间的元素

clear();                 //删除容器中所有元素

at(int idx);             //返回索引idx所指的数据
operator[];              //返回索引idx所指的数据

front();                 //返回容器中第一个数据元素
back();                  //返回容器中最后一个数据元素

swap(vec);               // 将vec与本身的元素互换

resize(int num);         //重新指定容器的长度为num,若容器变长,则以默认值填充新位置
​			             //如果容器变短,则末尾超出容器长度的元素被删除

resize(int num, elem);   //重新指定容器的长度为num,若容器变长,则以elem值填充新位置
​				         //如果容器变短,则末尾超出容器长度的元素被删除

二、list 容器

1、list容器实现机理

        链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的;

        STL中的链表是一个双向循环链表, 由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器;

list 的优点

  • 采用动态存储分配,不会造成内存浪费和溢出;
  • 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素;

list 的缺点

  • 链表灵活,但是空间(指针域) 和 时间(遍历)额外耗费较大;

List有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的;

2、list容器常见方法

size();             //返回容器中元素的个数
empty();            //判断容器是否为空

push_back(elem);    //在容器尾部加入一个元素
pop_back();         //删除容器中最后一个元素

push_front(elem);   //在容器开头插入一个元素
pop_front();        //从容器开头移除第一个元素

front();            //返回第一个元素
back();             //返回最后一个元素

reverse();          //反转链表
sort();             //链表排序

insert(pos,elem);   //在pos位置插elem元素的拷贝,返回新数据的位置
insert(pos,n,elem); //在pos位置插入n个elem数据,无返回值
insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值

clear();            //移除容器的所有数据

swap(lst);          //将lst与本身的元素互换

erase(beg,end);     //删除[beg,end)区间的数据,返回下一个数据的位置
erase(pos);         //删除pos位置的数据,返回下一个数据的位置

remove(elem);       //删除容器中所有与elem值匹配的元素

resize(num);        //重新指定容器的长度为num,若容器变长,则以默认值填充新位置
​ 		            //如果容器变短,则末尾超出容器长度的元素被删除
resize(num, elem);  //重新指定容器的长度为num,若容器变长,则以elem值填充新位置

三、stack 容器

1、stack容器实现机理

        stack是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口栈中只有顶端的元素才可以被外界使用,因此栈不允许有遍历行为;

2、stack容器常用方法

stack<T> stk;             //stack采用模板类实现, stack对象的默认构造形式
stack(const stack &stk);  //拷贝构造函数

stack& operator=(const stack &stk);     //重载等号操作符

push(elem);               //向栈顶添加元素

pop();                    //从栈顶移除第一个元素
top();                    //返回栈顶元素

empty();                  //判断堆栈是否为空
size();                   //返回栈的大小

注:常常可以利用栈的性质,用两个栈实现一个队列;

四、queue 容器

1、queue容器实现机理

        Queue是一种先进先出(First In First Out,FIFO)的数据结构,它有两个出口队列容器允许从一端新增元素,从另一端移除元素队列中只有队头和队尾才可以被外界使用,因此队列不允许有遍历行为;

2、queue容器常用方法

queue<T> que;             //queue采用模板类实现,queue对象的默认构造形式
queue(const queue &que);  //拷贝构造函数

queue& operator=(const queue &que); //重载等号操作符

push(elem);               //往队尾添加元素

pop();                    //从队头移除第一个元素
front();                  //返回第一个元素

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

empty();                  //判断堆栈是否为空
size();                   //返回栈的大小

五、deque 容器

1、deque容器实现机理

  • 双端数组,可以对头端进行插入删除操作

deque与vector区别

  • vector对于头部的插入删除效率低,数据量越大,效率越低;
  • deque相对而言,对头部的插入删除速度回比vector快;
  • vector访问元素时的速度会比deque快,这和两者内部实现有关;

deque内部工作原理:

        deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据中控器维护的是每个缓冲区的地址,使得使用deque时一片连续的内存空间;

  • deque容器的迭代器也是支持随机访问的;

2、deque容器常用方法

deque.empty();     //判断容器是否为空
deque.size();      //返回容器中元素的个数

push_back(elem);   //在容器尾部添加一个数据
push_front(elem);  //在容器头部插入一个数据

pop_back();        //删除容器最后一个数据
pop_front();       //删除容器第一个数据

front();           //返回容器中第一个数据元素
back();            //返回容器中最后一个数据元素

at(int idx);       //返回索引idx所指的数据
operator[];        //返回索引idx所指的数据

insert(pos,elem);         //在pos位置插入一个elem元素的拷贝,返回新数据的位置
insert(pos,n,elem);       //在pos位置插入n个elem数据,无返回值
insert(pos,beg,end);      //在pos位置插入[beg,end)区间的数据,无返回值

clear();           //清空容器的所有数据

erase(beg,end);    //删除[beg,end)区间的数据,返回下一个数据的位置
erase(pos);        //删除pos位置的数据,返回下一个数据的位置

sort(iterator beg, iterator end)     //对beg和end区间内元素进行排序

deque.resize(num);       //重新指定容器的长度为num,若容器变长,则以默认值填充新位置
​			             //如果容器变短,则末尾超出容器长度的元素被删除
deque.resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置
​				         //如果容器变短,则末尾超出容器长度的元素被删除


六、set 与 unordered_set

1、set容器实现机理

       基于红黑树实现,红黑树具有自动排序的功能,因此set内部所有的数据,在任何时候,都是有序的;

(1)set/multiset 容器常见方法:

set<T> st;                      //默认构造函数
set(const set &st);             //拷贝构造函数赋值
set& operator=(const set &st);  //重载等号操作符

size();                         //返回容器中元素的数目
empty();                        //判断容器是否为空

swap(st);                       //交换两个集合容器

insert(elem);                   //在容器中插入元素

clear();                        //清除所有元素
erase(pos);                     //删除 pos 迭代器所指的元素,返回下一个元素的迭代器
erase(beg, end);                //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器
erase(elem);                    //删除容器中值为elem的元素

find(key);                      //查找key是否存在,若存在返回该键的元素的迭代器;若不存在,返回                    
                                //set.end();
count(key);                     //统计key的元素个数

// set 和 multiset 的区别
set不可以插入重复数据,而multiset可以
set插入数据的同时会返回插入结果,表示插入是否成功
multiset不会检测数据,因此可以插入重复数据

2、unordered_set容器实现机理

  基于哈希表,数据插入和查找的时间复杂度很低,几乎是常数时间,而代价是消耗比较多的内存无自动排序功能。底层实现上,使用一个下标范围比较大的数组来存储元素,形成很多的桶,利用hash函数对key进行映射到不同区域进行保存;

(1)unordered_set容器常见方法

begin();     //返回指向容器中第一个元素的正向迭代器
end();        //返回指向容器中最后一个元素之后位置的正向迭代器

empty();      //若容器为空,则返回 true;否则 false

size();       //返回当前容器中存有元素的个数

max_size();   //返回容器所能容纳元素的最大个数,不同的操作系统,其返回值亦不相同

find(key);    //查找以值为 key 的元素,如果找到,则返回一个指向该元素的正向迭代器;反之,则返回一            
              //个指向容器中最后一个元素之后位置的迭代器(如果 end() 方法返回的迭代器)
count(key);   //在容器中查找值为 key 的元素的个数

insert();     //向容器中添加新元素

erase(pos);   //删除pos迭代器所指元素,返回下一个元素的迭代器
clear();      //清空容器,即删除容器中存储的所有元素
swap();       //交换 2 个 unordered_map 容器存储的元素,前提是必须保证这2个容器的类型完全相等

3、set使用情况

(1)我们需要有序数据(不同的元素);

(2)我们必须打印/访问数据(按排序顺序);

(3)我们需要元素的前身/后继者;

4、unordered_set使用情况

(1)我们需要保留一组不同的元素,不需要排序;

(2)我们需要单个元素访问,即没有遍历;

七、map 与 unordered_map

1、map/multimap容器实现机理

  • map/multimap属于关联式容器,底层结构是用二叉树实现
  • pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)
  • 所有元素都会根据元素的键值自动排序

优点:

  • 有序性,这是map结构最大的优点,其元素的有序性在很多应用中都会简化很多的操作;红黑树,内部实现一个红黑书使得map的很多操作在logn的时间复杂度下就可以实现,因此效率非常的高;

缺点:

  • 空间占用率高,因为map内部实现了红黑树,虽然提高了运行效率,但是因为每一个节点都需要额外保存父节点,孩子节点以及红/黑性质,使得每一个节点都占用大量的空间;

  • 适用处,对于那些有顺序要求的问题,用map会更高效一些;

map和multimap区别

  • map不允许容器中有重复key值元素
  • multimap允许容器中有重复key值元素

(1)set/multiset 容器常见方法:

map<T1, T2> mp;                     //map默认构造函数
map(const map &mp);                 //拷贝构造函数

eg:
map<int,int>m;                      //默认构造
m.insert(pair<int, int>(1, 10));

size();                             //返回容器中元素的数目
empty();                            //判断容器是否为空
swap(st);                           //交换两个集合容器

insert(elem);                       //在容器中插入元素

clear();                            //清除所有元素

erase(pos);                         //删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg, end);                    //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器
erase(key);                         //删除容器中值为key的元素

find(key);      //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end()
count(key);     //统计key的元素个数

//map容器默认排序规则为 按照key值进行 从小到大排序,掌握如何改变排序规则
//利用仿函数,可以改变排序规则

2、unordered_map容器实现机理

优点:

  •  因为内部实现了哈希表,因此其查找速度非常的快;

缺点:

  •  哈希表的建立比较耗费时间;
  •  适用处,对于查找问题,unordered_map会更加高效一些;

(1)unordered_map容器常见方法:

empty()	        //若容器为空,则返回 true;否则 false
size()	        //返回当前容器中存有键值对的个数

max_size()	    //返回容器所能容纳键值对的最大个数,不同的操作系统,其返回值亦不相同

operator[key]	//该模板类中重载了 [] 运算符,其功能是可以向访问数组中元素那样,只要给定某个键值对的键 key,就可以获取该键对应的值。注意,如果当前容器中没有以 key 为键的键值对,则其会使用该键向当前容器中插入一个新键值对

at(key)	    //返回容器中存储的键 key 对应的值,如果 key 不存在,则会抛出 out_of_range 异常  
   
find(key)	//查找以 key 为键的键值对,如果找到,则返回一个指向该键值对的正向迭代器;反之,则返回一个指向容器中最后一个键值对之后位置的迭代器(如果 end() 方法返回的迭代器)

count(key)	//在容器中查找以 key 键的键值对的个数

equal_range(key)	//返回一个 pair 对象,其包含 2 个迭代器,用于表明当前容器中键为 key 的键值对所在的范围

emplace()	        //向容器中添加新键值对,效率比 insert() 方法高
emplace_hint()	    //向容器中添加新键值对,效率比 insert() 方法高

insert() 	        //向容器中添加新键值对

erase()	            //删除指定键值对

clear() 	        //清空容器,即删除容器中存储的所有键值对

swap()	//交换 2 个 unordered_map 容器存储的键值对,前提是必须保证这 2 个容器的类型完全相等

八、string 容器

1、string容器实现机理

(1)string和char * 区别:

  • char * 是一个指针;
  • string是一个类,类内部封装了char*,管理这个字符串,是一个char*型的容器;

(2)特点:

string 类内部封装了很多成员方法;

例如:查找find,拷贝copy,删除delete 替换replace,插入insert;

string管理char*所分配的内存,不用担心复制越界和取值越界等,由类内部进行负责;

2、string容器常见方法

string();                     //创建一个空的字符串 例如: string str;
string(const char* s);        //使用字符串s初始化
string(const string& str);    //使用一个string对象初始化另一个string对象
string(int n, char c);        //使用n个字符c初始化

//eg:string s4(10, 'a');

string& operator=(const char* s);     //char*类型字符串 赋值给当前的字符串
string& operator=(const string &s);   //把字符串s赋给当前的字符串
string& operator=(char c);            //字符赋值给当前的字符串
string& assign(const char *s);        //把字符串s赋给当前的字符串
string& assign(const char *s, int n); //把字符串s的前n个字符赋给当前的字符串
string& assign(const string &s);      //把字符串s赋给当前字符串
string& assign(int n, char c);        //用n个字符c赋给当前字符串

string& operator+=(const char* str);     //重载+=操作符
string& operator+=(const char c);        //重载+=操作符
string& operator+=(const string& str);   //重载+=操作符
string& append(const char *s);           //把字符串s连接到当前字符串结尾
string& append(const char *s, int n);    //把字符串s的前n个字符连接到当前字符串结尾
string& append(const string &s);         //同operator+=(const string& str)
string& append(const string &s, int pos, int n);    //字符串s中从pos开始的n个字符连接到字符

int find(const string& str, int pos = 0) const;     //查找str第一次出现位置,从pos开始查找
int find(const char* s, int pos = 0) const;         //查找s第一次出现位置,从pos开始查找
int find(const char* s, int pos, int n) const;      //从pos位置查找s的前n个字符第一次位置
int find(const char c, int pos = 0) const;          //查找字符c第一次出现位置
int rfind(const string& str, int pos = npos) const; //查找str最后一次位置,从pos开始查找
int rfind(const char* s, int pos = npos) const;     //查找s最后一次出现位置,从pos开始查找
int rfind(const char* s, int pos, int n) const;     //从pos查找s的前n个字符最后一次位置
int rfind(const char c, int pos = 0) const;         //查找字符c最后一次出现位置
string& replace(int pos, int n, const string& str); //替换从pos开始n个字符为字符串str
string& replace(int pos, int n,const char* s);      //替换从pos开始的n个字符为字符串s
  • 字符串之间的比较

比较方式:

  • 字符串比较是按字符的ASCII码进行对比

        = 返回 0

        > 返回 1

        < 返回 -1

int compare(const string &s) const;     //与字符串s比较
int compare(const char *s) const;       //与字符串s比较

//字符的获取
char& operator[](int n);                //通过[]方式取字符
char& at(int n);                        //通过at方法获取字符

string& insert(int pos, const char* s);         //插入字符串
string& insert(int pos, const string& str);     //插入字符串
string& insert(int pos, int n, char c);         //在指定位置插入n个字符c
string& erase(int pos, int n = npos);           //删除从Pos开始的n个字符

//获取原字符串中的某一区间的字符串
string substr(int pos = 0, int n = npos) const; //返回由pos开始的n个字符组成的字符串

注:此文章内容仅是自己在学习过程中的一个小小总结(且仅是为了以后的学习使用提供方便),在后面的学习过程中会不断地对STL进行完善;

在刷算法题的时候可以根据各个容器的特性做出合适的选择;

猜你喜欢

转载自blog.csdn.net/weixin_47156401/article/details/120356835