0


【STL】:list的模拟实现

朋友们、伙计们,我们又见面了,本期来给大家解读一下有关list的模拟实现,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!

C 语 言 专 栏:C语言:从入门到精通****

数据结构专栏:数据结构****

个 人 主 页 :stackY、****

C + + 专 栏 :C++****

Linux 专 栏 :Linux****

1. 基本构造

list的底层其实是一个带头双向循环的链表,所以在模拟实现之前可以看一下库里面怎么实现的:

  1. namespace ywh
  2. {
  3. //链表结构
  4. template<class T>
  5. struct list_node
  6. {
  7. T _data; //节点中的数据
  8. list_node<T>* _prev; //指向前一个节点的指针
  9. list_node<T>* _next; //指向后一个节点的指针
  10. //构造
  11. list_node(const T& x = T())
  12. :_data(x)
  13. , _prev(nullptr)
  14. , _next(nullptr)
  15. {}
  16. };
  17. //list结构
  18. template<class T>
  19. class list
  20. {
  21. public:
  22. typedef list_node<T> Node;
  23. public:
  24. //空初始化
  25. void empty_init()
  26. {
  27. _head = new Node;
  28. _head->_prev = _head;
  29. _head->_next = _next;
  30. }
  31. //构造
  32. list()
  33. {
  34. empty_init();
  35. }
  36. private:
  37. Node* _head; //链表的头节点
  38. size_t _size; //节点个数
  39. };
  40. }

2. 正向迭代器

在使用list的阶段的迭代器使用方法和之前的string、vector一样,但是了解过链表的结构都知道,链表要访问下一个节点就是使用节点中的next指针指向下一个节点,需要访问里面的数据需要找到里面的data,++和解引用并不能访问链表的节点,那么迭代器的使用在底层肯定是封装加运算符重载。

在实现迭代器的时候也需要采用封装和运算符重载,运算符重载需要用到++、--、!=、==、*、->等运算符。迭代器分为const迭代器和非const迭代器,首先先来看看非const迭代器:

2.1 非const迭代器

迭代器的实现一般使用struct来进行封装:

  1. namespace ljm
  2. {
  3. //链表结构
  4. template<class T>
  5. struct list_node
  6. {
  7. T _data; //节点中的数据
  8. list_node<T>* _prev; //指向前一个节点的指针
  9. list_node<T>* _next; //指向后一个节点的指针
  10. //构造
  11. list_node(const T& x = T())
  12. :_data(x)
  13. , _prev(nullptr)
  14. , _next(nullptr)
  15. {}
  16. };
  17. //非const正向迭代器
  18. template<class T>
  19. struct __list_iterator
  20. {
  21. typedef list_node<T> Node;
  22. typedef __list_iterator<T> self;
  23. Node* _node;
  24. //迭代器构造
  25. __list_iterator(Node* node)
  26. :_node(node)
  27. {}
  28. //前置
  29. //operator++
  30. self& operator++()
  31. {
  32. return _node->_next;
  33. }
  34. //operator--
  35. self& operator--()
  36. {
  37. return _node->_prev;
  38. }
  39. //后置
  40. self operator++(int)
  41. {
  42. self* tmp(_node);
  43. _node = _node->_next;
  44. return tmp;
  45. }
  46. //operator--
  47. self operator--(int)
  48. {
  49. self* tmp(_node);
  50. _node = _node->_prev;
  51. return tmp;
  52. }
  53. //operator*
  54. T& operator*()
  55. {
  56. return _node->_data;
  57. }
  58. //operator->
  59. T* operator->()
  60. {
  61. return &_node->_data;
  62. }
  63. //operator!=
  64. bool operator!=(const self& s)
  65. {
  66. return _node != s._node;
  67. }
  68. //operator==
  69. bool operator==(const self& s)
  70. {
  71. return _node == s._node;
  72. }
  73. };
  74. //list结构
  75. template<class T>
  76. class list
  77. {
  78. public:
  79. typedef list_node<T> Node;
  80. public:
  81. //空初始化
  82. void empty_init()
  83. {
  84. _head = new Node;
  85. _head->_prev = _head;
  86. _head->_next = _head;
  87. }
  88. //构造
  89. list()
  90. {
  91. empty_init();
  92. }
  93. ///正向迭代器
  94. iterator begin()
  95. {
  96. return iterator(_head->_next); //使用匿名对象进行构造
  97. }
  98. iterator end()
  99. {
  100. return iterator(_head);
  101. }
  102. private:
  103. Node* _head; //链表的头节点
  104. size_t _size; //节点个数
  105. };
  106. }

