当前位置:   article > 正文

双循环链表(C++)_node *tail =&head c++

node *tail =&head c++

    在C++里,存在多种类型的表,其中有一种线性表,链表则是一种线性表,正如它的名字一样,链表的样子就像是用一条链子串起来的表(这里,我主要讲的是双循环链表)

而用来连接链子的每个环节的是指针,在最基本的单向不循环链表中,有一根单向指针next,这根指针的作用显而易见,就是串联上下两个节点。

    说到串联节点,那么必不可少的自然是节点,节点又如何创建呢。首先,我们要创建一个节点类(class Node),在双循环链表中,想要实现双循环,那么就要求要有双向效果,也就是用来指向的指针应该要有两根,一根指向本节点的下一个节点(next),一根指向本节点的上一个节点(prior),以此达到双向的效果

这里,我以一个记录学生信息的双循环链表作为例子

  1. class Node
  2. {
  3. public:
  4. int ID;
  5. string name;
  6. Node * next;
  7. Node * prior;
  8. Node() :next(nullptr), prior(nullptr) {}
  9. Node(int ID, string name) :ID(ID), name(name), next(nullptr), prior(nullptr) {}
  10. Node(Node &n) :ID(n.ID), name(n.name), next(nullptr), prior(nullptr) {}
  11. void display()
  12. {
  13. cout << "ID:" << ID << endl << "Name:" << name << endl;
  14. }
  15. };

 在这个类里面,要有三种构造函数,无参构造主要是为了在链表类里面创建头结点使用,第一类有参构造是为了主函数内创建节点,而第二类构造则是拷贝构造,目的在于拷贝节点信息。

    创建完节点,需要做的便是将节点串联起来。串联节点,首先需要有一个起点,这个起点就是一个标志性作用,在循环链表里面,头结点既是开头也是结尾,起到关键作用

所以,在创建链表的时候,首先应该先有一个Node型的头结点

  1. Link::Link()
  2. {
  3. head = new Node();
  4. head->name = "头结点";
  5. head->next = head;
  6. head->prior = head;
  7. }

 在没有插入任何其他节点的时候,头结点既是头节点的上一节点也是头结点的下一节点,也就是所有指针全部指向自己。当然,这个头结点是private的,不可被外界访问到。有了头节点之后,我们可以开始对这个链表进行各种操作了。

  1. class Link
  2. {
  3. private:
  4. Node * head;
  5. public:
  6. Link();
  7. ~Link();
  8. void traverse1();
  9. void traverse2();
  10. void insert(Node &n);
  11. void deleteByID(int id);
  12. void modifyByID(int id, string name);
  13. };

这里,我只写了顺序遍历、倒序遍历、插入、按ID关键字删除、 按关键字修改信息五个函数。首先,我们先讲插入,没有插入就没有其他节点的存在。双循环链表的插入比较复杂一点,最好可以用纸笔进行模拟,可以促进理解。

    插入,有两种情况,第一种是在除了头结点外为空的链上插入,此时我们要做的是将头节点的next指向要插入的节点(下面称为本节点),将头结点的prior指向本节点,将本节点的prior指向头结点,将本节点的next指向头结点。这样就可以实现头结点与本节点之间的双向循环。至于第二种,就是在链表已经足够长的情况下插入节点,我们这里的插入只是单纯插在尾部,至于其他类型的插入,大致不会差多少,所以谨以此例子作为示范。要插在尾部,我们要先找到尾部在哪里,于是有了一根指针(tail),tail=head,当tail的下一个节点不是头结点的时候,我们就继续找下一个,一直到他指向头结点,此时tail所代表的节点必然就是最后一个节点,new 出一个新的实体,这个实体的所有信息与传入的节点的信息完全一致,也就是进行拷贝,然后使newNode得next指向头结点,将头结点的prior指向newNode,将newNode的prior指向tail(最后一个节点),将最后一个节点的next指向newNode,这样,newNode就成为新的最后一个节点,并且是支持双向循环的。

  1. void Link::insert(Node &n)
  2. {
  3. Node *tail = head;
  4. if (head->next == head)
  5. {
  6. Node *newNode = new Node(n);
  7. head->next = newNode;
  8. head->prior = newNode;
  9. newNode->prior = head;
  10. newNode->next = head;
  11. }
  12. else
  13. {
  14. while (tail->next != head)
  15. {
  16. tail = tail->next;
  17. }
  18. Node *newNode = new Node(n);
  19. newNode->next = head;
  20. head->prior = newNode;
  21. newNode->prior = tail;
  22. tail->next = newNode;
  23. }
  24. }

    然后我们讲遍历,两种遍历的方法基本一致,只是顺序不一样而已,我只讲一种顺序遍历。首先创建一根副指针p,p指向头节点的下一个节点,然后将其输出出来,然后使p=p->next,实现指向再下一个节点,以循环不断做,直到p指向的是头结点才结束,这样就能够全部打印一遍。

  1. void Link::traverse1()
  2. {
  3. Node *p = head->next;
  4. while (p != head)
  5. {
  6. p->display();
  7. p = p->next;
  8. }
  9. cout << endl;
  10. }

    然后是删除,按关键字删除,那么首先要做的就是找到关键字所在地方,建造两根副指针,p,q;p指向头结点的下一个节点,q指向本节点,以p查看每个节点信息,q作为他后面的节点,方便q的修改,当找到关键字后,先修改q的next,使其变成p的next,然后删除p节点,这样p所在位置的节点就被删除了,然后还需要做的是将原来p的next的节点的prior指向q,所以我们让p指向该节点,然后使他的prior指向q.这样就完成删除。(查找过程依然采用遍历查找)

  1. void Link::deleteByID(int id)
  2. {
  3. Node *p = head->next;
  4. Node *q = head;
  5. while (p != head)
  6. {
  7. if (p->ID == id)
  8. {
  9. q->next = p->next;
  10. delete(p);
  11. p = q->next;
  12. p->prior = q;
  13. }
  14. else
  15. {
  16. p = p->next;
  17. q = q->next;
  18. }
  19. }
  20. }

     最后讲的是按关键字修改。当然了,按关键字修改最重要的依然是找到关键字,所以重复同样的方法,创建副指针,循环查找,当找到关键字的时候,将信息修改成传入的信息即可。

  1. void Link::modifyByID(int id, string name)
  2. {
  3. Node *p = head->next;
  4. Node *q = head->prior;
  5. while (p != head)
  6. {
  7. if (p->ID == id)
  8. {
  9. p->name = name;
  10. }
  11. p = p->next;
  12. q = q->prior;
  13. }
  14. }

