STL 簡單 iterator 的實現(含原始碼)
我使用vs2015寫的程式(原始碼下載)
STL的中心思想在於將容器(container)和演算法(algorithms)分開,彼此獨立設計,最後再以一貼膠著劑將它們撮合在一起,而這個膠著劑就是迭代器(iterator)。
迭代器是訪問容器的工具。注意,先有容器,才有訪問容器的工具。迭代器需要了解容器的特性才能實現,這決定了迭代器必須要深入到容器內部,於是STL乾脆把迭代器的開發交給容器的設計者。
迭代器的開發分為三步:
1. 元素的設計;
2. 裝載元素的容器的設計;
3. 訪問容器的迭代器的設計;
為了方便起見,我設計的是一款基於單向連結串列的迭代器。根據迭代器的開發步驟,首先給出連結串列節點的設計程式碼。
ListItem.h:
<pre name="code" class="cpp">#ifndef _CGH_LIST_ITEM_ #define _CGH_LIST_ITEM_ // 定義連結串列節點型別 template<typename T> class ListItem{ public: Tvalue() const{ return _value; } ListItem*next() const{ return _next; } ListItem(Tvalue) : _value(value), _next(NULL) { } public: T_value; ListItem*_next; }; #endif
連結串列節點主要包含兩個成員變數:
1. 儲存節點值的_value;
2. 指向下一個節點的_next指標。
接下來是容器的設計,我開發的容器是單向連結串列,單向連結串列類的程式碼如下:
template<typename T> class cghList{ public: voidinsert_front(T value); // 插入節點到連結串列頭部 voidinsert_end(T value); // 插入節點到連結串列尾部 voiddisplay(std::ostream& os = std::cout)const; // 從頭到尾列印連結串列 cghList():_end(NULL), _front(NULL) { } // 建構函式,初始化頭指標、尾指標 ListItem<T>*front()const{ return _front; } // 返回頭指標 ListItem<T>*end()const{ return _end; } // 返回尾指標 private: ListItem<T>*_end; // 連結串列尾指標 ListItem<T>*_front; // 連結串列頭指標 long_size; // 連結串列長度 };
單向連結串列的成員變數和成員函式的作用很簡單,全是基本的連結串列操作。成員函式的實現不復雜,主要是對連結串列的頭插和尾插。成員函式的實現程式碼如下。
// 插入節點到連結串列頭部
template<typename T>
void cghList<T>::insert_front(T value){
cghList<T>::_size++;
ListItem<T>*tmp = new ListItem<T>(value);
if(typename cghList<T>::_front == NULL) {
typenamecghList<T>::_front = tmp;
typenamecghList<T>::_end = tmp;
}
else{
tmp->_next= _front;
_front= tmp;
}
}
// 插入節點到連結串列尾部
template<typename T>
void cghList<T>::insert_end(T value){
cghList<T>::_size++;
ListItem<T>*tmp = new ListItem<T>(value);
if(typename cghList<T>::_front == NULL) {
typenamecghList<T>::_front = tmp;
typenamecghList<T>::_end = tmp;
}
else{
typenamecghList<T>::_end->_next = tmp;
typenamecghList<T>::_end = typename cghList<T>::_end->_next;
}
}
//從頭到尾列印連結串列
template<typename T>
void cghList<T>::display(std::ostream&os = std::cout)const{
if(typename cghList<T>::_front == NULL || typename cghList<T>::_end ==NULL){
return;
}
ListItem<T>*tmp = typename cghList<T>::_front;
while(tmp != NULL){
std::cout<< tmp->_value << std::endl;
tmp= tmp->_next;
}
}
有了容器和容器的元素,接下來就是最關鍵的迭代器啦~
上程式碼:
cghIterator.h
#ifndef _CGH_ITERATOR_
#define _CGH_ITERATOR
template<typename Item>
struct ListIter : public std::iterator<std::forward_iterator_tag,Item>
{
Item*ptr; // 容器與迭代器的紐帶
ListIter(Item*p = 0) :ptr(p) { } // 建構函式,初始化ptr指標
Item&operator*() const { return *ptr; } // 返回容器(本例為連結串列)的節點引用
Item*operator->() const { return ptr; } // 返回容器(本例為連結串列)的節點地址
// 指向容器(本例為連結串列)的下一個節點,i++
ListIter&operator++(){
ptr= ptr->next();
return*this;
}
// 指向容器(本例為連結串列)的下一個節點,++i
ListIter&operator++(int){
ListItertmp = *this;
++*this;
returntmp;
}
//判斷兩節點是否相等,也就是判斷兩節點的地址是否相同
booloperator==(const ListIter& i) const{
returnptr == i.ptr;
}
//判斷兩節點是否不相等,也就是判斷兩節點的地址是否不相同
booloperator!=(const ListIter& i) const{
returnptr != i.ptr;
}
};
#endif
迭代器直接用struct定義的,而不是class,為什麼呢?因為class的成員變數和成員函式預設是private訪問許可權,而struct的成員變數和成員函式預設是public訪問許可權。設計成struct也就是說任何人都可以使用迭代器的所有屬性和功能。
本迭代器唯一也是最重要的成員成員變數是ptr指標,ptr其實就是ListItem*型別,是聯絡連結串列和迭代器的橋樑。
接下來是測試容器的程式碼:
// iterator.cpp : 定義控制檯應用程式的入口點。
//
#include "stdafx.h"
#include "cghList.h"
#include "cghIterator.h"
#include "ListItem.h"
#include<iostream>
int _tmain(int argc, _TCHAR* argv[])
{
cghList<int>myList; // 定義容器
//往容器中加入節點
for(int i = 0; i < 5; i++){
myList.insert_front(i);
}
//從前向後列印節點
//myList.display();
for(ListIter<ListItem<int>> iter = myList.front(); iter != myList.end();iter++){
std::cout<< iter->_value << std::endl;
}
system("pause");
return0;
}
有了這個雛形,就可以往裡面添磚加瓦了,有興趣的童鞋可以在此基礎上修改,寫出自己的功能強大的迭代器!