皆さん、またお会いしましょう。今回は list のシミュレーション実装について説明します。読んで少しでも興味を持っていただけましたら、ぜひコメントを残してください。あなたの願いがすべて叶いますように。
C 言語コラム:C 言語: 初心者からマスターまで
データ構造列:データ構造
个 人 主 页 :stackY、
C + + 专 栏 :C++
Linux 专 栏 :Linux
目次
3.2 テール挿入、ヘッド挿入、テール削除、ヘッド削除、クリーニング
1. 基本構造
リストの最下層は実際には、先頭に双方向ループを持つリンク リストなので、実装をシミュレートする前に、それがライブラリでどのように実装されているかを確認できます。
namespace ywh { //链表结构 template<class T> struct list_node { T _data; //节点中的数据 list_node<T>* _prev; //指向前一个节点的指针 list_node<T>* _next; //指向后一个节点的指针 //构造 list_node(const T& x = T()) :_data(x) , _prev(nullptr) , _next(nullptr) {} }; //list结构 template<class T> class list { public: typedef list_node<T> Node; public: //空初始化 void empty_init() { _head = new Node; _head->_prev = _head; _head->_next = _next; } //构造 list() { empty_init(); } private: Node* _head; //链表的头节点 size_t _size; //节点个数 }; }
2. 前方反復子
リストを使う段階でイテレータを使う方法は、先ほどの文字列やベクトルと同じですが、リンクリストの構造を知っていれば、リンクリストの次のノードにアクセスするには、ノード内の次のポインタは次のノードを指すため、内部のデータにアクセスする必要があります。内部のデータを見つける必要があり、++ と逆参照はリンク リストのノードにアクセスできないため、イテレータを使用する必要があります。カプセル化され、さらに最下位レベルで演算子のオーバーロードが行われます。
イテレーターを実装するときは、カプセル化と演算子のオーバーロードも使用する必要があります。演算子のオーバーロードでは、++、--、!=、==、*、-> などの演算子を使用する必要があります。イテレータは const イテレータと非 const イテレータに分けられます。まず、非 const イテレータを見てみましょう。
2.1 非定数反復子
イテレータの実装は通常、struct を使用してカプセル化されます。
namespace ljm { //链表结构 template<class T> struct list_node { T _data; //节点中的数据 list_node<T>* _prev; //指向前一个节点的指针 list_node<T>* _next; //指向后一个节点的指针 //构造 list_node(const T& x = T()) :_data(x) , _prev(nullptr) , _next(nullptr) {} }; //非const正向迭代器 template<class T> struct __list_iterator { typedef list_node<T> Node; typedef __list_iterator<T> self; Node* _node; //迭代器构造 __list_iterator(Node* node) :_node(node) {} //前置 //operator++ self& operator++() { return _node->_next; } //operator-- self& operator--() { return _node->_prev; } //后置 self operator++(int) { self* tmp(_node); _node = _node->_next; return tmp; } //operator-- self operator--(int) { self* tmp(_node); _node = _node->_prev; return tmp; } //operator* T& operator*() { return _node->_data; } //operator-> T* operator->() { return &_node->_data; } //operator!= bool operator!=(const self& s) { return _node != s._node; } //operator== bool operator==(const self& s) { return _node == s._node; } }; //list结构 template<class T> class list { public: typedef list_node<T> Node; public: //空初始化 void empty_init() { _head = new Node; _head->_prev = _head; _head->_next = _head; } //构造 list() { empty_init(); } ///正向迭代器 iterator begin() { return iterator(_head->_next); //使用匿名对象进行构造 } iterator end() { return iterator(_head); } private: Node* _head; //链表的头节点 size_t _size; //节点个数 }; }
2.2 定数反復子
イテレータに含まれる変更は * と -> です。const イテレータの機能は、指すコンテンツは変更できず、コンテンツ自体も変更できないため、再カプセル化する必要があることです。
namespace ljm { //链表结构 template<class T> struct list_node { T _data; //节点中的数据 list_node<T>* _prev; //指向前一个节点的指针 list_node<T>* _next; //指向后一个节点的指针 //构造 list_node(const T& x = T()) :_data(x) , _prev(nullptr) , _next(nullptr) {} }; //非const正向迭代器 //... //const正向迭代器 template<class T> struct __list_const_iterator { typedef list_node<T> Node; typedef __list_const_iterator<T> self; Node* _node; //迭代器构造 __list_const_iterator(Node* node) :_node(node) {} //前置 //operator++ self& operator++() { _node = _node->_next; return *this; } //operator-- self& operator--() { _node = _node->_prev; return *this; } //后置 self operator++(int) { self* tmp(_node); _node = _node->_next; return tmp; } //operator-- self operator--(int) { self* tmp(_node); _node = _node->_prev; return tmp; } //operator* const T& operator*() { return _node->_data; } //operator-> const T* operator->() { return &_node->_data; } //operator!= bool operator!=(const self& s) { return _node != s._node; } //operator== bool operator==(const self& s) { return _node == s._node; } }; //list结构 template<class T> class list { public: typedef list_node<T> Node; typedef __list_iterator<T> iterator; typedef __list_const_iterator<T> const_iterator; public: 基本构造/// //空初始化 void empty_init() { _head = new Node; _head->_prev = _head; _head->_next = _head; } //构造 list() { empty_init(); } ///正向迭代器 iterator begin() { return iterator(_head->_next); //使用匿名对象进行构造 } iterator end() { return iterator(_head); } const_iterator begin() const { return const_iterator(_head->_next); } const_iterator end() const { return const_iterator(_head); } private: Node* _head; //链表的头节点 size_t _size; //节点个数 }; }
2.3 前方イテレータの改善と最適化
上記の 2 つの記述方法から、多くのコードが繰り返され、コードが非常に冗長になっていることがわかります。
これをライブラリに実装する方法を見てみましょう。
汎用プログラミングとテンプレートを使用すると、この変換作業はコンパイラーに渡され、const パラメーターと非 const パラメーターを渡すだけで済みます。
namespace ywh { //链表结构 template<class T> struct list_node { T _data; //节点中的数据 list_node<T>* _prev; //指向前一个节点的指针 list_node<T>* _next; //指向后一个节点的指针 //构造 list_node(const T& x = T()) :_data(x) , _prev(nullptr) , _next(nullptr) {} }; //非const正向迭代器 // 类型模板参数 传递引用 传递指针 template<class T, class Ref, class Ptr> struct __list_iterator { typedef list_node<T> Node; typedef __list_iterator<T, Ref, Ptr> self; Node* _node; //迭代器构造 __list_iterator(Node* node) :_node(node) {} //前置 //operator++ self& operator++() { _node = _node->_next; return *this; } //operator-- self& operator--() { _node = _node->_prev; return *this; } //后置 self operator++(int) { self* tmp(_node); _node = _node->_next; return tmp; } //operator-- self operator--(int) { self* tmp(_node); _node = _node->_prev; return tmp; } //operator* Ref operator*() { return _node->_data; } //operator-> Ptr operator->() { return &_node->_data; } //operator!= bool operator!=(const self& s) { return _node != s._node; } //operator== bool operator==(const self& s) { return _node == s._node; } }; //list结构 template<class T> class list { public: typedef list_node<T> Node; typedef __list_iterator<T, T&, T*> iterator; //非const迭代器 typedef __list_iterator<T, const T&, const T*> const_iterator; //const迭代器 public: 基本构造/// //空初始化 void empty_init() { _head = new Node; _head->_prev = _head; _head->_next = _head; } //构造 list() { empty_init(); } ///正向迭代器 iterator begin() { return iterator(_head->_next); //使用匿名对象进行构造 } iterator end() { return iterator(_head); } const_iterator begin() const { return const_iterator(_head->_next); } const_iterator end() const { return const_iterator(_head); } private: Node* _head; //链表的头节点 size_t _size; //节点个数 }; }
3. 関連するインターフェースを変更する
3.1 挿入、消去
pos 位置での挿入と削除は比較的簡単です. 新しいノードをリンクし、ノード内のポインタの向きを変更する必要があります. ライブラリには挿入と削除の両方の戻り値があるので、戻り値も追加します実装する場合:
///修改相关接口 //在pos位置插入节点 iterator insert(iterator pos, const T& x) { //创建新新节点 Node* newnode = new Node(x); //链接节点 Node* cur = pos._node; Node* prev = cur->_prev; prev->_next = newnode; newnode->_prev = prev; newnode->_next = cur; cur->_prev = newnode; //更新节点个数 ++_size; //返回新节点的位置 return iterator(newnode); } //删掉pos位置的节点 iterator erase(iterator pos) { //保存相对位置 Node* cur = pos._node; Node* prev = cur->_prev; Node* next = cur->_next; //链接节点 delete cur; prev->_next = next; next->_prev = prev; //更新节点个数 --_size; //返回pos的下一个位置 return iterator(next); }
挿入後イテレータの有効期限は切れませんが、消去後に位置が解放されるため、消去後はイテレータが無効になることがわかります。使用する前にイテレータを更新してください。
3.2 テール挿入、ヘッド挿入、テール削除、ヘッド削除、クリーニング
挿入と消去が実装された後、これらのインターフェイスは直接再利用できます。
//尾插 void push_back(const T& x) { insert(end(), x); } //头插 void push_front(const T& x) { insert(begin(), x); } //尾删 void pop_back() { erase(--end()); } //头删 void pop_front() { erase(begin()); } //清理 void clear() { iterator it = begin(); while (it != end()) { it = erase(it); } }
4. コピー構築、代入のオーバーロード、および破棄
ここでは全員が現代文を使用します。
コピー構築では、反復子を直接使用して、末尾の挿入のために順次走査します。
//拷贝构造 list(const list<T>& lt) { //先创建空节点 empty_init(); //依次尾插即可 for (auto e : lt) { push_back(e); } } //operator= void swap(list<T>& lt) { std::swap(_head, lt._head); std::swap(_size, lt._size); } list<T>& operator=(list<T> lt) { swap(lt); return *this; } //析构 ~list() { clear(); delete _head; _head = nullptr; _size = 0; }
5. 完全なコード
ヘッダーファイル: List.h
#pragma once namespace ywh { //链表结构 template<class T> struct list_node { T _data; //节点中的数据 list_node<T>* _prev; //指向前一个节点的指针 list_node<T>* _next; //指向后一个节点的指针 //构造 list_node(const T& x = T()) :_data(x) , _prev(nullptr) , _next(nullptr) {} }; //非const正向迭代器 // 类型模板参数 传递引用 传递指针 template<class T, class Ref, class Ptr> struct __list_iterator { typedef list_node<T> Node; typedef __list_iterator<T, Ref, Ptr> self; Node* _node; //迭代器构造 __list_iterator(Node* node) :_node(node) {} //前置 //operator++ self& operator++() { _node = _node->_next; return *this; } //operator-- self& operator--() { _node = _node->_prev; return *this; } //后置 self operator++(int) { self* tmp(_node); _node = _node->_next; return tmp; } //operator-- self operator--(int) { self* tmp(_node); _node = _node->_prev; return tmp; } //operator* Ref operator*() { return _node->_data; } //operator-> Ptr operator->() { return &_node->_data; } //operator!= bool operator!=(const self& s) { return _node != s._node; } //operator== bool operator==(const self& s) { return _node == s._node; } }; //list结构 template<class T> class list { public: typedef list_node<T> Node; typedef __list_iterator<T, T&, T*> iterator; //非const迭代器 typedef __list_iterator<T, const T&, const T*> const_iterator; //const迭代器 public: 基本构造/// //空初始化 void empty_init() { _head = new Node; _head->_prev = _head; _head->_next = _head; } //构造 list() { empty_init(); } //拷贝构造 list(const list<T>& lt) { //先创建空节点 empty_init(); //依次尾插即可 for (auto e : lt) { push_back(e); } } //operator= void swap(list<T>& lt) { std::swap(_head, lt._head); std::swap(_size, lt._size); } list<T>& operator=(list<T> lt) { swap(lt); return *this; } //析构 ~list() { clear(); delete _head; _head = nullptr; _size = 0; } ///正向迭代器 iterator begin() { return iterator(_head->_next); //使用匿名对象进行构造 } iterator end() { return iterator(_head); } const_iterator begin() const { return const_iterator(_head->_next); } const_iterator end() const { return const_iterator(_head); } ///修改相关接口 //在pos位置插入节点 iterator insert(iterator pos, const T& x) { //创建新新节点 Node* newnode = new Node(x); //链接节点 Node* cur = pos._node; Node* prev = cur->_prev; prev->_next = newnode; newnode->_prev = prev; newnode->_next = cur; cur->_prev = newnode; //更新节点个数 ++_size; //返回新节点的位置 return iterator(newnode); } //删掉pos位置的节点 iterator erase(iterator pos) { //保存相对位置 Node* cur = pos._node; Node* prev = cur->_prev; Node* next = cur->_next; //链接节点 delete cur; prev->_next = next; next->_prev = prev; //更新节点个数 --_size; //返回pos的下一个位置 return iterator(next); } //尾插 void push_back(const T& x) { insert(end(), x); } //头插 void push_front(const T& x) { insert(begin(), x); } //尾删 void pop_back() { erase(--end()); } //头删 void pop_front() { erase(begin()); } //清理 void clear() { iterator it = begin(); while (it != end()) { it = erase(it); } } //节点个数 size_t size() { return _size; } private: Node* _head; //链表的头节点 size_t _size; //节点个数 }; }
友人の皆さん、楽しい時間はいつも短いです。この号での共有はここで終わりです。次に何が起こるかを知りたい場合は、次のエピソードを聞いてください~。読み終わった後は、大切な人を残すことを忘れないでください。ありがとうございました。あなたのサポート!