1. 基本框架
首先,我們先從節點的準備工作入手,請看示例:????????
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
//節點
template<class T>
struct ListNode
{ListNode<T>* _next;ListNode<T>* _prev;T _data;ListNode(const T& data = T()):_next(nullptr), _prev(nullptr), _data(data){}
};
在上述代碼中:先定義一個雙向鏈表的節點結構ListNode。節點結構ListNode包含以下成員變量:
????????1. _next:指向下一個節點的指針。
????????2. _prev:指向上一個節點的指針。
????????3. _data:存儲節點數據的變量。
????????節點結構ListNode還包含一個構造函數,用于初始化成員變量。構造函數接受一個參數data,用于初始化_data成員變量。如果沒有提供參數,則_data成員變量的默認值為T(),即T類型的默認構造函數的返回值。
????????該頭文件還使用了iostream和assert.h兩個標準頭文件,并使用了std命名空間。
2. 封裝迭代器
請看示例代碼:
//迭代器template<class T, class Ref, class Ptr>struct ListIterator{typedef ListNode<T> Node;typedef ListIterator<T, Ref, Ptr> Self;Node* _node;ListIterator(Node* node):_node(node){}// ++it;Self& operator++(){_node = _node->_next;return *this;}Self& operator--(){_node = _node->_prev;return *this;}Self operator++(int){Self tmp(*this);_node = _node->_next;return tmp;}Self& operator--(int){Self tmp(*this);_node = _node->_prev;return tmp;}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator!=(const Self& it){return _node != it._node;}bool operator==(const Self& it){return _node == it._node;}};
在上述代碼中:定義了一個迭代器結構ListIterator,用于遍歷雙向鏈表。迭代器結構ListIterator包含以下成員變量和成員函數:
成員變量: _node:指向當前迭代器所指向的節點的指針。
成員函數如下:
????????1. 構造函數:接受一個參數node,用于初始化迭代器的節點指針。
????????2. 前置遞增運算符(++it):將迭代器指向下一個節點,并返回自身的引用。
????????3. 前置遞減運算符(--it):將迭代器指向上一個節點,并返回自身的引用。
????????4. 后置遞增運算符(it++):將迭代器指向下一個節點,并返回之前的迭代器的副本。
????????5. 后置遞減運算符(it--):將迭代器指向上一個節點,并返回之前的迭代器的副本。
????????6. 解引用運算符(*):返回迭代器指向節點的數據的引用。
????????7. 成員訪問運算符(->):返回迭代器指向節點數據的指針。
????????8. 不等于運算符(!=):判斷當前迭代器是否與另一個迭代器不相等。
????????9. 等于運算符(==):判斷當前迭代器是否與另一個迭代器相等。
迭代器結構ListIterator還使用了兩個類型別名:
????????1. Node:表示節點類型ListNode<T>。
????????2. Self:表示迭代器自身類型ListIterator<T, Ref, Ptr>。
3. 迭代器和構造函數
請看示例代碼:
template<class T>class list{typedef ListNode<T> Node;public:// 不符合迭代器的行為,無法遍歷//typedef Node* iterator;//typedef ListIterator<T> iterator;//typedef ListConstIterator<T> const_iterator;typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T*> const_iterator;iterator begin(){//iterator it(_head->_next);//return it;return iterator(_head->_next);}const_iterator begin() const{return const_iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator end() const{return const_iterator(_head);}list(){_head = new Node();_head->_next = _head;_head->_prev = _head;}
該部分定義了一個雙向鏈表類list。
list類包含以下成員變量和成員函數:
????????1. typedef Node:類型別名,表示節點類型ListNode<T>。
????????2. typedef iterator:類型別名,表示迭代器類型ListIterator<T, T&, T*>。
????????3. typedef const_iterator:類型別名,表示常量迭代器類型ListIterator<T, const T&, const T*>。
成員函數如下:
????????1. begin():返回頭節點的下一個節點的迭代器,用于遍歷鏈表。
????????2. begin() const:返回頭節點的下一個節點的常量迭代器,用于遍歷常量鏈表。
????????3. end():返回頭節點的迭代器,用于判斷迭代結束。
????????4. end() const:返回頭節點的常量迭代器,用于判斷常量迭代結束。
????????5. 構造函數:初始化頭節點,將頭節點的_next和_prev指向自身。
注意:由于ListIterator的設計不符合迭代器的行為,無法進行迭代,所以在list類中注釋掉了typedef iterator和typedef const_iterator的定義。
3. push_back、pop_back、push_front和pop_front
請看示例代碼:
void push_back(const T& x)
{/*Node* newnode = new Node(x);Node* tail = _head->_prev;tail->_next = newnode;newnode->_prev = tail;newnode->_next = _head;_head->_prev = newnode;*/insert(end(), x);
}void pop_back()
{erase(--end());
}void push_front(const T& x)
{insert(begin(), x);
}void pop_front()
{erase(begin());
}
這部分代碼實現了list類的push_back、pop_back、push_front和pop_front成員函數。
????????1. push_back:在鏈表末尾添加一個節點。首先創建一個新的節點newnode,然后獲取鏈表末尾的節點tail,將tail的_next指向newnode,newnode的_prev指向tail,newnode的_next指向頭節點_head,頭節點的_prev指向newnode。最后調用insert函數,在末尾迭代器的位置插入新節點。
????????2. pop_back:刪除鏈表末尾的節點。首先獲取鏈表末尾節點的前一個節點,然后調用erase函數,將末尾迭代器的前一個位置的節點刪除。
????????3. push_front:在鏈表開頭添加一個節點。調用insert函數,在開頭迭代器的位置插入新節點。
????????4. pop_front:刪除鏈表開頭的節點。調用erase函數,將開頭迭代器的位置的節點刪除。
4. insert和erase
請看示例代碼:
// 沒有iterator失效iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* newnode = new Node(x);Node* prev = cur->_prev;// prev newnode curprev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;return iterator(newnode);}// erase 后 pos失效了,pos指向節點被釋放了iterator erase(iterator pos){assert(pos != end());Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;return iterator(next);}
這部分代碼實現了list類的insert和erase成員函數。
????????1. insert:在指定位置前插入一個節點。首先獲取迭代器pos所指向的節點cur,創建一個新的節點newnode,然后獲取pos的前一個節點prev。將prev的_next指向newnode,newnode的_prev指向prev,newnode的_next指向cur,cur的_prev指向newnode。最后返回一個指向新節點的迭代器。
????????2. erase:刪除指定位置的節點。首先斷言pos不等于end(),即pos不是指向末尾的迭代器。然后獲取迭代器pos所指向的節點cur,分別獲取cur的前一個節點prev和后一個節點next。將prev的_next指向next,next的_prev指向prev。刪除cur節點,并釋放內存。最后返回一個指向刪除節點后的節點的迭代器。
????????需要注意的是,在使用erase函數刪除節點時,要確保操作前的迭代器pos不會失效,否則會導致未定義行為。
????????到此我們只是簡單的模擬實現了一下STL中list的相關接口~,后續我們會一一展開學習的,希望這篇博客能給您帶來一些啟發和思考!那我們下次再一起探險嘍,歡迎在評論區進行討論~~~