当前位置:   article > 正文

单、双向链表(c++)插入和删除的秘密_双向链表和单向链表的插入和删除

双向链表和单向链表的插入和删除

一、文章概述

        本人在学习线性表时,发现单链表与双向链表的插入、删除操作的算法实现有较大差别,并且自己用的课本并未详细给出双向链表的插入和删除的算法实现,于是自己就动手实现了这两个操作,下面我将分享自己在学习中总结的单链表与双链表插入删除算法的区别,并给出算法实现。但由于本人学识浅陋、见闻不广,文中难免会出现错误或不足之处,恳请读者批评指正。

二、区别

(一)操作时获取的指针不同

为了方便下面的讲解,先把两种链表的结构划出,如下图:

头结点:链表中的第一个节点

首元结点:链表中的第一个元素节点

(1)单链表获取的指针

        单链表无论是插入还是删除,我们都需要找到待插入位置或删除位置的前一个位置,比如我们如果要将一个元素插入到第i个元素位置,那么我们就要找到第i-1个元素的指针即可,要删除第i个结点,我们也需要找到第i-1个结点的指针。

举例:

        (1)如下图,我们要将数据域为10的S结点插入到第2个元素位置,那么我们要找第1个元素的指针P,然后执行图中的两步操作

        

(2)如下图,我们要删除第2个元素,我们也要先找到第1个元素的指针p,然后再进行下面的操作。

(2)双向链表获取的指针

        与单链表不同的是,我们如果要将元素插入到第i个位置,或删除第i个位置,我们都需要找到第i个元素的指针,而不是第i-1个元素的指针。

举例

        (1)如下图,我们要将数据域为10的S结点插入到第2个元素位置,那么我们要找到第2个元素的指针P,然后执行图中的四步操作

        ​​​​​​​

        (2)如下图,我们要删除第2个元素,我们也要先找到第2个元素的指针p,然后再进行下面的操作。

(二)考虑的情况不同

(1)单链表所考虑的情况

        由下面的代码可知,单链表的插入和删除较为简单,我们没有特殊的需要情况考虑,而下面要讲的双向链表有特殊情况需要考虑。

  1. //双向链表的存储结构
  2. typedef struct LNode {
  3. int data;
  4. struct LNode* next;
  5. }LNode, *LinkList;
  6. //在链表第i个位置插入结点
  7. void listInsert(LinkList L, int i, int data) {
  8. LinkList p = L;
  9. int j = 0;
  10. //找到待插入位置的前一结点的指针
  11. while (p && j < i - 1) {
  12. p = p->next;
  13. j++;
  14. }
  15. if (!p || j > i - 1) {
  16. printf("i为不合法的插入位置");
  17. return;
  18. }
  19. //创建待插入节点s
  20. LNode* s = new LNode;
  21. s->data = data;
  22. s->next = NULL;
  23. //将结点插入
  24. s->next = p->next;
  25. p->next = s;
  26. }
  27. //删除链表L第i个位置的元素
  28. void listDelete(LinkList L, int i) {
  29. int j = 0;
  30. LNode* p = L;
  31. //找到待删除结点的前一结点的指针
  32. while (p->next && j < i - 1) {
  33. p = p->next;
  34. j++;
  35. }
  36. if (!(p->next) || j > i - 1) {
  37. printf("i为不合法的删除位置");
  38. return;
  39. }
  40. LNode* s = p->next;
  41. p->next = p->next->next;
  42. delete s;
  43. }

 (2)双向链表所考虑的情况

插入时:

        (1)插入位置=0,的情况需要单独考虑,提示"i为不合法的插入位置",仍然按照单链表中的逻辑:if(!p&&j>i){},不可以检测出插入位置=0的不合法情况。

        (2)我们需要单独考虑 插入位置 = 元素个数+1的情况,否则的话根据下面的代码,可知会直接显示“i为不合法的插入位置”。

