当前位置:   article > 正文

数组模拟实现链表(C++)

数组模拟实现链表(C++)

目录

前言

一、数组模拟单链表

二、数组模拟双链表

三、对比

总结


前言

 本章介绍怎么使用数组模拟链表,首先得理解其定义

链表是指由一系列储存在非连续储存空间 结点组成的储存结构。每个结点由两部分组成:一是储存元素的数据域,一是储存下一个节点地址的指针域。用数组模拟链表得十分清晰明了地理解这一定义。

为什么要用数组模拟实现呢?数组实现的双链表本质上是静态链表,但是具有实现简单,速度极快等特点,比数据结构书上声明新的数据类型的方法代码简洁,好记忆。

数组是一种线性结构,存储空间是内存连续的,每当创建一个数组时,就必须先申请好一段指定大小的空间。由于内存连续这一特性,数组的访问特别快,知道下标索引后,就可以通过地址偏移计算得到指定位置的地址,进而能够直接访问到那个地址空间的数据。数组要保证内存连续这一特性,数组在进行任意位置的插入和删除元素时,就会涉及到部分元素的移动,即插入第i个位置时,需要把i+1位置及其后面的所有元素都往后移动一位,然后执行插入;或者删除第i个位置时,在删除后,需要把第i+1位置及其后面的所有元素都往前移动一位,这样才能保证数据的内存连续。

一、数组模拟单链表

数组可以模拟实现单链表和双链表,我们先来介绍单链表。

代码如下

  1. int head, e[N], ne[N], idx;
  2. // head存储链表头,e[]存储节点的值,ne[]存储节点的next指针,idx表示当前用到了哪个节点
  3. void init()//初始化
  4. {
  5. head = -1;idx = 0;
  6. }
  7. void insert(int a)// 在链表头插入一个数a
  8. {
  9. e[idx] = a,ne[idx] = head, head = idx ++ ;
  10. }
  11. void remove(int k)// 将k位置删掉
  12. {
  13. ne[k]=ne[ne[k]];
  14. }
  15. for (int i = head; i != -1; i = ne[i]) cout << e[i] << ' ';//输出链表元素

图解代码:

 

二、数组模拟双链表

代码如下:

  1. // e[]表示节点的值,l[]表示节点的左指针,r[]表示节点的右指针,idx表示当前用到了哪个节点
  2. int e[N], l[N], r[N], idx;
  3. void init()//初始化0是左端点,1是右端点
  4. {
  5. r[0] = 1, l[1] = 0;
  6. idx = 2;
  7. }
  8. void insert(int a, int x)// 在节点a的右边插入一个数x
  9. {
  10. e[idx] = x;
  11. l[idx] = a, r[idx] = r[a];
  12. l[r[a]] = idx, r[a] = idx ++ ;
  13. }
  14. void remove(int a)// 删除节点a
  15. {
  16. l[r[a]] = l[a];
  17. r[l[a]] = r[a];
  18. }
  19. insert(0,x);//插到头节点后;头节点下标是0
  20. insert(l[1],x);//插入到队尾,尾节点下标为1,所以尾节点的左节点下标为l[1]
  21. insert(l[k],x);//插入到k节点左边,k节点的左下标为了l[k]
  22. for (int i = r[0]; i != 1; i = r[i])cout << e[i] << ' ';//输出链表元素

图解代码

 

 三、对比

如果不用数组实现链表,代码的长度会很长,但是也有它的优点,好理解。

