目錄
- 迭代器的使用
- 迭代器的種類
- 迭代器的失效
- 迭代器的實現
1.迭代器的使用
為了提高C++編程的效率,STL中提供了許多容器,包括vector、list、map、set等。有些容器例如vector可以通過腳標索引的方式訪問容器里面的數據,但是大部分的容器不能使用這種方式,例如list、map、set。STL中每種容器在實現的時候設計了一個內嵌的iterator類,不同的容器有自己專屬的迭代器,使用迭代器來訪問容器中的數據。除此之外,通過迭代器,可以將容器和通用算法結合在一起,只要給予算法不同的迭代器,就可以對不同容器執行相同的操作,例如find查找函數。迭代器對指針的一些基本操作如*、->、++、==、!=、=進行了重載,使其具有了遍歷復雜數據結構的能力,其遍歷機制取決於所遍歷的數據結構,所有迭代的使用和指針的使用非常相似。通過begin,end函數獲取容器的頭部和尾部迭代器,end 迭代器不包含在容器之內,當begin和end返回的迭代器相同時表示容器為空。
template<typename InputIterator, typename T> InputIterator find(InputIterator first, InputIterator last, const T &value) { while (first != last && *frist != value) ++first; return first; }
#include <iostream> #include <vector> #include <list> #include <algorithm> using namespace std; int main(int argc, const char *argv[]) { int arr[5] = { 1, 2, 3, 4, 5}; vector<int> iVec(arr, arr + 5);//定義容器vector list<int> iList(arr, arr + 5);//定義容器list //在容器iVec的頭部和尾部之間尋找整形數3 vector<int>::iterator iter1 = find(iVec.begin(), iVec.end(), 3); if (iter1 == iVec.end()) cout<<"3 not found"<<endl; else cout<<"3 found"<<endl; //在容器iList的頭部和尾部之間尋找整形數4 list<int>::iterator iter2 = find(iList.begin(), iList.end(), 4); if (iter2 == iList.end()) cout<<"4 not found"<<endl; else cout<<"4 found"<<endl; return 0; }
2.迭代器的種類
根據迭代器所支持的操作,可以把迭代器分為5類。
1) 輸入迭代器:是只讀迭代器,在每個被遍歷的位置上只能讀取一次。例如上面find函數參數就是輸入迭代器。
2) 輸出迭代器:是只寫迭代器,在每個被遍歷的位置上只能被寫一次。
3) 前向迭代器:兼具輸入和輸出迭代器的能力,但是它可以對同一個位置重復進行讀和寫。但它不支持operator--,所以只能向前移動。
4) 雙向迭代器:很像前向迭代器,只是它向后移動和向前移動同樣容易。
5) 隨機訪問迭代器:有雙向迭代器的所有功能。而且,它還提供了“迭代器算術”,即在一步內可以向前或向后跳躍任意位置, 包含指針的所有操作,可進行隨機訪問,隨意移動指定的步數。支持前面四種Iterator的所有操作,並另外支持it + n、it - n、it += n、 it -= n、it1 - it2和it[n]等操作。
STL每種容器類型都定義了 const_iterator,只能讀取容器的值,不能修改所指向容器范圍內元素的值。vector、string、Deque隨機存取迭代器;List、Set、map、mutiset、multimap雙向迭代器。
3.迭代器失效
容器的插入insert和erase操作可能導致迭代器失效,對於erase操作不要使用操作之前的迭代器,因為erase的那個迭代器一定失效了,正確的做法是返回刪除操作時候的那個迭代器。
#include <vector> using namespace std; int main(int argc, const char *argv[]) { int arr[5] = { 1, 2, 3, 4, 5 }; vector<int> iVec(arr, arr + 5); //定義容器vector //迭代器失效 // for (vector<int>::iterator it = iVec.begin(); it != iVec.end();) { // iVec.erase(it); // } //返回erase操作之后的迭代器 for (vector<int>::iterator it = iVec.begin();it != iVec.end();) { it = iVec.erase(it); } return 0; }
4.迭代器的實現
STL中每個容器都有自己的迭代器,各種迭代器的接口相同,內部實現卻不相同,這也直接體現了泛型編程的概念,下面在單鏈表類中內嵌入一個iterator的類來實現單鏈表的迭代
1 #include <iostream> 2 3 template<typename T> 4 struct ListNode { 5 T value; 6 ListNode* next; 7 ListNode() { 8 next = 0; 9 } 10 ListNode(T val, ListNode *p = nullptr) : 11 value(val), next(p) { 12 } 13 }; 14 15 template<typename T> 16 class List { 17 private: 18 ListNode<T> *m_pHead; 19 ListNode<T> *m_pTail; 20 int m_nSize; 21 public: 22 List() { 23 m_pHead = nullptr; 24 m_pTail = nullptr; 25 m_nSize = 0; 26 } 27 //從鏈表尾部插入元素 28 void push_back(T value) { 29 if (m_pHead == nullptr) { 30 m_pHead = new ListNode<T>(value); 31 m_pTail = m_pHead; 32 } else { 33 m_pTail->next = new ListNode<T>(value); 34 m_pTail = m_pTail->next; 35 } 36 37 } 38 39 //打印鏈表元素 40 void print(std::ostream &os = std::cout) const { 41 for (ListNode<T> *ptr = m_pHead; ptr != m_pTail->next ; ptr = ptr->next) 42 std::cout << ptr->value << " "; 43 os << std::endl; 44 } 45 46 //內置迭代器 47 class iterator { 48 private: 49 ListNode<T> *m_ptr; 50 public: 51 iterator(ListNode<T>* p = nullptr) : 52 m_ptr(p) { 53 } 54 55 T operator*() const { 56 return m_ptr->value; 57 } 58 ListNode<T>* operator->() const { 59 return m_ptr; 60 } 61 iterator& operator++() { 62 m_ptr = m_ptr->next; 63 return *this; 64 } 65 iterator operator++(int) { 66 ListNode<T>* tmp = m_ptr; 67 m_ptr = m_ptr->next; 68 return iterator(tmp); 69 } 70 71 bool operator==(const iterator &arg) const { 72 return arg.m_ptr == this->m_ptr; 73 } 74 75 bool operator!=(const iterator &arg) const { 76 return arg.m_ptr != this->m_ptr; 77 } 78 79 }; 80 81 //返回鏈表頭部指針 82 iterator begin() const { 83 return iterator(m_pHead); 84 } 85 86 //返回鏈表尾部指針 87 iterator end() const { 88 return iterator(m_pTail->next); 89 } 90 91 //其它成員函數 92 93 }; 94 95 int main() { 96 List<int> l; 97 l.push_back(1); 98 l.push_back(2); 99 l.print(); 100 for (List<int>::iterator it = l.begin(); it != l.end(); ++it) { 101 std::cout << *it << " "; 102 } 103 std::cout << std::endl; 104 return 0; 105 }
參考: http://blog.csdn.net/shudou/article/details/11099931