当前位置:   article > 正文

【数据结构】链表 详解_空链表和空

空链表和空

我们不废话,直入正题。

引入

什么是链表?

来看看百度怎么说:

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。

可以发现:

每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域

链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。

这些,就是链表的特性。

这就是链表的概念图。Blue、Yellow、Red 这 3 个字符串作为数据被存储于链表的数据域中。每个数据都有 1 个 “指针”,它指向下一个数据的内存地址,这被称为指针域


了解完概念,我们就要来看看基本操作了。

一.创建

上面看到:

每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

一个结点,可用一个结构体存储(此处表示为Lnode)。

数据域就很简单,我们通常用再搞一个结构体来存储。

而指针呢?

在链表的创建中,我们需要添加一个指向下一个节点的指针,这个指针保存的是下一个节点的地址

那么指针的类型是什么呢?当然是Lnode了,因为指针指向的,是下一个结点。

下面引入一段话来帮助理解:

将某个变量赋值给指针,实际上就是将这个变量的地址赋值给指针,或者反过来说,指针中存储了这个变量的内存地址,指向了这个变量,通过指针就能找到这个变量。

那么,就可以实现了。

  1. struct Lnode{
  2. ElemType data;//数据域
  3. struct Node *next;//指针域
  4. };

二.初始化

说是初始化,实际上是在创建结点。那么,只需开辟一个类型为Lnode的空间即可。

如何开辟空间?

我们需要一个new

new是什么?

new其实就是计算机开辟一段新的空间,但是和一般的声明不同的是,new开辟的空间在堆上,而一般声明的变量存放在栈上。通常来说,当在局部函数中new出一段新的空间,该段空间在局部函数调用结束后仍然能够使用,可以用来向主函数传递参数。另外需要注意的是,new的使用格式,new出来的是一段空间的首地址。所以一般需要用指针来存放这段地址。
————————————————
版权声明:本内容为CSDN博主「柒笙歌」的原创
原文链接: C++之new的详解_new c++_柒笙歌的博客-CSDN博客

算了,不乱说了,自己搜搜看吧!然后,接着来。

真正的初始化

不过,这个结点后面还没有其它的结点,因此其指针域的指向应该是空的。

这里,我们用NULL表示。

NULL是什么?

Null是在计算中具有保留的值,用于指示 指针不引用有效对象。

这句话很显然的点明了。

在C++中,NULL可以直接赋值给指针。因此就很简单了!

代码实现

  1. void InitList(Lnode* &L)//初始化
  2. {
  3. L=new Lnode;
  4. L->next=NULL;
  5. }

三.判断是否为空链表

首先,我们要知道,什么是空链表?

空链表:链表中无元素。(头指针和头结点仍在)

也就是说,头结点的指针域的指向为空

那么,就非常简单了。

  1. bool check(Lnode* L)//判断是否为空
  2. {
  3. if(L->next==NULL) return 0;//空
  4. return 1;
  5. }

四.清空链表(不留头结点)

用一个L表示当前头结点,用p表示当前节点。

每次就将p转到L的下一个,然后释放L,在将L变为p。以此不断循环,直到p为空。

代码如下:

  1. void xiaohui(linklist &L)//全部删掉 (不留头结点)
  2. {
  3. Lnode *p;//linklist L
  4. while(p)
  5. {
  6. L=p;
  7. p=p->next;
  8. free(L);
  9. }
  10. }

五.变成空表(留头结点)

这与上面的只有一个区别。题目写得很清楚:留头结点

那么我们只用q替代L,帮p探路。那么,在p为NULL时,我们还可知道原来的头结点的指针——就是L

好,上代码:

  1. void qk(linklist &L)//变成空表(留头结点)
  2. {
  3. Lnode *p,*q;//linklist L
  4. q=L->next;
  5. while(p)
  6. {
  7. p=q;
  8. q=q->next;
  9. free(p);
  10. }
  11. L->next=NULL;
  12. }

五.查找、访问

相对于数组,链表的数据是分散储存于数组的随机位置的。

因为数据都是分散存储的,所以如果想要访问 数据,只能从第1个数据开始,顺着指针的指 向一一往下访问(这便是顺序访问)。比如,想 要找到Red这一数据,就得从Blue开始访问。

这之后,还要经过 Yellow,我们才能找到 Red。

也比较基础,上代码!

  1. int cz(linklist L,char mz[])//查找
  2. {
  3. Lnode *p=L->next;
  4. while(p)
  5. {
  6. if(strcmp(mz,p->data.name)==0) break;
  7. p=p->next;
  8. }
  9. if(!p)
  10. {
  11. return 0;
  12. }
  13. return 1;
  14. }


六.添加

如果想要添加数据,只需要改变添加位置前后 的指针指向就可以,非常简单。比如,在Blue 和Yellow之间添加Green。

