C++ STL模板庫7-迭代器
文章目錄
- C++ STL模板庫7-迭代器
- 一、迭代器的核心作用
- 二、迭代器的五大分類與操作
- 三、關鍵用法與代碼示例
- 1. 迭代器的原理
- 2. 迭代器用法與示例
- 3. 迭代工具用法示例
- 4. 使用技巧
迭代器是C++中連接容器與算法的通用接口,提供了一種訪問容器元素的統一方式,類似于指針但更強大。
使用迭代器需包含 <iterator>
一、迭代器的核心作用
-
解耦容器與算法
- 算法(如
std::sort
,std::copy
)通過迭代器操作容器,無需知道容器具體類型(數組、鏈表等)。 - 示例:
std::sort(vec.begin(), vec.end())
可對vector
、deque
等均生效。
- 算法(如
-
統一訪問模式
- 無論容器如何存儲數據(連續內存/鏈表/樹),迭代器提供一致的遍歷接口(
++
,*
,->
)。
- 無論容器如何存儲數據(連續內存/鏈表/樹),迭代器提供一致的遍歷接口(
-
支持范圍操作
- 通過
begin()
和end()
定義半開區間[begin, end)
,安全遍歷且避免越界。
- 通過
二、迭代器的五大分類與操作
-
根據功能由弱到強分為:
分類 支持操作 典型容器 輸入迭代器 只讀一次( *it
,++
,==
)istream_iterator
輸出迭代器 只寫一次( *it=
,++
)ostream_iterator
前向迭代器 多次讀寫( ++
)forward_list
, 哈希表雙向迭代器 雙向移動( ++
,--
)list
,set
,map
隨機訪問迭代器 跳躍訪問( +n
,-n
,[]
, 比較)vector
,deque
, 數組 -
核心聲明語法
容器類型::iterator 變量名; // 可修改元素的迭代器 容器類型::const_iterator 變量名; // 只讀元素的迭代器 容器類型::reverse_iterator 變量名; // 反向迭代器
vector<int>::iterator it = vn.begin (); array<int,5>::iterator it = vn.begin (); array<string>::iterator it = vn.begin ();
下面的語句令一個整型向量的迭代器指向該向量的第一個元素:
it = vn.begin ();
而下面的語句令該迭代器指向向量中最后一個元素的下一個位置:
it = vn.end ();
通過begin()和end()構建迭代循環:for (vector<int>::iterator it = vn.begin(); it != vn.end (); it++)... 一般用 auto 類型推導代替 vector<int>::iterator ,來縮短代碼和防止出錯
遍歷容器中元素。
迭代器的基本操作:*、++/–、+/-/+=/-=整數(部分容器的迭代器) -
迭代器工具函數(需包含
<iterator>
)函數 語法/示例 作用 std::advance
advance(iter, n)
移動迭代器n步(支持正負方向) std::distance
distance(iter1, iter2)
計算兩個迭代器之間的元素數量 std::next
/std::prev
next(iter, n=1)
或prev(iter, n=1)
獲取移動后的迭代器副本(不修改原迭代器) 示例:
std::deque<int> dq = {10, 20, 30}; auto dq_it = dq.begin(); std::advance(dq_it, 2); // 移動到第3個元素(30) auto count = std::distance(dq.begin(), dq.end()); // 計算長度(3) auto next_it = std::next(dq_it, -1); // 獲取前一個位置的迭代器(20)
三、關鍵用法與代碼示例
1. 迭代器的原理
迭代器本質是抽象化的指針
迭代器模式的核心價值在于解耦數據結構和算法
int arr[5] = {10, 20, 30, 40, 50}; // ? 指針作為迭代器的用法
int* begin = arr; // 首元素迭代器
int* end = arr + 5; // 尾后迭代器 // 遍歷操作
for (int* it = begin; it != end; ++it) { std::cout << *it << " "; // 輸出:10 20 30 40 50
} // 隨機訪問
*(begin + 2) = 99; // 修改第三個元素 → arr[2]=99
std::cout << begin[3]; // 輸出:40(等價于*(begin+3)) // 算法應用
auto min_pos = begin;
for (int* p = begin + 1; p != end; ++p) { if (*p < *min_pos) min_pos = p;
}
std::cout << "最小值:" << *min_pos; // 輸出:10
- 指針迭代的缺點:
- 無邊界檢查:
end + 1
會導致未定義行為 - 無類型封裝:無法區分
int*
是迭代器還是普通指針 - 功能缺失:不支持反向迭代器等高級特性
- 無邊界檢查:
2. 迭代器用法與示例
-
遍歷數組(正/反向)
#include <iostream> #include <array> int main() { std::array<int, 4> arr = {10, 20, 30, 40}; // 正向迭代器(常量與非常量) for(auto it = arr.begin(); it != arr.end(); ++it) { *it += 1; // 修改元素值 std::cout << *it << " "; // 輸出:11 21 31 41 } // 反向迭代器(C++11) for(auto rit = arr.rbegin(); rit != arr.rend(); ++rit) { std::cout << *rit << " "; // 輸出:41 31 21 11 } }
-
遍歷容器
std::array<int, 3> arr = {10, 20, 30}; for (std::array<int, 3>::iterator it = arr.begin(); it != arr.end(); ++it) { std::cout << *it << " "; // 輸出:10 20 30 } auto it = arr.begin() + 2; *it = 99; // // C++11范圍for(底層使用迭代器) for (int val : arr) { std::cout << val << " "; //輸出:10 20 99 }
-
與標準算法結合
#include <iostream> #include <array> #include <algorithm> #include <numeric> // accumulate? 必須包含此頭文件 int main() { std::array<int, 4> arr = {10, 20, 30, 40}; // 正向迭代器(常量與非常量)//std::array<int, 4>::iterator it for(auto it = arr.begin(); it != arr.end(); ++it) { *it += 1; // 修改元素值 std::cout << *it << " "; // 輸出:11 21 31 41 } // 反向迭代器(C++11) for(auto rit = arr.rbegin(); rit != arr.rend(); ++rit) { std::cout << *rit << " "; // 輸出:41 31 21 11 } std::sort(arr.begin(), arr.end()); // 查找元素 auto pos = std::find(arr.cbegin(), arr.cend(), 21); if(pos != arr.end()) { std::cout << "位置索引:" << pos - arr.begin()<<std::endl; // 輸出:1 } // 累加計算(C++17) int sum = std::accumulate(arr.cbegin(), arr.cend(), 0);std::cout << "總和:" << sum<<std::endl; // 輸出:104 }
-
隨機訪問操作
auto first = arr.begin(); auto third = first + 2; // 直接跳轉到索引2 std::cout << *(first + 1) <<std::endl; // 輸出:21(等價于arr[1]) std::cout << (third > first) <<std::endl; // 輸出:1(支持比較) std::cout << third[1] <<std::endl; // 輸出:41(索引相對訪問)
-
安全訪問:常量迭代器
void printArray(const std::array<int, 4>& arr) { // 使用cbegin/cend防止意外修改 for(auto it = arr.cbegin(); it != arr.cend(); ++it) { std::cout << *it << " "; // *it = 0; // 錯誤!常量迭代器禁止修改 } }
3. 迭代工具用法示例
-
基礎迭代器操作工具
-
std::next
/std::prev
(安全位移)#include <iterator> std::vector<int> vec{10, 20, 30, 40};// 向前移動2步(支持所有迭代器類型) auto it_next = std::next(vec.begin(), 2); // 指向30 // 向后移動1步(僅雙向迭代器可用) auto it_prev = std::prev(vec.end(), 1); // 指向40
-
std::advance
(原位修改迭代器)auto it = vec.begin(); std::advance(it, 3); // it直接指向40(無返回值,修改原迭代器)
特性對比:
- 與
std::next
的區別:直接修改迭代器,適用于循環中逐步推進。
- 與
-
std::distance
(計算距離)int len = std::distance(vec.begin(), vec.end()); // 輸出4(元素總數)
兼容性:
- 隨機訪問迭代器:O(1) 時間復雜度
- 其他迭代器:O(n) 時間復雜度(需遍歷)
-
4. 使用技巧
-
迭代器的顯式聲明和類型推導
- 顯式聲明
std::array<int, 4>::iterator it;
- 類型推導
auto it;
- 顯式聲明
-
獲取首尾元素的迭代器
auto front_it = arr.begin(); // 首元素迭代器 auto back_it = arr.end() - 1; // 尾元素迭代器(因end()指向末尾后一位)
-
數組與指針互操作
int* ptr = arr.data(); // 獲取原生指針 auto it_from_ptr = arr.begin() + (ptr - arr.data()); // 指針轉迭代器
-
優先使用范圍
for
循環for (int val : arr) { ... } // 簡潔安全
-
只讀訪問用
cbegin/cend
auto it = arr.cbegin(); // 明確表達只讀意圖
-
隨機訪問時檢查邊界
if(index < arr.size()) { auto it = arr.begin() + index; }