单链表代码如下

  1. #define ERROR 0
  2. #define OK 1
  3. typedef int Status;
  4. typedef int ElemType;
  5. struct Node{
  6. ElemType data;
  7. struct Node * next;
  8. };
  9. typedef struct Node *LinkList;
  10. void InitList(LinkList *L){
  11. *L = (LinkList)malloc(sizeof(Node));
  12. (*L)->next = NULL;
  13. }
  14. bool ListEmpty(LinkList L){
  15. if(L->next)
  16. return false;
  17. else
  18. return true;
  19. }
  20. void ClearList(LinkList *L){
  21. LinkList p,q;
  22. p = (*L)->next;
  23. while(p){
  24. q = p->next;
  25. free(p);
  26. p = q;
  27. }
  28. (*L)->next = NULL;
  29. }
  30. int ListLength(LinkList L){
  31. int i = 0;
  32. LinkList p = L->next;
  33. while(p){
  34. i++;
  35. p = p->next;
  36. }
  37. return i;
  38. }
  39. Status GetElem(LinkList L,int i,ElemType *e){
  40. int cnt = 1;
  41. LinkList p = L->next;
  42. while(p && cnt < i){
  43. p = p->next;
  44. cnt++;
  45. }
  46. if(!p)
  47. return ERROR;
  48. *e = p->data;
  49. return OK;
  50. }
  51. int LocateElem(LinkList L,ElemType e){
  52. int cnt = 0;
  53. LinkList p = L->next;
  54. while(p){
  55. cnt++;
  56. if(p->data == e)
  57. return cnt;
  58. p = p->next;
  59. }
  60. return 0;
  61. }
  62. Status ListInsert(LinkList *L,int i,ElemType e){
  63. LinkList p,s;
  64. p = (*L);
  65. int cnt = 1;
  66. while(p && cnt < i){
  67. cnt++;
  68. p = p->next;
  69. }
  70. if(!p)
  71. return ERROR;
  72. s = (LinkList)malloc(sizeof(Node));
  73. s->data = e;
  74. s->next = p->next;
  75. p->next = s;
  76. return OK;
  77. }
  78. Status ListDelete(LinkList *L,int i,ElemType *e){
  79. int cnt = 1;
  80. LinkList q,p;
  81. p = (*L);
  82. //此时 p 为头节点,p->next为第一个节点
  83. while( p->next && cnt < i){
  84. p = p->next;
  85. cnt++;
  86. }
  87. //第一个节点不为空,并且 cnt 小于要删除的节点位置,开始循环
  88. if(!(p->next))
  89. return ERROR;
  90. q = p->next;
  91. p->next = q->next;
  92. *e = q->data;
  93. free(q);
  94. return OK;
  95. }
  96. Status ListTraverse(LinkList L){
  97. LinkList p = L->next;
  98. while(p){
  99. printf("%d ",p->data);
  100. p = p->next;
  101. }
  102. printf("\n");
  103. return OK;
  104. }
  105. void CreateListHead(LinkList *L,int n){
  106. LinkList p;
  107. srand(time(0));
  108. *L = (LinkList)malloc(sizeof(Node));
  109. (*L)->next = NULL;
  110. for(int i = 0 ; i < n ; i++){
  111. p = (LinkList)malloc(sizeof(Node));
  112. p->data = rand()%100 + 1;
  113. p->next = (*L)->next;
  114. (*L)->next = p;
  115. }
  116. }
  117. void CreateListTail(LinkList *L,int n){
  118. LinkList p,r;
  119. srand(time(0));
  120. *L = (LinkList)malloc(sizeof(Node));
  121. r = *L;
  122. for(int i = 0 ; i < n ; i++){
  123. p = (LinkList)malloc(sizeof(Node));
  124. p->data = rand()%100 + 1;
  125. r->next = p;
  126. r = p;
  127. }
  128. r->next = NULL;
  129. }

 对比发现代码长了非常多。这里只对比了单链表,如果有兴趣可以看看自行对比一下双链表

相较于数组模拟,数组更好写,更好记忆,如果参加一些比赛的话我更加推荐使用数组模拟的链表,另外C++ STL里的list,也是可以的。代码如下

  1. #include <list>
  2. list<int> a;

总结

数组模拟链表经常作为算法的模板使用,要学会这个得了解基础链表的基本概念和实现方式,并且多写多用。如果不是很好理解的话可以尝试跟着代码画一遍图,就可以很好的理解了。

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

闽ICP备14008679号