2.2 const迭代器

迭代器中涉及到修改的就是*和->,const迭代器的作用是指向的内容不能修改,本身不能修改,所以需要重新进行封装:

  1. namespace ljm
  2. {
  3. //链表结构
  4. template<class T>
  5. struct list_node
  6. {
  7. T _data; //节点中的数据
  8. list_node<T>* _prev; //指向前一个节点的指针
  9. list_node<T>* _next; //指向后一个节点的指针
  10. //构造
  11. list_node(const T& x = T())
  12. :_data(x)
  13. , _prev(nullptr)
  14. , _next(nullptr)
  15. {}
  16. };
  17. //非const正向迭代器
  18. //...
  19. //const正向迭代器
  20. template<class T>
  21. struct __list_const_iterator
  22. {
  23. typedef list_node<T> Node;
  24. typedef __list_const_iterator<T> self;
  25. Node* _node;
  26. //迭代器构造
  27. __list_const_iterator(Node* node)
  28. :_node(node)
  29. {}
  30. //前置
  31. //operator++
  32. self& operator++()
  33. {
  34. _node = _node->_next;
  35. return *this;
  36. }
  37. //operator--
  38. self& operator--()
  39. {
  40. _node = _node->_prev;
  41. return *this;
  42. }
  43. //后置
  44. self operator++(int)
  45. {
  46. self* tmp(_node);
  47. _node = _node->_next;
  48. return tmp;
  49. }
  50. //operator--
  51. self operator--(int)
  52. {
  53. self* tmp(_node);
  54. _node = _node->_prev;
  55. return tmp;
  56. }
  57. //operator*
  58. const T& operator*()
  59. {
  60. return _node->_data;
  61. }
  62. //operator->
  63. const T* operator->()
  64. {
  65. return &_node->_data;
  66. }
  67. //operator!=
  68. bool operator!=(const self& s)
  69. {
  70. return _node != s._node;
  71. }
  72. //operator==
  73. bool operator==(const self& s)
  74. {
  75. return _node == s._node;
  76. }
  77. };
  78. //list结构
  79. template<class T>
  80. class list
  81. {
  82. public:
  83. typedef list_node<T> Node;
  84. typedef __list_iterator<T> iterator;
  85. typedef __list_const_iterator<T> const_iterator;
  86. public:
  87. 基本构造///
  88. //空初始化
  89. void empty_init()
  90. {
  91. _head = new Node;
  92. _head->_prev = _head;
  93. _head->_next = _head;
  94. }
  95. //构造
  96. list()
  97. {
  98. empty_init();
  99. }
  100. ///正向迭代器
  101. iterator begin()
  102. {
  103. return iterator(_head->_next); //使用匿名对象进行构造
  104. }
  105. iterator end()
  106. {
  107. return iterator(_head);
  108. }
  109. const_iterator begin() const
  110. {
  111. return const_iterator(_head->_next);
  112. }
  113. const_iterator end() const
  114. {
  115. return const_iterator(_head);
  116. }
  117. private:
  118. Node* _head; //链表的头节点
  119. size_t _size; //节点个数
  120. };
  121. }

2.3 正向迭代器的改进优化

上面的这两种写法不难看出有很多代码都是重复出现的,使得代码非常冗余,那么怎么将这些冗余的代码进行合并呢?

我们可以看一下库里面如何实现:

