C++中的ilst使用以及模擬實現(xiàn)
list介紹
- list是一個類模板,加<類型>實例化才是具體的類。
- list是可以在任意位置進行插入和刪除的序列式容器。
- list的底層是雙向循環(huán)鏈表結(jié)構(gòu),鏈表中每個元素存儲在互不相關(guān)的獨立節(jié)點中,在節(jié)點中通過指針指向其前一個元素和后一個元素。
- 與其他序列式容器相比,list最大的缺陷是不支持任意位置的隨機訪問,比如訪問第六個節(jié)點,必須從已知節(jié)點迭代到該節(jié)點。
雙向鏈表圖解:
list常用接口
1.構(gòu)造
函數(shù) | 功能 |
---|---|
list (size_type n, const value_type& val = value_type()) | 構(gòu)造的list中包含n個值為val的節(jié)點 |
list() | 構(gòu)造空的list |
list (const list& x) | 拷貝構(gòu)造 |
list (InputIterator first, InputIterator last) | 迭代器區(qū)間初始化 (模板,可以傳入其它容器的迭代器區(qū)間) |
2.迭代器
函數(shù) | 功能 |
---|---|
begin()加end() | 獲取第一個數(shù)據(jù)位置的iterator/const_iterator,獲取最后一個數(shù)據(jù)的下一個位置的iterator/const_iterator |
rbegin()加rend() | 反向迭代器,獲取最后一個數(shù)據(jù)位置的reverse_iterator,獲取第一個數(shù)據(jù)前一個位置的reverse_iterator |
3.容量
函數(shù) | 功能 |
---|---|
size() | 獲取有效數(shù)據(jù)個數(shù) |
empty() | 判斷是否為空(size為0為空,返回true) |
4.訪問數(shù)據(jù)
函數(shù) | 功能 |
---|---|
front() | 取到頭節(jié)點數(shù)據(jù)的引用 |
back() | 返回尾節(jié)點數(shù)據(jù)的引用 |
5.增刪查改
函數(shù) | 功能 |
---|---|
push_front (const value_type& val) | 頭插數(shù)據(jù)val |
push_back (const value_type& val) | 尾刪數(shù)據(jù)val |
pop_front() | 頭刪 |
pop_back() | 尾刪 |
insert (iterator position, const value_type& val) | 在position位置中插入值為val的元素 |
erase (iterator position) | 刪除position位置的元素 |
swap(list& x) | 交換兩個list |
clear() | 清空有效數(shù)據(jù) |
6.迭代器失效
迭代失效即迭代器所指向的節(jié)點的無效,即該節(jié)點被刪除了。 因為list的底層結(jié)構(gòu)為帶頭結(jié)點的雙向循環(huán)鏈表,因此在list中進行插入時是不會導(dǎo)致list的迭代器失效的,只有在刪除時才會失效,并且失效的只是指向被刪除節(jié)點的迭代器,其他迭代器不會受到影響。
#include<iostream> #include<list> using namespace std; //錯誤代碼演示 int main() { int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; list<int> l(array, array + sizeof(array) / sizeof(array[0])); auto it = l.begin(); while (it != l.end()) { // erase()函數(shù)執(zhí)行后,it所指向的節(jié)點已被刪除 //因此it無效,在下一次使用it時,必須先給其賦值 it = l.erase(it); //只需要去掉++it,這里修改成it = erase(it)即可 ++it; } return 0; }
list模擬實現(xiàn)
1.迭代器的實現(xiàn)
有別于vector,list的迭代器并不是一個原生的指針,因為使用者需要得到的是節(jié)點中的數(shù)據(jù)而不是整個節(jié)點,而且尋找下一個節(jié)點并不能通過指針簡單的++,所以需要把迭代器單獨封裝成一個類,通過重載*等運算符來完成需求。
namespace MyList { //節(jié)點設(shè)計成結(jié)構(gòu)體,方便訪問 template<typename T> struct list_node { list_node(const T val = T()) :_data(val) , _next(nullptr) , _prev(nullptr) {} T _data; list_node<T>* _next; list_node<T>* _prev; }; //迭代器 //這里設(shè)計模板參數(shù)除了迭代器,還有Ref(引用)和Ptr(指針) //這樣設(shè)計是為了同時生成普通迭代器和const對象的迭代器 //普通對象(可讀可寫):iterator<T, T&, T*> //const對象(可讀不可寫):const_iterator<T, const T&, const T*> template<typename T, typename Ref, typename Ptr> struct __list_iterator { typedef list_node<T> Node; typedef __list_iterator<T, Ref, Ptr> self; //要返回迭代器需要返回實例化對象,重命名一下 Node* _node; __list_iterator(Node* p) :_node(p) {} self& operator++() { _node = _node->_next; return *this; } //后置++ self operator++(int) { self tmp(*this); _node = _node->_next; return tmp; } self& operator--() { _node = _node->_prev; return *this; } self operator--(int) { self tmp(*this); _node = _node->_prev; return tmp; } Ref operator*() { return _node->_data; } //返回指針可以讓自定義類型自行打印,訪問成員 //->操作符,比較特殊,it->_num轉(zhuǎn)換出來其實是it.operator->()->_num Ptr operator->() { return &(_node->_data); } bool operator!=(const self& s) { return _node != s._node; } bool operator==(const self& s) { return _node == s._node; } }; //反向迭代器 //反向迭代器需要進行封裝,其實就是復(fù)用普通迭代器,然后++和--操作反過來 //普通對象(可讀可寫):Reverse_iterator<iterator,T&,T*> //const對象(可讀不可寫):Reverse_iterator<const_iterator,const T&,const T*> template<class Iterator, class Ref, class Ptr> struct Reverse_iterator { typedef Reverse_iterator<Iterator, Ref, Ptr> self; Iterator _it; //構(gòu)造 Reverse_iterator(Iterator it) :_it(it) {} self& operator++() { _it--; return *this; } self operator++(int) { self tmp(*this); _it--; return tmp; } self& operator--() { _it++; return *this; } self operator--(int) { self tmp(*this); _it++; return tmp; } Ref operator*() { return *_it; } Ptr operator->() { return _it; } bool operator!=(const self& s) { return _it != s._it; } bool operator==(const self& s) { return _it == s._it; } }; }
2.完整代碼
#pragma once #include<iostream> using namespace std; namespace MyList { //節(jié)點設(shè)計成結(jié)構(gòu)體,方便訪問 template<typename T> struct list_node { list_node(const T val = T()) :_data(val) , _next(nullptr) , _prev(nullptr) {} T _data; list_node<T>* _next; list_node<T>* _prev; }; //迭代器 //這里設(shè)計模板參數(shù)除了迭代器,還有Ref(引用)和Ptr(指針) //這樣設(shè)計是為了同時生成普通迭代器和const對象的迭代器 //普通對象(可讀可寫):iterator<T, T&, T*> //const對象(可讀不可寫):const_iterator<T, const T&, const T*> template<typename T, typename Ref, typename Ptr> struct __list_iterator { typedef list_node<T> Node; typedef __list_iterator<T, Ref, Ptr> self; //要返回迭代器需要返回實例化對象,重命名一下 Node* _node; __list_iterator(Node* p) :_node(p) {} self& operator++() { _node = _node->_next; return *this; } self operator++(int) { self tmp(*this); _node = _node->_next; return tmp; } self& operator--() { _node = _node->_prev; return *this; } self operator--(int) { self tmp(*this); _node = _node->_prev; return tmp; } Ref operator*() { return _node->_data; } //返回指針可以讓自定義類型自行打印,訪問成員 //->操作符,比較特殊,it->_num轉(zhuǎn)換出來其實是it.operator->()->_num Ptr operator->() { return &(_node->_data); } bool operator!=(const self& s) { return _node != s._node; } bool operator==(const self& s) { return _node == s._node; } }; //反向迭代器 //反向迭代器需要進行封裝,其實就是復(fù)用普通迭代器,然后++和--操作反過來 //普通對象(可讀可寫):Reverse_iterator<iterator,T&,T*> //const對象(可讀不可寫):Reverse_iterator<const_iterator,const T&,const T*> template<class Iterator, class Ref, class Ptr> struct Reverse_iterator { typedef Reverse_iterator<Iterator, Ref, Ptr> self; Iterator _it; Reverse_iterator(Iterator it) :_it(it) {} self& operator++() { _it--; return *this; } self operator++(int) { self tmp(*this); _it--; return tmp; } self& operator--() { _it++; return *this; } self operator--(int) { self tmp(*this); _it++; return tmp; } Ref operator*() { return *_it; } Ptr operator->() { return _it; } bool operator!=(const self& s) { return _it != s._it; } bool operator==(const self& s) { return _it == s._it; } }; template<typename T> class list { typedef list_node<T> Node; public: typedef __list_iterator<T, T&, T*> iterator; typedef __list_iterator<T, const T&, const T*> const_iterator; typedef Reverse_iterator<iterator, T&, T*> reverse_iterator; typedef Reverse_iterator< const_iterator, const T&, const T*> reverse_const_iterator; //迭代器部分 iterator begin() { return _head->_next; } iterator end() { return _head; } const_iterator begin()const { return _head->_next; } const_iterator end()const { return _head; } reverse_iterator rbegin() { return (--end());//_head->_prev } reverse_iterator rend() { return (end());//_head } reverse_const_iterator rbegin()const { return (--end());//_head->_prev } reverse_const_iterator rend()const { return (end());//_head } /// // /// private: //不希望外界調(diào)用,設(shè)計成私有 void empty_init() { _head = new Node; _head->_next = _head; _head->_prev = _head; _size = 0; } public: //構(gòu)造、析構(gòu)部分 list() { empty_init(); } list(size_t n, const T& value = T()) { empty_init(); while (n--) { push_back(value); } } //重載給內(nèi)置類型使用,整形默認是int,不寫這個會優(yōu)先匹配list(Iterator first, Iterator last) list(int n, const T& value = T()) { empty_init(); while (n--) { push_back(value); } } //迭代器區(qū)間初始化 template <class Iterator> list(Iterator first, Iterator last) { empty_init(); while(first != last) { push_back(*first); first++; } } list(const list<T>& lt) { empty_init(); for (auto e : lt) { push_back(e); } } ~list() { clear(); delete _head; _head = nullptr; } //其它 void swap(list<T> lt) { std::swap(_size, lt._size); std::swap(_head, lt._head); } //使用傳之傳參,直接拷貝一份交換操作的底層空間就好 list<T>& operator=(list<T> lt) { swap(lt); return *this; } void clear() { iterator it = begin(); while (it != end()) { it = erase(it); } } /// / / //訪問頭,尾數(shù)據(jù) T& front() { return _head->_next->_data; } const T& front()const { return _head->_next->_data; } T& back() { return _head->_prev->_data; } const T& back()const { return _head->_prev->_data; } /// // /// //增加刪除部分 void push_back(const T& val) { insert(end(), val); } void push_front(const T& val) { insert(begin(), val); } iterator insert(iterator pos, const T& val) { Node* newnode = new Node(val); Node* cur = pos._node; Node* prev = cur->_prev; cur->_prev = newnode; newnode->_next = cur; newnode->_prev = prev; prev->_next = newnode; ++_size; return newnode; } void pop_back() { erase(--end()); } void pop_front() { erase(begin()); } iterator erase(iterator pos) { Node* cur = pos._node; Node* prev = cur->_prev; Node* next = cur->_next; prev->_next = next; next->_prev = prev; delete cur; --_size; return next; } //獲取有效數(shù)據(jù)量 size_t size() { return _size; } private: Node* _head; //這里存儲衛(wèi)兵節(jié)點,因為底層是雙向循環(huán)鏈表,可以找到頭和尾 size_t _size; //只需要在insert和erase里面加減就可以 }; }
以上就是C++中的ilst使用以及模擬實現(xiàn)的詳細內(nèi)容,更多關(guān)于C++ list使用及實現(xiàn)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語言植物大戰(zhàn)數(shù)據(jù)結(jié)構(gòu)二叉樹遞歸
這篇文章主要為大家介紹了C語言植物大戰(zhàn)數(shù)據(jù)結(jié)構(gòu)二叉樹遞歸,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-05-05