数据结构之线性表——(二、链式存储结构)[c语言]

数据结构之线性表——(二、链式存储结构-单链表)

链式存储结构以及基本运算的实现

背景:由于线性表的存储特点是用物理上的相邻实现逻辑上的相邻,他要求用连续的存储单元顺序存储线性表中的各个元素,所以,对线性表中的元素进行插入、删除时要移动元素,很影响运算的效率。而在链式存储结构中,存储单元的地址可连续,也可不连续,这就意味着这些数据元素可以存放在内存中未被占用的任何位置。它不要求逻辑上相邻的两个数据元素物理上也相邻,其逻辑关系是通过“链”建立起数据元素之间的关系,因此对线性表的插入、删除操作时不需要移动数据,提高了效率。

一、单链表
单链表的表示

链表是通过一组任意的存储单元来存储线性表中的数据元素的,每个数据元素(ai),除了存放自身的数据外,还需要存放其后继ai+1所在的存储单元的地址,这两部分信息组成一个“结点”,存放数据元素信息的数据域为data,存放其后继地址的称为指针域next,所以n个数据元素的线性表通过每个结点的指针域连成一条“链”,故称为链表。其结点的结构如下:
在这里插入图片描述
注:在这里我们称为单链表,单链表是因为其每个结点中只有一个指向后继的指针,所以称为单链表。

1、单链表的定义

单链表是由一个个结点构成的,使用单链表首先要定义一个结点,也可称为结构体,其定义如下:

typedef struct node
{
   
DataType data;
struct node *next;
}Lnode,*LinkList;  
/*Lnode是结构体别名,用其定义结点如:Lnode n;
但是用  *LinkList定义的是指针。 */
定义头指针变量
LinkList H;           //linkList是指向Lnode类型结点的指针类型 

在这里插入图片描述
  在上图中,顺序存储结构的地址是连续的,而且其数据域中的数据也是按照逻辑结构自上而下的。在链式存储结构中,每个结点(node)不仅存储了数据本身(A),还存放了下一个结点的地址(0x5),但头指针中没有存放数据,它存放的是第一个结点(A)的地址。在顺序存储结构里我们将A称为B的直接前驱,B称为A的直接后继,由于是单向链表,在这个链式存储中只有前驱到后继的指针,前驱和后继的关系由指针来链接,也就是说,如果我们要查找后面的元素必须要从头查找。
  作为线性表的一种存储结构,我们关心的是结点之间的逻辑结构,而对每个结点之间的实际地址不感兴趣。
  单链表分为带头和不带头两种
  在这里插入图片描述
在这里插入图片描述
对于线性表来说,有头有尾,链表也同样,我们把链表中第一个结点存储的位置叫做头指针,通常用“头指针”来标识一个单链表。在上图带头结点单链表示意图中,第一个结点的地址放在了指针变量H中,链表的最后一个结点指针为空(NULL)。
在下图中,假设p是指向线性表第i个元素的指针,则结点ai的数据域用p->data来表示,即p->data的值是一个数据元素,p->data = ai;结点ai的指针域用p->next表示,即p->next是一个指针,(p->next)->data = ai+1
在这里插入图片描述

2、单链表的基本操作

(1)初始化创建单链表
在每次将新节点插入到单链表的尾部时,我们需要加入一个指针 r来始终指向单链表中的为节点。
步骤:
1、初始化,头指针H=NULL,尾指针r=NULL
2、线性表中元素的顺序依次读入数据元素,如果不是结束标志,申请结点。
3、将新节点插入到r所指结点的后面,然后r指向新节点。(第一个结点不同)

LinkList Creat_LinkList()
{
    
    LinkList L = NULL;    //头指针L置空
    Lnode *s,*r=NULL;
    char x,flag='0';
    printf("请输入数据,输入0结束\n");
    scanf("%d",&x);
    while(x!=flag)
    {
    
        s = (Lnode *)malloc(sizeof(Lnode));  //申请一个新结点
        s->data = x;      //将输入的x放在结点的数据域中
        if(L==NULL) L = s;    //如果头指针为空,将结点s的指针放在头指针中
        else r->next = s;     //若不为空放在指针r 中
        r = s;               //r始终指向最后一个结点
        printf("请输入数据,输入0结束\n");
        scanf("%c",&x);
     }
     if(r!=NULL)
     r->next = NULL;    //对于非空表,最后结点的指针域放空指针
     return L;
     }

(2)按序号查找结点
1、从链表的第一个数据元素结点起,判断当前结点是否是第i个结点。
2、若是第i个结点,则返回,该结点的指针,否则继续下一个,直至结束为止。
3、若没有第i个结点时返回为空。

//按序号查找结点
Lnode *Get_LinkList(LinkList L,int i)
{
   
     Lnode *p =L;                  //把第一个结点的指针放在p里面
	 int j=1;
	 if(i==1) return p;
     if(p==NULL) {
    printf("表为空");return NULL; }
     while((p->next!=NULL) && j<i)   //判断当前结点是否是第i个结点
     {
     p = p->next; ++j;}
     if(j==i)    return p;         //如果是第i个结点,则返回该节点的指针
     else        return NULL;
 }

(3)单链表的插入
  设p指向单链表中某结点,s指向待插入的值为x的新节点,将结点s插入到结点p的后面,插入的示意图如下:
  在这里插入图片描述

  1. s->next = p->next;
  2. p->next = s; 先挂链再改链,顺序不能交换

1、查找第i-1个结点,如果找到继续,否则结束
2、申请、填装新节点。
3、将新节点插入,结束。

Lnode * Insert_LinkList(LinkList L,int i,char x)
{
   
     Lnode *p,*s;  //定义p s 两个指针
     
     if(i==1)             //如果插入的位置是第一个呢
     {
     s = (Lnode *)malloc(sizeof(Lnode));
        s->data = x;
        s->next = L;    //把老的第一个的地址放进新第一个里面
        L = s;  return L;//把新第一个的地址放在头指针里面
      }
	 
	 p = Get_LinkList(L,i-1);
      if( p==NULL)        //第i个结点前面位置不存在不能插入
      {
       printf("插入位置前面没有元素!\n");
           retur
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值