采用泛型编程,使用模板,将这一转化的工作交给编译器,而我们只需传递const参数和非const参数即可:

  1. namespace ywh
  2. {
  3. //链表结构
  4. template<class T>
  5. struct list_node
  6. {
  7. T _data; //节点中的数据
  8. list_node<T>* _prev; //指向前一个节点的指针
  9. list_node<T>* _next; //指向后一个节点的指针
  10. //构造
  11. list_node(const T& x = T())
  12. :_data(x)
  13. , _prev(nullptr)
  14. , _next(nullptr)
  15. {}
  16. };
  17. //非const正向迭代器
  18. // 类型模板参数 传递引用 传递指针
  19. template<class T, class Ref, class Ptr>
  20. struct __list_iterator
  21. {
  22. typedef list_node<T> Node;
  23. typedef __list_iterator<T, Ref, Ptr> self;
  24. Node* _node;
  25. //迭代器构造
  26. __list_iterator(Node* node)
  27. :_node(node)
  28. {}
  29. //前置
  30. //operator++
  31. self& operator++()
  32. {
  33. _node = _node->_next;
  34. return *this;
  35. }
  36. //operator--
  37. self& operator--()
  38. {
  39. _node = _node->_prev;
  40. return *this;
  41. }
  42. //后置
  43. self operator++(int)
  44. {
  45. self* tmp(_node);
  46. _node = _node->_next;
  47. return tmp;
  48. }
  49. //operator--
  50. self operator--(int)
  51. {
  52. self* tmp(_node);
  53. _node = _node->_prev;
  54. return tmp;
  55. }
  56. //operator*
  57. Ref operator*()
  58. {
  59. return _node->_data;
  60. }
  61. //operator->
  62. Ptr operator->()
  63. {
  64. return &_node->_data;
  65. }
  66. //operator!=
  67. bool operator!=(const self& s)
  68. {
  69. return _node != s._node;
  70. }
  71. //operator==
  72. bool operator==(const self& s)
  73. {
  74. return _node == s._node;
  75. }
  76. };
  77. //list结构
  78. template<class T>
  79. class list
  80. {
  81. public:
  82. typedef list_node<T> Node;
  83. typedef __list_iterator<T, T&, T*> iterator; //非const迭代器
  84. typedef __list_iterator<T, const T&, const T*> const_iterator; //const迭代器
  85. public:
  86. 基本构造///
  87. //空初始化
  88. void empty_init()
  89. {
  90. _head = new Node;
  91. _head->_prev = _head;
  92. _head->_next = _head;
  93. }
  94. //构造
  95. list()
  96. {
  97. empty_init();
  98. }
  99. ///正向迭代器
  100. iterator begin()
  101. {
  102. return iterator(_head->_next); //使用匿名对象进行构造
  103. }
  104. iterator end()
  105. {
  106. return iterator(_head);
  107. }
  108. const_iterator begin() const
  109. {
  110. return const_iterator(_head->_next);
  111. }
  112. const_iterator end() const
  113. {
  114. return const_iterator(_head);
  115. }
  116. private:
  117. Node* _head; //链表的头节点
  118. size_t _size; //节点个数
  119. };
  120. }

3. 修改相关接口

3.1 insert、erase

在pos位置进行插入删除比较简单,需要进行链接新节点,改变节点中指针的指向即可,库里面对于插入和删除都带有返回值,那么我们在实现的时候也加上返回值:

  1. ///修改相关接口
  2. //在pos位置插入节点
  3. iterator insert(iterator pos, const T& x)
  4. {
  5. //创建新新节点
  6. Node* newnode = new Node(x);
  7. //链接节点
  8. Node* cur = pos._node;
  9. Node* prev = cur->_prev;
  10. prev->_next = newnode;
  11. newnode->_prev = prev;
  12. newnode->_next = cur;
  13. cur->_prev = newnode;
  14. //更新节点个数
  15. ++_size;
  16. //返回新节点的位置
  17. return iterator(newnode);
  18. }
  19. //删掉pos位置的节点
  20. iterator erase(iterator pos)
  21. {
  22. //保存相对位置
  23. Node* cur = pos._node;
  24. Node* prev = cur->_prev;
  25. Node* next = cur->_next;
  26. //链接节点
  27. delete cur;
  28. prev->_next = next;
  29. next->_prev = prev;
  30. //更新节点个数
  31. --_size;
  32. //返回pos的下一个位置
  33. return iterator(next);
  34. }

