当前位置:   article > 正文

C++ 数据结构之-双向链表(link_list)_c++双向链表

c++双向链表

双向链表

        双向链表(Doubly Linked List)是一种常见的数据结构,它与单向链表相似,但每个节点有两个指针,一个指向前一个节点(前驱节点),一个指向后一个节点(后继节点)。

        双向链表中的每个节点包含三个基本部分:数据域(存储节点的数据)、前驱指针和后继指针。头节点和尾节点是特殊的节点,它们分别代表双向链表的起始和结束。

特点

  1. 双向连接:每个节点都有两个指针,一个指向前驱节点,一个指向后继节点。这种双向连接的结构使得在链表中的节点之间可以进行双向遍历。

  2. 首尾节点:双向链表通常有头节点和尾节点,它们分别代表链表的起始和结束。头节点的前驱指针为空,尾节点的后继指针为空。

  3. 插入和删除的灵活性:相较于单向链表,双向链表可以更方便地在任意位置插入和删除节点。通过调整前驱和后继指针的指向,可以高效地完成这些操作,而无需遍历整个链表。

  4. 前向和后向遍历:由于每个节点都有前驱和后继指针,双向链表可以从头节点或尾节点开始,沿着不同的方向遍历整个链表。这种灵活性在某些情况下能提高效率。

  5. 多占用空间:相对于单向链表,双向链表需要额外存储每个节点的前驱指针,因此会占用更多的内存空间。

  6. 维护复杂性:因为每个节点有两个指针,所以在插入、删除或修改节点时,需要同时更新相关节点的前驱和后继指针,这增加了链表的维护复杂性。

实现

数据结构:

节点:

  1. template<typename T>
  2. class Node {
  3. public:
  4. T val; // 数据域
  5. Node *pre; // 前驱节点指针
  6. Node *next; // 后继节点指针
  7. ~Node() {
  8. }
  9. };

 链表属性:

  1. private:
  2. Node<T> *head; // 头指针
  3. Node<T> *tail; // 尾指针
  4. int siz = 0; // 元素个数

 头尾指针使用同一个节点 ,不保存数据

结构图

实现功能

      1、void add(T t);  // 从尾部添加元素

      2、void add(int index, T t); //在索引index处添加元素t

      3、add_first(T t);  // 从头部添加元素

      4、bool contains(T t) const // 判断元素t是否在list中

      5、T get(int index); // 获取指定位置的元素

      6、T get_first() ;//获取第一个元素

      7、T get_last(); // 获取最后一个元素

      8、int index_of(T t); 获取指定位置的索引

      9、 void clear();清空list

C++代码

头文件
  1. /**
  2. * 双向链表实现list
  3. */
  4. #include <iostream>
  5. #include <bits/functexcept.h>
  6. #ifndef LIST_LINK_LIST_H
  7. #define LIST_LINK_LIST_H
  8. template<typename T>
  9. class Node {
  10. public:
  11. T val;
  12. Node *pre;
  13. Node *next;
  14. ~Node() {
  15. }
  16. };
  17. template<typename T>
  18. class LinkList {
  19. public:
  20. // 从尾部添加元素
  21. void add(T t);
  22. // 在索引index处添加元素t
  23. void add(int index, T t);
  24. // 从头部添加元素
  25. void add_first(T t);
  26. // 清空list
  27. void clear() {
  28. Node<T> *t_h = head->next;
  29. while (t_h != tail) {
  30. Node<T> * t = t_h;
  31. t_h = t_h->next;
  32. delete t;
  33. }
  34. siz = 0;
  35. head->pre = tail->next = nullptr;
  36. };
  37. // 判断元素t是否在list中
  38. bool contains(T t) const {
  39. Node<T> *t_h = head->next;
  40. while (t_h != tail) {
  41. if (t_h->val == t) return true;
  42. t_h = t_h->next;
  43. }
  44. return false;
  45. };
  46. T get(int index) {
  47. if (index < 0 || index > siz - 1) {
  48. std::__throw_out_of_range_fmt("LinkList<T>::get(int index) index out of range");
  49. }
  50. Node<T> *ind_node;
  51. if (index < (siz >> 1)) {
  52. ind_node = head->next;
  53. for (int i = 0; i < index; i++) {
  54. ind_node = ind_node->next;
  55. }
  56. } else {
  57. ind_node = tail->pre;
  58. for (int i = siz - 1; i > index; i--) {
  59. ind_node = ind_node->pre;
  60. }
  61. }
  62. return ind_node->val;
  63. };
  64. T get_first() const { return head->next->val; }
  65. T get_last() const { return tail->pre->val; }
  66. int index_of(T t);
  67. int size() const { return siz; }
  68. // 打印
  69. void print() {
  70. if(!siz) return;
  71. Node<T> *t = head->next;
  72. while (t != tail) {
  73. std::cout << t->val << " ";
  74. t = t->next;
  75. }
  76. std::cout << std::endl;
  77. }
  78. LinkList() {
  79. head = tail = new Node<T>();
  80. head->pre = tail->next = nullptr;
  81. }
  82. ~LinkList() {
  83. Node<T> *t_h = head;
  84. while (t_h != tail) {
  85. t_h = t_h->next;
  86. Node<T> *t = t_h;
  87. delete t;
  88. }
  89. }
  90. private:
  91. Node<T> *head; // 头指针
  92. Node<T> *tail; // 尾指针
  93. int siz = 0; // 元素个数
  94. };
  95. #endif //LIST_LINK_LIST_H