最后补充说一下,查找的过程中可能遍历了整个链都找不到关键字,此时应该要报错或者有其他处理方法,我这里写的都是认为一定可以找到的,所以没有进行处理,有需要的还是要做一下处理。

     那么双循环链表就讲到这里,如果有不同意见或者见解,又或者觉得我有哪里写错了,欢迎私聊我,大家一起学习一起进步,谢谢啦(QQ:2245440426)

 

完整代码如下

  1. #include<iostream>
  2. #include<string>
  3. using namespace std;
  4. /*######################################*/
  5. /* 学生类双链表 */
  6. /*######################################*/
  7. class Node
  8. {
  9. public:
  10. int ID;
  11. string name;
  12. Node * next;
  13. Node * prior;
  14. Node() :next(nullptr), prior(nullptr) {}
  15. Node(int ID, string name) :ID(ID), name(name), next(nullptr), prior(nullptr) {}
  16. Node(Node &n) :ID(n.ID), name(n.name), next(nullptr), prior(nullptr) {}
  17. void display()
  18. {
  19. cout << "ID:" << ID << endl << "Name:" << name << endl;
  20. }
  21. };
  22. class Link
  23. {
  24. private:
  25. Node * head;
  26. public:
  27. Link();
  28. ~Link();
  29. void traverse1();
  30. void traverse2();
  31. void insert(Node &n);
  32. void deleteByID(int id);
  33. void modifyByID(int id, string name);
  34. };
  35. Link::Link()
  36. {
  37. head = new Node();
  38. head->name = "头结点";
  39. head->next = head;
  40. head->prior = head;
  41. }
  42. Link::~Link()
  43. {
  44. while (head != nullptr)
  45. {
  46. Node *p = head->next;
  47. delete(head);
  48. head = p;
  49. }
  50. }
  51. void Link::traverse1()
  52. {
  53. Node *p = head->next;
  54. while (p != head)
  55. {
  56. p->display();
  57. p = p->next;
  58. }
  59. cout << endl;
  60. }
  61. void Link::traverse2()
  62. {
  63. Node *p = head->prior;
  64. while (p != head)
  65. {
  66. p->display();
  67. p = p->prior;
  68. }
  69. cout << endl;
  70. }
  71. void Link::insert(Node &n)
  72. {
  73. Node *tail = head;
  74. if (head->next == head)
  75. {
  76. Node *newNode = new Node(n);
  77. head->next = newNode;
  78. head->prior = newNode;
  79. newNode->prior = head;
  80. newNode->next = head;
  81. }
  82. else
  83. {
  84. while (tail->next != head)
  85. {
  86. tail = tail->next;
  87. }
  88. Node *newNode = new Node(n);
  89. newNode->next = head;
  90. head->prior = newNode;
  91. newNode->prior = tail;
  92. tail->next = newNode;
  93. }
  94. }
  95. void Link::deleteByID(int id)
  96. {
  97. Node *p = head->next;
  98. Node *q = head;
  99. while (p != head)
  100. {
  101. if (p->ID == id)
  102. {
  103. q->next = p->next;
  104. delete(p);
  105. p = q->next;
  106. p->prior = q;
  107. }
  108. else
  109. {
  110. p = p->next;
  111. q = q->next;
  112. }
  113. }
  114. }
  115. void Link::modifyByID(int id, string name)
  116. {
  117. Node *p = head->next;
  118. Node *q = head->prior;
  119. while (p != head)
  120. {
  121. if (p->ID == id)
  122. {
  123. p->name = name;
  124. }
  125. p = p->next;
  126. q = q->prior;
  127. }
  128. }
  129. int main()
  130. {
  131. Link link;
  132. Node s1(1001, "张三");
  133. Node s2(1002, "李四");
  134. Node s3(2001, "王五");
  135. link.insert(s1);
  136. link.insert(s2);
  137. link.insert(s3);
  138. link.traverse1();
  139. link.traverse2();
  140. link.deleteByID(s2.ID);
  141. link.traverse1();
  142. link.traverse2();
  143. link.modifyByID(s3.ID, "赵六");
  144. link.traverse1();
  145. link.traverse2();
  146. return 0;
  147. }

 

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

闽ICP备14008679号