C语言基础之——单向链表的创建和遍历

在这里插入图片描述

一、前言

在数据的存储中,有一种存储方式称为“线性表”,“线性表”是指数据具有“一对一”的逻辑方式,所有的数据像一根线一样,被串起来存储到物理空间中,“链表”属于“线性表”的一种,今天我们来学习下链表的使用。

二、名词解释

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

链表在插入的时候是O(1)的时间复杂度,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间复杂度,与另一种线性表——顺序表的插入O(n)的时间复杂度,查找O(1)的时间复杂度刚好相反。

三、重要概念

1、某一元素的左侧相邻元素称为“直接前驱”,位于此元素左侧的所有元素都统称为“前驱元素”;

2、某一元素的右侧相邻元素称为“直接后继”,位于此元素右侧的所有元素都统称为“后继元素”;

3、链表中的每个存储元素,我们称之为“结点”,结点由数据域和指针域两部分组成,数据域存储数据,指针域存储下一个结点的地址,即指向直接后继元素。

结点内容:
在这里插入图片描述
链表形式:
在这里插入图片描述
链表有两种定义形式,一种是有头结点,一种没有头结点。

  • 有头结点时,头指针指向头结点,头结点指向首元结点,首元结点再指向其他结点,以此类推。

  • 无头结点时,头指针指向首元结点,首元结点指向其他结点,以此类推。

头指针,头结点和首元结点的概念:

1、头指针:它的特点是永远指向链表第一个节点的位置。很明显,头指针用于指明链表的位置,便于后期找到链表并使用表中的数据;

2、结点:链表中的又细分为头结点、首元结点和其他结点:

  • 头结点:其实就是一个不存任何数据的空结点,通常作为链表的第一个结点。对于链表来说,头结点不是必须的,它的作用只是为了方便解决某些实际问题;
  • 首元结点:由于头结点(也就是空结点)的缘故,链表中称第一个存有数据的结点为首元结点。首元结点只是对链表中第一个存有数据结点的一个称谓,没有实际意义;
  • 其他结点:链表中其他的结点;
    在这里插入图片描述

四、链表的初始化和遍历

创建一个链表需要做如下工作:

1、声明一个头指针(如果有必要,可以声明一个头结点);
2、创建多个存储数据的结点,在创建的过程中,要随时与直接前驱建立逻辑关系。

以创建一个存储了数据{1,2,3,4}为例,代码如下(无头结点和有头结点):

#include "stdio.h"

typedef struct _link_list_t
{
  int data;
  struct _link_list_t *p_next;
}link_list_t;
void print_link_list_withoutHeaderPoint(link_list_t *temp)
{
    while(temp)
    {
      printf("%d ",temp->data);
      temp = temp->p_next;
    }
}
void print_link_list_withHeaderPoint(link_list_t *temp)
{
    while(temp->p_next)
    {
      temp = temp->p_next;
      printf("%d ",temp->data);
    }
}
//创建并初始化一个链表(含头结点),每个节点都有数据域和指针域,指针域指向下一个节点 
link_list_t *LinkInitWithoutHeaderPoint(void)
{
    int i;
    link_list_t *header = NULL;   //创建头指针,用来指向首元结点 
    link_list_t *temp = (link_list_t *)malloc(sizeof(link_list_t));  //创建一个首元结点 
    temp->data = 1;
    temp->p_next = NULL;   //首元结点初始化

    header = temp;  //头指针指向首元结点,与首元结点建立联系
    for(i=2;i<5;i++)    
    {
      link_list_t *a = (link_list_t *)malloc(sizeof(link_list_t));
      a->data = i;
      a->p_next = NULL;  //节点初始化

      temp->p_next = a;  //temp结点指针域指向刚建立的节点,与其建立联系
      temp = temp->p_next; //temp移动一位,以指向下一个节点 
    }

    return header;
}
//创建并初始化一个链表(含头结点),每个节点都有数据域和指针域,指针域指向下一个节点   
link_list_t *LinkInitWithHeaderPoint(void)
{
    int i;
    link_list_t *header = NULL;   //创建头指针,用来指向头结点
    link_list_t *temp = (link_list_t *)malloc(sizeof(link_list_t));  //创建一个头结点 

    header = temp;  //头指针指向头结点
    for(i=1;i<5;i++)    
    {
      link_list_t *a = (link_list_t *)malloc(sizeof(link_list_t));
      a->data = i;
      a->p_next = NULL;  //节点初始化

      temp->p_next = a;  //temp结点指针域指向刚建立的节点,与其建立联系
      temp = temp->p_next; //temp移动一位,以指向下一个节点 
    }

    return header;
} 
int main(void)
{
    //link_list_t *p = LinkInitWithoutHeaderPoint();
    link_list_t *p = LinkInitWithHeaderPoint();
    printf("创建并打印的链表数值为:\r\n");
    //print_link_list_withoutHeaderPoint(p);
    print_link_list_withHeaderPoint(p);
    return 0;
}

五、运行

在这里插入图片描述

六、结语

1、在初始化链表时,结点需要动态分配内存malloc,每初始化新建一个结点,都需要和直接前驱建立联系,即将它的地址给到直接前驱的指针域。

2、头指针是结构体类型的指针,头结点数据域没有任何数据,指针域指向首元结点。

3、在打印有头结点的链表时,需要先执行temp = temp->p_next;再来打印,原因是temp指向的是头结点,而头结点是没有任何数据的。需要打印的是首元结点的数据,同理判断条件是while(temp->p_next),而不是while(temp).

如您在使用过程中有任何问题,请加QQ群进一步交流。

QQ交流群:906015840 (备注:物联网项目交流)

静晨出品:静之所想,晨之所计
在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值