当前位置:   article > 正文

数据结构(线性结构:单链表)

数据结构(线性结构:单链表)

上一篇博客讲解了数据结构中的线性结构的一个最简单的结构,顺序结构,本篇文章来讲解稍微复杂点的的结构,单链表。

顺序结构类似于一种结构数组,在一个结构中有一个数组,数组中存放数据,因此一个结构可以存放多个元素。而单链表类似于带有指针的结构体。一个结构只存放一个元素,但是结果与结构之间使用指针相连,构成了一个线性的结构。单链表结构如图所示:

 头结点指向表中的第一个结构,一般头结点不存储元素,每个结构中存储一个元素,指针指向下一个后继节点。第一个存储元素的结构成为首结点,最后一个结构成为尾结点,尾结点指针为空。头结点指向首结点,并且单链表一直从头结点开始,一直到最后一个尾结点。

单链表结构定义如下:

  1. #include <stdio.h>
  2. #include <malloc.h>
  3. typedef char elemtype; //定义数据类型;
  4. typedef struct LNode
  5. {
  6. elemtype data; //用来存放数据
  7. struct LNode *next; //指针指向后继节点
  8. }LinkNode;

在单链表的一些基本操作和顺序表相似,有建立,销毁初始化等操作,但是执行起来却大不相同。在单链表中的操作有:

1.建立单链表

建立单链表的基本操作就是插入结点。将一个新的节点插入到单链表中。例如我们要将结点s插入到节点L后面,基本操作为,先让节点s的后继指针指向L后继指针所指的结点,在将L的后继指针指向s。如图所示:

初始时,结点s不在表中

 先将s的后继节点的指针指向L后继节点的指针所指向的结点:如图

 在将L后继节点的指针指向s:如图

 最后结点成功插入:

代码实现如下:

  1. s->next=L->next; //将L的后继节点赋给s;
  2. L->next=s; //将L的后继节点定义为s;

以数组a[n]中的元素为基准建立单链表。其中建立单链表的方式有两种,一种是头插法,另一种是尾插法。头插法是先提取a[i],在建立新节点,从表头开始依次插入结点,而尾插法则是把每个元素都插在表尾。

头插法建立单链表相对简单,直接插在元素头结点后面就可以完成对单链表的建立,代码实现如下:

  1. void CreateListF(LinkNode *&L,elemtype a[],int n)
  2. {
  3. int i=0;
  4. LinkNode *p; //定义新节点p;
  5. L=(LinkNode*)malloc(sizeof(LinkNode)); //将要建立的单链表L置为空,在依次插如元素
  6. L->next=NULL;
  7. while(i<n)
  8. {
  9. p=L=(LinkNode*)malloc(sizeof(LinkNode)); //给p分配存储节点,在将a[i]的值赋给p;
  10. p->data=a[i];
  11. p->next=L->next; //将p插入L中
  12. L->next=p;
  13. }
  14. }

如图,将新的节点插在头结点后面,将其他结点“挤”到后面,依次插入,最后建立完成。

尾插法建立单链表相对较复杂,通过一个结点指向单链表的尾结点,将要插入的结点插在该元素后面,插入一个新元素之后,该结点向后移动一位,重新指向新的尾元素。

代码实现如下:

  1. void CreateListR(LinkNode *&L,int a[],int n)
  2. {
  3. LinkNode *p,*q;
  4. L=(LinkNode*)malloc(sizeof(LinkNode)); //将L置为空,依次插入元素
  5. L->next=NULL
  6. p=L; //指针p指向L;
  7. for(int i=0;i<n;i++)
  8. {
  9. q=(LinkNode*)malloc(sizeof(LinkNode));//给q分配存储空间,将数组的值赋给q的元素值
  10. q->data=a[i];
  11. q->next=p->next; //将q插入p的后面;
  12. p->next=q;
  13. p=q; //p指向尾结点;
  14. }
  15. }

如图,指针p始终指向尾结点,插入元素时直接插在p指向的结点后面,依次插入,建立完成。

2.销毁单链表

该操作相对简单,通过定义两个指针p,pre,pre指向单链表的首结点,p指向首结点的后继节点,先释放掉pre,在将pre指向p的后继节点,将p指向pre的后继节点,在删除pre,依次进行删除释放,最后销毁整个单链表。

代码实现如下:

  1. void DestroyList(LinkNode *&L)
  2. {
  3. LinkNode *pre=L,*p=L->next; //pre指向首结点结点,pre指向首结点的后继节点
  4. while(p!=NULL)
  5. {
  6. free(pre); //销毁首结点
  7. pre=p; //此时新的首结点为p,在将pre指向新的首结点
  8. p=pre->next; //p指向首结点的后继节点
  9. }
  10. free(pre); //删除尾结点,销毁完成
  11. }

如图所示:

3.初始化单链表

初始化线性表指建立一个空的单链表,相当于建立一个头结点为空的单链表。直接将头结点置为空之后就可以完成改操作。代码实现如下

  1. void InitList(LinkNode *&L)
  2. {
  3. L=(LinkNode*)malloc(sizeof(LinkNode));
  4. L->next=NULL; //创建头结点并置为空
  5. }

