【C++】STL 总结

简介: 【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)map/multimap 容器常见方法:


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()             //删除指定键值对,map.erase(val);
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进行完善;

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

相关文章
|
2月前
|
存储 算法 C++
C++ STL 初探:打开标准模板库的大门
C++ STL 初探:打开标准模板库的大门
108 10
|
2月前
|
存储 搜索推荐 C++
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
55 2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
|
2月前
|
存储 程序员 C++
C++常用基础知识—STL库(2)
C++常用基础知识—STL库(2)
74 5
|
2月前
|
存储 自然语言处理 程序员
C++常用基础知识—STL库(1)
C++常用基础知识—STL库(1)
67 1
|
2月前
|
安全 测试技术 C++
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化2
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化
65 6
|
2月前
|
安全 测试技术 C++
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化1
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化
67 7
|
2月前
|
算法 安全 Linux
【C++STL简介】——我与C++的不解之缘(八)
【C++STL简介】——我与C++的不解之缘(八)
|
2月前
|
存储 C++ 容器
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器1
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
55 5
|
2月前
|
安全 C语言 C++
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
【C++篇】探寻C++ STL之美:从string类的基础到高级操作的全面解析
38 4
|
2月前
|
编译器 C语言 C++
【C++篇】解密 STL 动态之魂:全面掌握 C++ vector 的高效与优雅
【C++篇】解密 STL 动态之魂:全面掌握 C++ vector 的高效与优雅
52 3