一、Vector和list的區別——從“它們是什么”到“區別在哪兒”
1. 它們是什么?
-
Vector:類似于一排排整齊的書架(數組),存放元素時,元素排成一條線,連續存儲。可以很快通過編號(索引)找到任何一項。
-
List:像一串珠子,每個珠子知道前后兩個珠子(通過指針連接),存儲位置不連續。有兩種常用鏈表:單鏈表和雙鏈表,雙鏈表每個節點都知道前后兩個節點。
2. 它們的主要差別
比較點 | Vector | List |
---|---|---|
存儲方式 | 連續內存(數組式) | 非連續(鏈式) |
訪問元素 | 支持隨機訪問(用下標直接取) | 需要遍歷,逐個走鏈找到 |
插入/刪除(尾部) | 快(攤銷時間O(1)) | 快(指針操作,無移動元素) |
中間插入/刪除 | 復雜(需要移動大量元素,時間O(n)) | 方便(只需調整鏈表指針,時間O(1)) |
內存使用 | 占用連續空間,偶爾會需要重新“擴容” | 多占用空間(存指針) |
迭代速度 | 快(緩存友好,占用連續內存) | 相對慢(節點散布內存,緩存效率低) |
二、實際工作中的應用場景——什么時候用Vector,什么時候用list?
場景一:你要頻繁隨機訪問元素——用Vector
- 比如存儲一組數據,之后可能會多次訪問(查找、排序)
場景二:你需要在中間插入或刪除元素——用List
- 比如維護一個任務隊列,任務需要頻繁插入到中間或刪除, 或是在鏈表頭尾操作
場景三:尾部頻繁插入刪除(比如維護動態數組),用Vector
場景四:需要穩定的元素存儲,不頻繁改變結構,容器大小變化不大,用Vector
三、迭代器會失效的情況——擦亮眼睛,避免“坑”!
1. 什么是迭代器?
- 就像指針一樣的東西,用來看“容器”里的元素。比如
auto it = vec.begin();
,用it
可以遍歷所有元素。
2. 什么時候迭代器會失效?
Vector的情況
- push_back
- 增加元素可能會導致容器重新分配(擴容)
- 這時候所有原有的迭代器都“作廢”了(指向的地址變了)
- erase(刪除元素)
- 刪除元素后,除非用返回值重啟迭代器,否則原迭代器會失效
- resize(調整大小)
- 改變容器大小也可能導致迭代器失效
List的情況
- 插入和刪除操作
- 不會影響其他迭代器,只要你不刪除它們指向的元素,迭代器不會失效
3. 小結——什么情況下失效?
容器類型 | 會導致迭代器失效的操作 | 示例 |
---|---|---|
Vector | push_back() (擴容時),erase() ,resize() | 添加元素導致重分配,刪除某元素后繼續用舊迭代器 |
List | 一般情況下不會失效,只要不刪除迭代器指向的元素 | 插入、刪除元素不會使其他迭代器失效 |
四、通俗點的理解——比喻和總結
比喻:搬家和串珠
-
Vector:就像把所有房子(元素)堆在一排(連續內存)里。搬家(擴容)時,可能要找個更大的車(新空間),搬出來所有房子(大量移動元素),舊的地址都不能用了(迭代器失效)
-
List:像一串串珠子,每個珠子用線串起來(指針連接)。插入或刪除珠子,只要調轉指針就行,不會影響其他珠子。
小結一句話
- Vector:“快、連續、隨機訪問”——適合“讀多寫少、以訪問為主”的場景,但擴容時可能會“搬家”,導致迭器失效。
- List:”鏈式、插入刪除快“——適合“頻繁插入刪除、順序存儲不變”的場景,不會輕易導致迭代器失效,只要注意不要刪除你關心的珠子。