目錄
🚪什么是迭代器?
🔧 迭代器的本質
為什么不用普通數組或下標?
STL容器的迭代器并不是共用一個類型!
迭代器的類型(Iterator Categories)
📦 常見容器的迭代器類型
? 迭代器最常用的動作
🚸 初學者推薦寫法:使用 auto 和 范圍for
🚪什么是迭代器?
迭代器 = “智能指針”,用來一個一個地訪問容器中的元素。
你可以想象迭代器像是容器中的“手指”或“光標”:
-
指著某個元素
-
可以向前走(甚至有些還能往后走)
-
能取出或修改元素
?示例對比:用數組 vs 用迭代器
int arr[] = {10, 20, 30};
for (int i = 0; i < 3; i++) {std::cout << arr[i];
}
改成 vector
+ 迭代器寫法:?
std::vector<int> v = {10, 20, 30};
for (std::vector<int>::iterator it = v.begin(); it != v.end(); ++it) {std::cout << *it;
}
-
v.begin()
:返回指向第一個元素的迭代器 -
v.end()
:返回“超出最后一個元素的下一個位置”的迭代器 -
*it
:表示取出當前指向的元素 -
++it
:移動到下一個元素
🔧 迭代器的本質
迭代器是一個類類型(不是基本類型)
雖然它看起來像指針(用 *it
解引用,用 ++it
移動),但它本質上是一個 C++ 類對象,封裝了訪問容器內部元素的邏輯。
🚩你可以這樣理解:
指針 | 迭代器 |
---|---|
訪問數組元素 | 訪問容器元素 |
用 *ptr 獲取值 | 用 *it 獲取元素 |
是內建類型 | 是類類型(有重載了 * , ++ , == 等操作符) |
🎓 舉個例子看看類型:
std::vector<int> v = {1, 2, 3};
auto it = v.begin();
-
it
實際的類型是std::vector<int>::iterator
-
你可以打印:
std::cout << typeid(it).name() << std::endl;
輸出可能是:__gnu_cxx::__normal_iterator<int*, std::vector<int>>
🔍 它是一個內部實現的類,封裝了指針行為,但比裸指針更安全、更通用。
為什么不用普通數組或下標?
STL 有很多不同的容器:鏈表、哈希表、紅黑樹……
它們里面的元素并不一定支持下標 []
,但每種容器都提供了“迭代器”接口,你可以統一方式遍歷。
容器 | 支持下標? | 支持迭代器? |
---|---|---|
vector | ? | ? |
list | ? | ? |
set | ? | ? |
map | ? | ? |
每個容器都有自己專屬的迭代器類型,std::vector<T>::iterator? 這種寫法是訪問這個類型的一種方式。
STL容器的迭代器并不是共用一個類型!
容器類型 | 對應迭代器類型 |
---|---|
std::vector<T> | std::vector<T>::iterator |
std::list<T> | std::list<T>::iterator |
std::set<T> | std::set<T>::iterator |
std::map<K,V> | std::map<K,V>::iterator |
std::vector<int>::iterator it; // vector 的迭代器
std::list<double>::iterator it2; // list 的迭代器
為什么不統一一個 iterator
類型呢?
👉 因為不同容器的內部結構不同(如數組 vs 鏈表 vs 紅黑樹),它們的迭代器行為也不同。比如:
-
vector
支持隨機訪問 (it + 3
) -
list
只支持前后移動(++it
,--it
)
?
迭代器的類型(Iterator Categories)
STL 根據迭代器的能力,把迭代器分成 五類,從弱到強如下:
類型 | 功能 | 示例容器 |
---|---|---|
InputIterator | 單向只讀 | istream_iterator |
OutputIterator | 單向只寫 | ostream_iterator |
ForwardIterator | 單向讀寫 | forward_list |
BidirectionalIterator | 可雙向移動 | list , set , map |
RandomAccessIterator | 支持隨機訪問 it+n , it1-it2 | vector , deque , array |
💡 STL 算法會根據迭代器的種類選擇最優的操作方式。
?
📦 常見容器的迭代器類型
容器 | 支持的迭代器類型 |
---|---|
vector , deque , array | 隨機訪問迭代器(RandomAccessIterator) |
list | 雙向迭代器(BidirectionalIterator) |
forward_list | 單向迭代器(ForwardIterator) |
set , map , multimap , multiset | 雙向迭代器(BidirectionalIterator) |
unordered_map , unordered_set | 同樣為雙向迭代器 |
隨機訪問迭代器(vector
):?
std::vector<int> v = {1, 2, 3, 4};
auto it = v.begin();
std::cout << *(it + 2); // 輸出:3
?雙向迭代器(list
):
std::list<int> l = {1, 2, 3};
auto it = l.end(); --it;
std::cout << *it; // 輸出:3
?單向迭代器(forward_list
):
std::forward_list<int> fl = {1, 2, 3};
auto it = fl.begin();
++it; // 可以前進,但不能后退
? 迭代器最常用的動作
操作 | 含義 |
---|---|
it = container.begin() | 取得起始位置的迭代器 |
it != container.end() | 判斷是否結束 |
++it | 移動到下一個元素 |
*it | 獲取當前指向的元素 |
std::vector<int> nums = {5, 10, 15};
for (auto it = nums.begin(); it != nums.end(); ++it) {std::cout << *it << " ";
}
操作 | 說明 |
---|---|
--it | 移動到上一個元素(雙向或更強迭代器) |
it == it2 , it != it2 | 比較兩個迭代器 |
it + n , it - n | 隨機訪問(僅支持隨機訪問迭代器) |
std::distance(it1, it2) | 兩個迭代器之間的距離 |
std::advance(it, n) | 將迭代器移動 n 個位置(支持不同迭代器類型) |
🚸 初學者推薦寫法:使用 auto
和 范圍for
從 C++11 開始,可以讓寫法更簡單!
? 用 auto
簡化迭代器聲明:
for (auto it = nums.begin(); it != nums.end(); ++it)
? 更簡單的方法:范圍for(推薦):
范圍 for
是 C++11 引入的一種簡潔寫法,用于遍歷容器或數組。它讓你不需要寫迭代器、不需要用下標,直接訪問每一個元素。?
for (元素類型 變量名 : 容器) {// 使用變量名代表當前元素
}
傳統寫法(使用迭代器):?
std::vector<int> v = {1, 2, 3, 4};
for (std::vector<int>::iterator it = v.begin(); it != v.end(); ++it) {std::cout << *it << "\n";
}
?范圍 for
寫法:
std::vector<int> v = {1, 2, 3, 4};
for (int x : v) {std::cout << x << "\n";
}
?范圍 for
背后的原理:
for (auto it = v.begin(); it != v.end(); ++it) {int x = *it;...
}
所以它仍然依賴迭代器,只不過幫你“自動寫好了”。