其他实现
末尾添加元素
  1. template<typename T>
  2. void LinkList<T>::add(T t) {
  3. Node<T> *node = new Node<T>();
  4. node->val = t;
  5. if (!siz) {
  6. head->next = node;
  7. tail->pre = node;
  8. node->next = tail;
  9. node->pre = head;
  10. } else {
  11. tail->pre->next = node;
  12. node->pre = tail->pre;
  13. tail->pre = node;
  14. node->next = tail;
  15. }
  16. siz++;
  17. }
指定位置添加元素
  1. template<typename T>
  2. void LinkList<T>::add(int index, T t) {
  3. Node<T> *node = new Node<T>();
  4. node->val = t;
  5. Node<T> *ind_node;
  6. if (index < 0) {
  7. add_first(t);
  8. } else if (index >= siz) {
  9. add(t);
  10. } else {
  11. if (index < (siz >> 1)) {
  12. ind_node = head->next;
  13. for (int i = 0; i < index; i++) {
  14. ind_node = ind_node->next;
  15. }
  16. } else {
  17. ind_node = tail->next;
  18. for (int i = siz - 1; i > index; i--) {
  19. ind_node = ind_node->pre;
  20. }
  21. }
  22. }
  23. node->pre = ind_node->pre;
  24. ind_node->pre->next = node;
  25. ind_node->pre = node;
  26. node->next = ind_node;
  27. siz++;
  28. }
头部添加元素
  1. template<typename T>
  2. void LinkList<T>::add_first(T t) {
  3. Node<T> *node = new Node<T>();
  4. node->val = t;
  5. if (!siz) {
  6. head->next = node;
  7. tail->pre = node;
  8. node->pre = head;
  9. node->next = tail;
  10. } else {
  11. head->next->pre = node;
  12. node->next = head->next;
  13. node->pre = head;
  14. head->next = node;
  15. }
  16. siz++;
  17. }
获取指定位置的元素
  1. template<typename T>
  2. int LinkList<T>::index_of(T t) {
  3. int i = 0;
  4. Node<T> *t_h = head->next;
  5. for (i; i < siz; i++) {
  6. if (t_h->val == t) return i;
  7. t_h = t_h->next;
  8. }
  9. return -1;
  10. }
运行测试
  1. #include "link_list.h"
  2. int main() {
  3. LinkList<int> linkList = LinkList<int>();
  4. linkList.add_first(1);
  5. linkList.add(2);
  6. linkList.add_first(0);
  7. linkList.add(0,10);
  8. linkList.print();
  9. std::cout << linkList.index_of(1) << std::endl;
  10. std::cout<< linkList.get(2)<<std::endl;
  11. std::cout << linkList.contains(2) << std::endl;
  12. linkList.clear();
  13. std::cout << "----------" << std::endl;
  14. linkList.print();
  15. linkList.add(1);
  16. linkList.add(2);
  17. linkList.add(3);
  18. linkList.print();
  19. }
运行结果
  1. 10 0 1 2
  2. 2
  3. 1
  4. 1
  5. ----------
  6. 1 2 3

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/516247
推荐阅读
相关标签
  

闽ICP备14008679号