在进行insert之后可以看到迭代器是不会失效的,但是在erase之后pos位置会被释放,因此erase之后迭代器会失效,在使用前先更新迭代器。

3.2 尾插、头插、尾删、头删、清理

当实现了insert和erase之后,实现这些接口直接复用即可:

  1. //尾插
  2. void push_back(const T& x)
  3. {
  4. insert(end(), x);
  5. }
  6. //头插
  7. void push_front(const T& x)
  8. {
  9. insert(begin(), x);
  10. }
  11. //尾删
  12. void pop_back()
  13. {
  14. erase(--end());
  15. }
  16. //头删
  17. void pop_front()
  18. {
  19. erase(begin());
  20. }
  21. //清理
  22. void clear()
  23. {
  24. iterator it = begin();
  25. while (it != end())
  26. {
  27. it = erase(it);
  28. }
  29. }

4. 拷贝构造、赋值重载、析构

在这里我们都是采用现代写法:

拷贝构造直接使用迭代器依次遍历进行尾插。

  1. //拷贝构造
  2. list(const list<T>& lt)
  3. {
  4. //先创建空节点
  5. empty_init();
  6. //依次尾插即可
  7. for (auto e : lt)
  8. {
  9. push_back(e);
  10. }
  11. }
  12. //operator=
  13. void swap(list<T>& lt)
  14. {
  15. std::swap(_head, lt._head);
  16. std::swap(_size, lt._size);
  17. }
  18. list<T>& operator=(list<T> lt)
  19. {
  20. swap(lt);
  21. return *this;
  22. }
  23. //析构
  24. ~list()
  25. {
  26. clear();
  27. delete _head;
  28. _head = nullptr;
  29. _size = 0;
  30. }

5. 完整代码

