STL容器总结

一. 种类:
  • 标准STL序列容器vectorstringdequelist
  • 标准STL关联容器setmultisetmapmultimap
  • 非标准序列容器slistropeslist是一个单向链表,rope本质上是一个重型字符串
  • 非标准关联容器hash_sethash_multisethash_maphash_multimap
  • 几种标准非STL容器,包括数组、bitsetvalarraystackqueuepriority_queue

      值得注意的是,数组可以和STL算法配合,因为指针可以当作数组的迭代器使用

  二.删除元素
如果想删除东西,记住 remove 算法后,要加上 erase
所谓删除算法,最终还是要调用成员函数去删除某个元素,但是因为 remove 并不知道它现在作用于哪个容器,所以 remove 算法不可能真的删除一个元素
1.Vector
 
复制代码
vector < int >  v;   
v.reserve(
10 );   
for  ( int  i  =   1 ; i  <=   10 ++ i) {
 v.push_back(i);
}
cout 
<<  v.size();    //  10
v[ 3 =  v[ 5 =  v[ 9 =   99
remove(v.begin(), v.end(), 
99 ); 
// v.erase(remove(v.begin(),v.end(),99),v.end());
cout  <<  v.size();    //  10!
复制代码
2. list
list<int> listTest;
listTest.remove(99);// 这个成员函数将真的删除元素,并且要比 erase+remove 高效
remove remove_if 之间的十分相似。但 unique 行为也像 remove 。它用来从一个区间删除东西(邻近的重复值)而不用访问持有区间元素的容器。如果你真的要从容器中删除元素,你也必须成对调用 unique erase unique list 中也类似于 remove 。正像 list::remove 真的删除东西(而且比 erase-remove 惯用法高效得多)。 list::unique 也真的删除邻近的重复值(也比 erase-unique 高效)。
 
三 迭代器失效:
 
一个网友提的问题:

void   main() 

vector 
<string> vcs; 
vcs.push_back( 
"this   is   A "); 
vector 
<string   > ::iterator   it=vcs.begin(); 
int   i=9
for(;it!=vcs.end();++it) 

cout 
< < "caplity   of   vector   is   :   " < <vcs.size() < <endl; 

cout 
< < "---> " < <*it < <endl;   //去掉此句会有一个超过vector 
                                   
//大小的循环,高手能解释一下为什么? 
if(i==9

vcs.push_back( 
"this   is   BBBBB "); 
cout 
< < "vcs.push! " < <endl; 

i
=8

}
典型的迭代器失效.
 
vector
1.当插入(push_back)一个元素后,end操作返回的迭代器肯定失效。
2.当插入(push_back)一个元素后,capacity返回值与没有插入元素之前相比有改变,则需要重新加载整个容器,此时first和end操作返回的迭代器都会失效。
3.当进行删除操作(erase,pop_back)后,指向删除点的迭代器全部失效;指向删除点后面的元素的迭代器也将全部失效。
deque迭代器的失效情况:
1.在deque容器首部或者尾部插入元素不会使得任何迭代器失效。
2.在其首部或尾部删除元素则只会使指向被删除元素的迭代器失效。
3.在deque容器的任何其他位置的插入和删除操作将使指向该容器元素的所有迭代器失效。
List/set/map
1. 删除时,指向该删除节点的迭代器失效
复制代码
list < int >  intList; 
list
< int > ::iterator it  =  intList.begin(); 
while (it  !=  intList.end()) 

it 
=  intList.erase(it); 
…… 
}
复制代码
四.选择时机<转>--总结各种容器特点
(1) vector
内部数据结构:数组。
随机访问每个元素,所需要的时间为常量。
在末尾增加或删除元素所需时间与元素数目无关,在中间或开头增加或删除元素所需时间随元素数目呈线性变化。
可动态增加或减少元素,内存管理自动完成,但程序员可以使用reserve()成员函数来管理内存。
vector的迭代器在内存重新分配时将失效(它所指向的元素在该操作的前后不再相同)。当把超过capacity()-size()个元素插入vector中时,内存会重新分配,所有的迭代器都将失效;否则,指向当前元素以后的任何元素的迭代器都将失效。当删除元素时,指向被删除元素以后的任何元素的迭代器都将失效。

(2)deque
内部数据结构:数组。
随机访问每个元素,所需要的时间为常量。
在开头和末尾增加元素所需时间与元素数目无关,在中间增加或删除元素所需时间随元素数目呈线性变化。
可动态增加或减少元素,内存管理自动完成,不提供用于内存管理的成员函数。
增加任何元素都将使deque的迭代器失效。在deque的中间删除元素将使迭代器失效。在deque的头或尾删除元素时,只有指向该元素的迭代器失效。

(3)list
内部数据结构:双向环状链表。
不能随机访问一个元素。
可双向遍历。
在开头、末尾和中间任何地方增加或删除元素所需时间都为常量。
可动态增加或减少元素,内存管理自动完成。
增加任何元素都不会使迭代器失效。删除元素时,除了指向当前被删除元素的迭代器外,其它迭代器都不会失效。

(4)slist
内部数据结构:单向链表。
不可双向遍历,只能从前到后地遍历。
其它的特性同list相似。

(5)stack
适配器,它可以将任意类型的序列容器转换为一个堆栈,一般使用deque作为支持的序列容器。
元素只能后进先出(LIFO)。
不能遍历整个stack。

(6)queue
适配器,它可以将任意类型的序列容器转换为一个队列,一般使用deque作为支持的序列容器。
元素只能先进先出(FIFO)。
不能遍历整个queue。

(7)priority_queue
适配器,它可以将任意类型的序列容器转换为一个优先级队列,一般使用vector作为底层存储方式。
只能访问第一个元素,不能遍历整个priority_queue。
第一个元素始终是优先级最高的一个元素。

(8)set
键和值相等。
键唯一。
元素默认按升序排列。
如果迭代器所指向的元素被删除,则该迭代器失效。其它任何增加、删除元素的操作都不会使迭代器失效。

(9)multiset
键可以不唯一。
其它特点与set相同。

(10)hash_set
与set相比较,它里面的元素不一定是经过排序的,而是按照所用的hash函数分派的,它能提供更快的搜索速度(当然跟hash函数有关)。
其它特点与set相同。

(11)hash_multiset
键可以不唯一。
其它特点与hash_set相同。

(12)map
键唯一。
元素默认按键的升序排列。
如果迭代器所指向的元素被删除,则该迭代器失效。其它任何增加、删除元素的操作都不会使迭代器失效。

(13)multimap
键可以不唯一。
其它特点与map相同。

(14)hash_map
与map相比较,它里面的元素不一定是按键值排序的,而是按照所用的hash函数分派的,它能提供更快的搜索速度(当然也跟hash函数有关)。
其它特点与map相同。

(15)hash_multimap
键可以不唯一。
其它特点与hash_map相同。
### 特点与用途总结 #### `vector` `vector` 是一个动态数组,支持随机访问迭代器,可以在尾部高效地添加或删除元素。由于其内部结构是连续存储的,因此在中间或头部插入/删除元素会导致大量元素移动[^3]。 ```cpp std::vector<int> v; v.push_back(1); // 尾部添加元素 v.pop_back(); // 尾部删除元素 ``` #### `list` `list` 是一个双向链表,支持常数时间内在任意位置插入和删除元素。不支持随机访问,只能通过迭代器进行顺序访问。适用于频繁插入/删除操作的场景[^2]。 ```cpp std::list<int> l; l.push_back(1); // 尾部添加元素 l.push_front(0); // 头部添加元素 l.pop_back(); // 尾部删除元素 l.pop_front(); // 头部删除元素 ``` #### `deque` `deque` 是一个双端队列,支持在头部和尾部高效地插入和删除元素。内部结构由中控器管理的分段连续空间组成,允许快速随机访问[^2]。 ```cpp std::deque<int> dq; dq.push_back(1); // 尾部添加元素 dq.push_front(0); // 头部添加元素 dq.pop_back(); // 尾部删除元素 dq.pop_front(); // 头部删除元素 ``` #### `queue` `queue` 是一个先进先出(FIFO)的数据结构,默认基于 `deque` 实现。提供 `push` 和 `pop` 方法来操作元素[^1]。 ```cpp std::queue<int> q; q.push(1); // 添加元素 q.pop(); // 删除元素 ``` #### `stack` `stack` 是一个后进先出(LIFO)的数据结构,默认基于 `deque` 实现。提供 `push` 和 `pop` 方法来操作元素[^1]。 ```cpp std::stack<int> s; s.push(1); // 添加元素 s.pop(); // 删除元素 ``` #### `set` `set` 是一个有序集合,默认基于红黑树实现。所有元素都是唯一的,并且按照特定顺序存储[^1]。 ```cpp std::set<int> st; st.insert(1); // 插入元素 st.erase(1); // 删除元素 ``` #### `map` `map` 是一个有序键值对容器,默认基于红黑树实现。每个键都是唯一的,并且按照特定顺序存储。 ```cpp std::map<std::string, int> m; m["one"] = 1; // 插入键值对 m.erase("one"); // 删除键值对 ``` ### 选择建议 - 如果需要随机访问并且尾部操作较多,使用 `vector`。 - 如果需要频繁在任意位置插入/删除元素,使用 `list`。 - 如果需要高效的头部和尾部操作,使用 `deque`。 - 如果需要实现队列行为,使用 `queue`。 - 如果需要实现栈行为,使用 `stack`。 - 如果需要保持元素唯一并按顺序存储,使用 `set`。 - 如果需要保持键值对唯一并按顺序存储,使用 `map`。 ### 相关问题 1. C++ STL 中 `unordered_set` 和 `unordered_map` 的特点是什么? 2. 如何在 C++ STL 中选择合适的数据结构? 3. C++ STL 中 `vector` 和 `deque` 的性能差异是什么? 4. C++ STL 中 `list` 和 `forward_list` 的区别是什么? 5. C++ STL 中 `set` 和 `multiset` 的区别是什么?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值