1. 程式人生 > >泛型程式設計學習,編寫一個類似STL庫中的簡易list的迭代器(iterator)

泛型程式設計學習,編寫一個類似STL庫中的簡易list的迭代器(iterator)

泛型程式設計學習,編寫一個類似STL庫中的簡易list的迭代器(iterator)

前言

近期在研究stl原始碼及stl裡各種實現的細節,初學入門免不了模仿,以下便寫一次自己的簡單的list容器的迭代器。
首先,在開始編寫List的迭代器的時候我們首先應該瞭解我們要寫的List和其迭代器要做出什麼樣的功能。(學習書籍《C++STL基礎應用》《STL原始碼剖析》《泛型思維》)


list

list相較於vector,list的好處是每次插入/刪除一個數據,他就重新申請/釋放一個空間,對記憶體的把握絕對的精準(vector是申請一片區域,超過此容量便進行“重新配置兩倍區域,元素移動,釋放原空間”);另外 對於元素的移動,list永遠是常數的時間。

迭代器

每一個容器都應有對應的迭代器(iterator),容器通過迭代器共享某一具體演算法(之後使用display()函式舉例)。迭代器是演算法和容器之間起媒介作用(display(iterator it1,iterator it2)),迭代器思維的產生是編制泛型演算法發展的必然結果。

簡單的display()函式

template<class T>
void display(T start, T end) {
	cout << endl;
	for (T i = start; i != end; i++) {
		cout << *i <<
endl; } cout << endl; }

我的目的就是為了使我編寫的list容器可以使用此display()函式。


編寫

list

我們想要的基礎的list需要:基本的結點struct Node(含*head 和 *prev分別指向下一位和前一位結點)

//	  head->Node1->Node2->......Noden->tail
//	  next ->  next  ->  next  ->......  next  ->tail->NULL
//NULL<-  prev<-  prev  <- prev   <-...... prev  
template<class T> struct Node { Node* next; Node* prev; T data; Node(T s = 0, Node* n = NULL, Node* p = NULL) :data(s), next(n), prev(p) {}; //Node的建構函式 };

確定好了Node開始編寫class list

template<class T>
class list {
public:
	struct  Node
	{
		//......
	};
	//iterator
	class iterator 
	{
		//......
	};
	//_list的迭代器
private:
	Node * head,*tail;         //我們編寫的list含首、尾指標
	int _size;
	void createlist() {
		_size = 0;
		head = new Node();
		tail = new Node();
		head->next = tail;
		tail->prev = head;
	}
public:
	list() {
		createlist();
	}
	~list() {
		while (!empty()) {
			pop_front();
		}
		delete head;
		delete tail;
	}
	bool empty()const { return _size == 0; };
	iterator begin() {
		return iterator(head->next);
	}
	iterator end() {
		return iterator(tail);
	}
	iterator insert(iterator pos, const T& value) {  
	//const T& value :const 防止引用引用被修改,引用傳遞相當於傳遞指標,8位元組 
	//而值傳遞會呼叫複製建構函式,佔用記憶體大
		Node* p = new Node(value, pos.cur, pos.cur->prev);
		_size++;
		p->prev->next = p;
		pos.cur->prev = p;
		return iterator(p);
		// 大佬的寫法
		//return iterator(p->prev = p->prev->next = new Node(val, p, p->prev));
	}
	iterator erase(iterator pos) {
		Node* p = pos.cur;
		iterator newite(p->next);
		p->prev->next = p->next;
		p->next->prev = p->prev;
		delete p;
		_size--;
		return newite;
	}
	void push_back(const T& value) {
		insert(end(), value);
	}
	void push_front(const T& value) {
		insert(begin(), value);
	}
	void pop_front() {
		erase(begin());
	}
	void pop_back() {
		erase(end());
	}
};

這樣,我們的list就含有基礎的push_back,push_front,pop_back,pop_front,insert,erase功能,和構造、析構函數了。

list 的iterator的編寫

template<class T>
class list {
public:
	struct  Node
	{
		//......Node的實現內容
	};
	//iterator
	class iterator {
	private:
		Node* cur; //指標,指向link的結點
	public:
		friend class list;   
		//重要!將list宣告為iterator的友元,iterator才可訪問list的private
		explicit iterator(Node* p=0) {cur = p; } 
		//阻止不應該允許的經過轉換建構函式進行的隱式轉換的發生。
		//宣告為explicit的建構函式不能在隱式轉換中使用
		bool operator ==(iterator& x) { return (*this).cur == x.cur; }
		bool operator !=(iterator& x) { return (*this).cur != x.cur; }
		iterator& operator++() {  //字首++
			cur = cur->next;
			return *this;
		}
		iterator operator++(int) { //字尾++
			iterator temp = *this;
			++(*this);
			return temp;
		}
		iterator& operator--() {
			cur = cur->prev;
			return *this;
		}
		iterator operator--(int) {
			iterator temp = *this;
			--(*this);
			return temp;
		}
		Node* operator->() {
			return cur;
		}
		T operator*() { return cur->data; }
		//如果不寫這一個,我們可以使用編寫過載全域性
		//ostream operator<<(ostream& os,const iterator& it)
		//來實現display()中的“cout<<*iterator;”
	};
	//_list的迭代器
	//......
	//list的實現內容
};

因為display()函式中使用了++,!=,->,因此需要寫迭代器的符號過載。

T operator*() { return cur->data; }

如果不寫這一個,我們可以使用編寫過載全域性

ostream operator<<(ostream& os,const iterator& it){ //實現細節 }

來實現display()中的“

cout<<*iterator;


main()函式及執行結果

#include"_list.h"
#include<iostream>
using namespace std;
int main() {
	list<int>a;
	for (int i = 0; i < 5; i++) {
		a.push_back(i);
	}
	list<int>::iterator itb = a.begin();
	list<int>::iterator ite = a.end();
	display(itb, ite); // 0 1 2 3 4

	a.insert(ite, 5);
	display(itb, ite); //0 1 2 3 4 5 

	cout << *itb<<endl; // 0
	cout<<*(++itb)<<endl;//1
	cout << *(--ite) << endl<<endl;//5

	a.pop_back();
	display(a.begin(), a.end());// 0 1 2 3 4

	
	system("pause");
	return 0;
}

至此簡歷list及其迭代器就編寫完了。
STL中list容器類的clear,remove,unique,splice,merge,reverse,sort等元素操作留著之後實現。
github個人部落格