** 头文件:List.h**

  1. #pragma once
  2. namespace ywh
  3. {
  4. //链表结构
  5. template<class T>
  6. struct list_node
  7. {
  8. T _data; //节点中的数据
  9. list_node<T>* _prev; //指向前一个节点的指针
  10. list_node<T>* _next; //指向后一个节点的指针
  11. //构造
  12. list_node(const T& x = T())
  13. :_data(x)
  14. , _prev(nullptr)
  15. , _next(nullptr)
  16. {}
  17. };
  18. //非const正向迭代器
  19. // 类型模板参数 传递引用 传递指针
  20. template<class T, class Ref, class Ptr>
  21. struct __list_iterator
  22. {
  23. typedef list_node<T> Node;
  24. typedef __list_iterator<T, Ref, Ptr> self;
  25. Node* _node;
  26. //迭代器构造
  27. __list_iterator(Node* node)
  28. :_node(node)
  29. {}
  30. //前置
  31. //operator++
  32. self& operator++()
  33. {
  34. _node = _node->_next;
  35. return *this;
  36. }
  37. //operator--
  38. self& operator--()
  39. {
  40. _node = _node->_prev;
  41. return *this;
  42. }
  43. //后置
  44. self operator++(int)
  45. {
  46. self* tmp(_node);
  47. _node = _node->_next;
  48. return tmp;
  49. }
  50. //operator--
  51. self operator--(int)
  52. {
  53. self* tmp(_node);
  54. _node = _node->_prev;
  55. return tmp;
  56. }
  57. //operator*
  58. Ref operator*()
  59. {
  60. return _node->_data;
  61. }
  62. //operator->
  63. Ptr operator->()
  64. {
  65. return &_node->_data;
  66. }
  67. //operator!=
  68. bool operator!=(const self& s)
  69. {
  70. return _node != s._node;
  71. }
  72. //operator==
  73. bool operator==(const self& s)
  74. {
  75. return _node == s._node;
  76. }
  77. };
  78. //list结构
  79. template<class T>
  80. class list
  81. {
  82. public:
  83. typedef list_node<T> Node;
  84. typedef __list_iterator<T, T&, T*> iterator; //非const迭代器
  85. typedef __list_iterator<T, const T&, const T*> const_iterator; //const迭代器
  86. public:
  87. 基本构造///
  88. //空初始化
  89. void empty_init()
  90. {
  91. _head = new Node;
  92. _head->_prev = _head;
  93. _head->_next = _head;
  94. }
  95. //构造
  96. list()
  97. {
  98. empty_init();
  99. }
  100. //拷贝构造
  101. list(const list<T>& lt)
  102. {
  103. //先创建空节点
  104. empty_init();
  105. //依次尾插即可
  106. for (auto e : lt)
  107. {
  108. push_back(e);
  109. }
  110. }
  111. //operator=
  112. void swap(list<T>& lt)
  113. {
  114. std::swap(_head, lt._head);
  115. std::swap(_size, lt._size);
  116. }
  117. list<T>& operator=(list<T> lt)
  118. {
  119. swap(lt);
  120. return *this;
  121. }
  122. //析构
  123. ~list()
  124. {
  125. clear();
  126. delete _head;
  127. _head = nullptr;
  128. _size = 0;
  129. }
  130. ///正向迭代器
  131. iterator begin()
  132. {
  133. return iterator(_head->_next); //使用匿名对象进行构造
  134. }
  135. iterator end()
  136. {
  137. return iterator(_head);
  138. }
  139. const_iterator begin() const
  140. {
  141. return const_iterator(_head->_next);
  142. }
  143. const_iterator end() const
  144. {
  145. return const_iterator(_head);
  146. }
  147. ///修改相关接口
  148. //在pos位置插入节点
  149. iterator insert(iterator pos, const T& x)
  150. {
  151. //创建新新节点
  152. Node* newnode = new Node(x);
  153. //链接节点
  154. Node* cur = pos._node;
  155. Node* prev = cur->_prev;
  156. prev->_next = newnode;
  157. newnode->_prev = prev;
  158. newnode->_next = cur;
  159. cur->_prev = newnode;
  160. //更新节点个数
  161. ++_size;
  162. //返回新节点的位置
  163. return iterator(newnode);
  164. }
  165. //删掉pos位置的节点
  166. iterator erase(iterator pos)
  167. {
  168. //保存相对位置
  169. Node* cur = pos._node;
  170. Node* prev = cur->_prev;
  171. Node* next = cur->_next;
  172. //链接节点
  173. delete cur;
  174. prev->_next = next;
  175. next->_prev = prev;
  176. //更新节点个数
  177. --_size;
  178. //返回pos的下一个位置
  179. return iterator(next);
  180. }
  181. //尾插
  182. void push_back(const T& x)
  183. {
  184. insert(end(), x);
  185. }
  186. //头插
  187. void push_front(const T& x)
  188. {
  189. insert(begin(), x);
  190. }
  191. //尾删
  192. void pop_back()
  193. {
  194. erase(--end());
  195. }
  196. //头删
  197. void pop_front()
  198. {
  199. erase(begin());
  200. }
  201. //清理
  202. void clear()
  203. {
  204. iterator it = begin();
  205. while (it != end())
  206. {
  207. it = erase(it);
  208. }
  209. }
  210. //节点个数
  211. size_t size()
  212. {
  213. return _size;
  214. }
  215. private:
  216. Node* _head; //链表的头节点
  217. size_t _size; //节点个数
  218. };
  219. }

朋友们、伙计们,美好的时光总是短暂的,我们本期的的分享就到此结束,欲知后事如何,请听下回分解~,最后看完别忘了留下你们弥足珍贵的三连喔,感谢大家的支持!

标签: c++ 开发语言 STL

本文转载自: https://blog.csdn.net/Yikefore/article/details/134090437
版权归原作者 stackY、 所有, 如有侵权,请联系我们删除。

“【STL】:list的模拟实现”的评论:

还没有评论