4.输出单链表

要逐一输出单链表,必须要有一个指针逐一扫描单链表,在将扫描到的元素值依次输出,由于头结点没有不存储元素,因此我们用首结点开始扫描。代码实现如下。

  1. void DispList(LinkNode *L)
  2. {
  3. char e;
  4. LinkNode *p=L->next; //将指针p指向首结点,相当于头结点的后继节点。
  5. while(p!=NULL) //如果p不为空,将该节点则输出。
  6. {
  7. e=p->data;
  8. printf("%c",e);
  9. p=p->next; //输出之后转移到下一个节点
  10. }
  11. printd("\n");
  12. }

5. 求单链表长度

在顺序表中,直接输出顺序表的长度即可。但是在单链表中,没有记录具体的长度,需要通过“数鸭子”一样的方式依次“数”出单链表的长度。同样,先定义一个指针p,让指针p指向首结点,并且记录,在将指针p向后移动,继续记录,直到p为空。代码实现如下:

  1. int ListLength(LinkNode *&L)
  2. {
  3. int i=0; //定义一个基本整形i,将i赋值为0;
  4. LinkNode *p=L->next; //将指针p指向首结点。
  5. while(p!=NULL) //若p不为空,表示有节点,i加上一位
  6. {
  7. i++;
  8. p=p->next; //p向后转移一位。
  9. }
  10. return (i); //最后返回i;
  11. }

6.求单链表中的某个元素值

要求单链表中的某个位置的元素值,首先应该找到改位置,然后在“读取”里面的元素值。例如,若要求出单链表中第i个元素的元素值。应该先用一个指针依次扫描并记录,直到扫描到第i个元素。代码实现如下:

  1. bool GetElem(LinkNode *L,int i,ElemType &e)
  2. {
  3. int j=1; //从第一个元素开始记录,将j定义为1
  4. LinkNode *p=L->next; //p指向首结点
  5. if(i<=0)
  6. return false; //如果i为0,则无法查找,返回错误
  7. while(j<i&&p!=NULL) //向后依次记录元素的个数
  8. {
  9. j++;
  10. p=p->next;
  11. }
  12. if(p==NULL) //若p为空,则单链表没有第i个元素,返回错误。
  13. return false;
  14. else //找到之后将i赋给e,返回为真,查找完成。
  15. {
  16. e=p->data;
  17. return true;
  18. }
  19. }

7.按元素查找

查找单链表中一个与值域相等的元素,同样,需要扫描单链表,如存在,则将该位置返回,不存在则返回0,代码实现如下:

  1. int LocateElem(LinkNode *L,elemtype e)
  2. {
  3. int i=1;
  4. LinkNode *p=L->next; //p指向首结点
  5. while(p!=NULL&&p->data!=e) //如果p值域不为e,i加1,p向后移动一位
  6. {
  7. i++;
  8. p=p->next;
  9. }
  10. if(p==NULL) //若p为空,则单链表中无该元素,返回0
  11. return 0;
  12. else //若p不为空,则将i返回
  13. return i;
  14. }

8.将数据元素插入指定的位置

将数据元素elemtype e插入单链表L的第i个位置,首先在单链表中找到第i-1个结点,然后在插入到该结点的后面,代码实现如下:

  1. bool ListInsert(LinkNode *L,int i,elemtype e)
  2. {
  3. int j=1;
  4. LinkNode *p,*q;
  5. p=L->next;
  6. while(j<i&&p!=NULL) //从头结点开始依次查找第i个元素
  7. {
  8. j++
  9. p=p->next
  10. }
  11. if(p==NULL) //未找到则返回错误
  12. return false;
  13. else //找到之后建立新的节点,再将新的节点插入,操作完成
  14. {
  15. q=(LinkNode*)malloc(sizeof(LinkNode));
  16. q->data=e;
  17. q->next=p->next;
  18. p->next=q;
  19. return true;
  20. }
  21. }

9.删除第i个结点,并将该结点用e返回

该运算实现的过程是找到第i-1个结点,直接将第i-1个结点的指针指向第i的结点的后继节点,在释放第i个结点,运算完成,代码实现如下:

  1. bool ListDelete(LinkNode *&L,int i,elemtype &e)
  2. {
  3. int j=1;
  4. LinkNode *p,q;
  5. p=L->next;
  6. while(j<i-2&&p!=NULL) //找到第i-1个元素。
  7. {
  8. j++;
  9. p=p->next;
  10. }
  11. if(p==NULL) //若没找到,则返回错我
  12. return false;
  13. else
  14. { //找到之后,如下一个元素为空,也返回错我。
  15. q=p->next;
  16. if(q==NULL)
  17. return false;
  18. e=q->data; //若不为空,则将第i个元素的值赋给e。
  19. p->next=q->next; //将第i-1个元素的指针指向第i个元素的后继节点
  20. free(p); //释放第i个元素,返回真
  21. return true;
  22. }
  23. }

单链表的基本操作已经讲解完成,若有不足和错误之处,欢迎大家在评论区指出,谢谢。

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

闽ICP备14008679号