删除时:

        (1)同插入时的情况(1),删除时也需要单独考虑插入位置=0的情况,否则会出现同样的情况。

        (2)我们需要考虑删除尾结点的情况,如果不单独考虑的话,会出现“null->next-prior”的情况,就会报错。

  1. //双向链表的存储结构
  2. typedef struct DuLNode {
  3. int data;
  4. struct DuLNode* prior;
  5. struct DuLNode* next;
  6. }DuLNode, *DuLinkList;
  7. //在第i个元素位置插入结点,结点数据域为data
  8. void listInsert_Du(DuLinkList L, int i, int data) {
  9. DuLinkList p = L;
  10. if (i == getLength( L) + 1) {//插入的位置为链表的尾部(尾结点后)
  11. for (int i = 0; i < getLength(L); i++) {//获取链表尾结点的指针
  12. p = p->next;
  13. }
  14. DuLNode* s = new DuLNode;
  15. s->data = data;
  16. p->next = s;
  17. s->prior = p;
  18. s->next = NULL;
  19. }
  20. else {
  21. int j = 0;
  22. while (p && j < i) {//将指针p指向待插入位置的节点
  23. p = p->next;
  24. j++;
  25. }
  26. if (!p || j > i || i== 0) {
  27. cout << "i为不合法的插入位置"<<endl;
  28. return;
  29. }
  30. DuLNode* s = new DuLNode;
  31. s->data = data;
  32. p->prior->next = s;
  33. s->prior = p->prior;
  34. p->prior = s;
  35. s->next = p;
  36. }
  37. }
  38. //删除链表中第i个元素
  39. void listDelete(DuLinkList L, int i) {
  40. DuLNode* p = L;
  41. int j = 0;
  42. while (p && j < i) {//获取待删除结点的指针
  43. p = p->next;
  44. j++;
  45. }
  46. if (!p || j > i || i == 0) {
  47. cout << "i为不合法的位置"<<endl;
  48. return;
  49. }
  50. if (j == getLength(L)) {//待删除的结点为尾结点
  51. p->prior->next = NULL;
  52. delete p;
  53. return;
  54. }
  55. p->prior->next = p->next;
  56. p->next->prior = p->prior;
  57. delete p;
  58. }

三、全部代码

下面是我在实验时写的整体代码,读者可以在本地查看执行效果:

双向链表:

  1. #include<iostream>
  2. using namespace std;
  3. //双向链表的存储结构
  4. typedef struct DuLNode {
  5. int data;
  6. struct DuLNode* prior;
  7. struct DuLNode* next;
  8. }DuLNode, *DuLinkList;
  9. void createList_Du(DuLinkList& L, int n);
  10. void printList(DuLinkList L);
  11. void listInsert_Du(DuLinkList L, int i, int data);
  12. void listDelete(DuLinkList L, int i);
  13. int getLength(DuLinkList L);
  14. int main() {
  15. DuLinkList L = NULL;
  16. int length = 0;
  17. cout << "请输入链表长度:";
  18. cin >> length;
  19. createList_Du(L, length);//创建一个长度为length的双向链表
  20. printList(L);//打印链表
  21. int i, data;
  22. cout << "请输入待插入位置、及数据:"<<endl;
  23. cin >> i>>data;
  24. listInsert_Du(L, i, data);//在链表第i个位置插入结点,结点数据为data
  25. printList(L);
  26. cout << "请输入待删除结点的位置:"<<endl;
  27. cin >> i;
  28. listDelete(L, i);//删除链表中第i个结点
  29. printList(L);
  30. return 0;
  31. }
  32. //创建含有n个元素的双向连表
  33. void createList_Du(DuLinkList &L, int n) {
  34. L = new DuLNode;//创建头结点
  35. L->next = NULL;
  36. L->prior = NULL;
  37. DuLNode* r = L;//指针r指向链表的尾结点
  38. cout << "请输入链表元素:";
  39. //尾插法创建长度为n的链表
  40. for (int i = 0; i < n; i++) {
  41. int data;
  42. cin >> data;
  43. DuLNode* p = new DuLNode;
  44. p->data = data;
  45. r->next = p;
  46. p->prior = r;
  47. p->next = NULL;
  48. r = p;
  49. }
  50. }
  51. //在第i个元素位置插入结点,结点数据域为data
  52. void listInsert_Du(DuLinkList L, int i, int data) {
  53. DuLinkList p = L;
  54. if (i == getLength( L) + 1) {//插入的位置为链表的尾部(尾结点后)
  55. for (int i = 0; i < getLength(L); i++) {//获取链表尾结点的指针
  56. p = p->next;
  57. }
  58. DuLNode* s = new DuLNode;
  59. s->data = data;
  60. p->next = s;
  61. s->prior = p;
  62. s->next = NULL;
  63. }
  64. else {
  65. int j = 0;
  66. while (p && j < i) {//将指针p指向待插入位置的节点
  67. p = p->next;
  68. j++;
  69. }
  70. if (!p || j > i || i== 0) {
  71. cout << "i为不合法的插入位置"<<endl;
  72. return;
  73. }
  74. DuLNode* s = new DuLNode;
  75. s->data = data;
  76. p->prior->next = s;
  77. s->prior = p->prior;
  78. p->prior = s;
  79. s->next = p;
  80. }
  81. }
  82. //删除链表中第i个元素
  83. void listDelete(DuLinkList L, int i) {
  84. DuLNode* p = L;
  85. int j = 0;
  86. while (p && j < i) {//获取待删除结点的指针
  87. p = p->next;
  88. j++;
  89. }
  90. if (!p || j > i || i == 0) {
  91. cout << "i为不合法的位置"<<endl;
  92. return;
  93. }
  94. if (j == getLength(L)) {//待删除的结点为尾结点
  95. p->prior->next = NULL;
  96. delete p;
  97. return;
  98. }
  99. p->prior->next = p->next;
  100. p->next->prior = p->prior;
  101. delete p;
  102. }
  103. //打印链表
  104. void printList(DuLinkList L) {
  105. DuLNode* p = L->next;
  106. cout << "形成的链表:";
  107. while (p) {
  108. cout << p->data << " ";
  109. p = p->next;
  110. }
  111. cout << endl;
  112. }
  113. //得到链表长度
  114. int getLength(DuLinkList L) {
  115. DuLNode* p = L->next;
  116. int length = 0;
  117. while (p) {
  118. p = p->next;
  119. length++;
  120. }
  121. return length;
  122. }