将 Blue 的指针指向的位置变成 Green,然后再 把Green的指针指向Yellow,数据的添加就大功告成了。

代码如下:

  1. int cr(linklist &L,int x,ElemType e)//插入
  2. {
  3. int i=0;
  4. Lnode *p=L;
  5. while(p&&i<x-1)
  6. {
  7. p=p->next;
  8. i++;
  9. }
  10. Lnode *s=new Lnode;
  11. s->data=e;
  12. s->next=p->next;
  13. p->next=s;
  14. return 1;
  15. }

七.删除

数据的删除也一样,只要改变指针的指向就可 以,比如删除Yellow。

这时,只需要把 Green 指针指向的位置从 Yellow 变成 Red,删除就完成了。但是, Yellow 本身还存储在 内存中,需要把它释放掉(可以用free数组)

看代码:

  1. int cr(linklist &L,int x,ElemType &e)//删除第x个节点,并返回删除值
  2. {
  3. int i=1;
  4. Lnode *p=L->next,*t;
  5. while(p&&i<x-1)
  6. {
  7. p=p->next;
  8. i++;
  9. }
  10. t=p->next;
  11. p->next=p->next->next;
  12. free(t);
  13. return 1;
  14. }

基本操作汇总

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef struct student{
  4. char name[8];
  5. int num;
  6. int cj;
  7. }ElemType;
  8. typedef struct Lnode{
  9. ElemType data;
  10. struct Lnode *next;
  11. }Lnode,*linklist;
  12. void InitList(linklist &L)//初始化
  13. {
  14. L=new Lnode;
  15. L->next=NULL;
  16. }
  17. bool check(linklist L)//判断是否为空
  18. {
  19. if(L->next==NULL) return 0;//空
  20. return 1;
  21. }
  22. void xiaohui(linklist &L)//全部删掉
  23. {
  24. Lnode *p;//linklist L
  25. while(p)
  26. {
  27. L=p;
  28. p=p->next;
  29. free(L);
  30. }
  31. }
  32. void qk(linklist &L)//变成空表(留头结点)
  33. {
  34. Lnode *p,*q;//linklist L
  35. q=L->next;
  36. while(p)
  37. {
  38. p=q;
  39. q=q->next;
  40. free(p);
  41. }
  42. L->next=NULL;
  43. }
  44. int bc(linklist &L)//链表的长度
  45. {
  46. int s=0;
  47. Lnode *p;
  48. p=L->next;
  49. while(p)
  50. {
  51. s++;
  52. p=p->next;
  53. }
  54. return s;
  55. }
  56. int qz(linklist &L,int x,ElemType &a)//取第x个的值
  57. {
  58. int i=1;
  59. Lnode *p=L->next;
  60. while(p&&i<x)
  61. {
  62. p=p->next;
  63. i++;
  64. }
  65. if(!p)
  66. {
  67. return 0;
  68. }
  69. a=p->data;
  70. return 1;
  71. }
  72. int cz(linklist L,char mz[])//查找
  73. {
  74. Lnode *p=L->next;
  75. while(p)
  76. {
  77. if(strcmp(mz,p->data.name)==0) break;
  78. p=p->next;
  79. }
  80. if(!p)
  81. {
  82. return 0;
  83. }
  84. return 1;
  85. }
  86. int cr(linklist &L,int x,ElemType e)//插入
  87. {
  88. int i=0;
  89. Lnode *p=L;
  90. while(p&&i<x-1)
  91. {
  92. p=p->next;
  93. i++;
  94. }
  95. Lnode *s=new Lnode;
  96. s->data=e;
  97. s->next=p->next;
  98. p->next=s;
  99. return 1;
  100. }
  101. int cr(linklist &L,int x,ElemType &e)//删除第x个节点,并返回删除值
  102. {
  103. int i=1;
  104. Lnode *p=L->next,*t;
  105. while(p&&i<x-1)
  106. {
  107. p=p->next;
  108. i++;
  109. }
  110. t=p->next;
  111. p->next=p->next->next;
  112. free(t);
  113. return 1;
  114. }
  115. int tc(int n,linklist &L)//建立头插法
  116. {
  117. Lnode *p;
  118. for(int i=1;i<=n;i++)
  119. {
  120. p=new Lnode;
  121. //cin>>p->data;
  122. p->next=L->next;
  123. L->next=p;
  124. }
  125. }
  126. int tc(int n,linklist &L)//建立尾插法
  127. {
  128. Lnode *p,*r=L;
  129. for(int i=1;i<=n;i++)
  130. {
  131. p=new Lnode;
  132. p->next=NULL;
  133. //cin>>p->data;
  134. r->next=p;
  135. r=p;
  136. }
  137. }
  138. int main()
  139. {
  140. }

最后

因为太懒了,就拖了很久,今天开网,终于发布了,麻烦来个三连,谢谢!

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

闽ICP备14008679号