泛型程式設計學習,編寫一個類似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個人部落格