单链表:

  1. #include <iostream>
  2. using namespace std;
  3. //单链表的存储结构
  4. typedef struct LNode {
  5. int data;
  6. struct LNode* next;
  7. }LNode, *LinkList;
  8. void createList(LinkList &L, int n);
  9. void listInsert(LinkList L, int i, int data);
  10. void printList(LinkList L);
  11. void listDelete(LinkList L, int i);
  12. int main() {
  13. LinkList L = NULL;
  14. int length = 0;
  15. cout << "请输入链表长度:";
  16. cin >> length;
  17. createList(L, length);//创建一个长度为length的双向链表
  18. printList(L);//打印链表
  19. int i, data;
  20. cout << "请输入待插入位置、及数据:" << endl;
  21. cin >> i >> data;
  22. listInsert(L, i, data);//在链表第i个位置插入节点,结点数据为data
  23. printList(L);
  24. cout << "请输入待删除结点的位置:" << endl;
  25. cin >> i;
  26. listDelete(L, i);//删除链表中第i个结点
  27. printList(L);
  28. return 0;
  29. }
  30. //尾插法创建一个长度为n的链表
  31. void createList(LinkList &L, int n) {
  32. L = new LNode;
  33. L->next = NULL;//创建头结点
  34. LNode* r = L;//指针r指向尾结点
  35. cout << "请输入链表元素:";
  36. for (int i = 0; i < n; i++) {
  37. int data;
  38. cin >> data;
  39. LNode* p = new LNode;
  40. p->data = data;
  41. r->next = p;
  42. p->next = NULL;
  43. r = p;
  44. }
  45. }
  46. //在带头结点的链表第i个位置插入结点
  47. void listInsert(LinkList L, int i, int data) {
  48. LinkList p = L;
  49. int j = 0;
  50. //找到待插入位置的前一结点的指针
  51. while (p && j < i - 1) {
  52. p = p->next;
  53. j++;
  54. }
  55. if (!p || j > i - 1) {
  56. printf("i为不合法的插入位置");
  57. return;
  58. }
  59. //创建待插入节点s
  60. LNode* s = new LNode;
  61. s->data = data;
  62. s->next = NULL;
  63. //将s结点插入
  64. s->next = p->next;
  65. p->next = s;
  66. }
  67. //删除链表L第i个位置的元素
  68. void listDelete(LinkList L, int i) {
  69. int j = 0;
  70. LNode* p = L;
  71. //找到待删除位置的前一结点的指针
  72. while (p->next && j < i - 1) {
  73. p = p->next;
  74. j++;
  75. }
  76. if (!(p->next) || j > i - 1) {
  77. printf("i为不合法的删除位置");
  78. return;
  79. }
  80. LNode* s = p->next;
  81. p->next = p->next->next;
  82. delete s;
  83. }
  84. //打印链表
  85. void printList(LinkList L) {
  86. LNode* p = L->next;
  87. cout << "形成的链表:";
  88. while (p) {
  89. cout << p->data << " ";
  90. p = p->next;
  91. }
  92. cout << endl;
  93. }

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

闽ICP备14008679号