【链表6】<最新>初识链表(link list)

文/Edward


回顾之前讲述的链接两个结构体节点的内容,我们可以简单的将一些存储对象数据的结构体变量链接到一起,然后再去通过next指针遍历整个数据链,这就类似于将一些毫无关联的结构体变量链接成了一个整体,这个整体就是链表。
我们之前讲述连接两个结构体这一章节的内容其实讲述了一个不完整的链表结构,不完整的地方在于,这种连接多个结构体变量的方式无法动态地去添加节点和删除节点,只能在有限的已经被定义的结构体变量中去做链接,本小节内容将会针对如何去动态创建链表节点,详细地阐述如何使用C语言中的链表。

  链表的理想形态
我们到底需要一种怎么样的链表?这是首先需要讨论的问题。
一个链表的理想形态主要有以下几点:
  • 链表的内存大小是动态的。当一个链表被创建时,如果没有存储任何内容,我们则希望这个链表最好不占用内存空间。
  • 链表的节点可以自由删减。当我们需要向链表中存入一个数据时,这个链表的内存可以被动态增加以用于存放数据。当我们需要将链表中的某一个节点删除,这个链表的内存可以被动态地释放,防止无故坏死的内存块存在。
  • 链表中的数据可以被检索,遍历。当我们需要在链表中查询某个元素的时候,链表可以快速地响应。
  • 链表中的数据可以被快速插入。当我们需要向链表中某一个位置插入一个数据时,这个数据节点可以被快速地插入,而不需要像线性表一样,对整体数据进行移位,因为这会远远加重程序的时间复杂性。
基于上面我们所希望的一个链表所具有的特性,我们可以简单地画出链表的内存特征。我们先声明一个链表节点的结构体存储:
typedef struct Node{int data;struct Node *next;} Node_t;
当这个表示链表节点的结构体存储类型被申明好之后,我们就可以使用它去定义一个节点指针了,这个节点指针被定义好之后,应该将其指向NULL,防止其称为野指针。
Node_t *node;
注意,此时只不过是定义了一个节点指针,它本身没有指向任何内存。具体存储示意图如图1所示。
图1 链表初始节点
当我们定义和声明好之后一个初始化节点之后,尽管此时不存入任何数据,但是我们还是需要为这个节点分配一个内存,以准备任何时刻都有数据存储进来,而此时的next指针由于不指向任何内存,因此需要将其指向NULL。分配内存,还是使用我们之前讲述过的malloc函数。
node_t *ll_pt;ll_pt = (node_t *)malloc(sizeof(node_t));
此时,初始的链表节点就指向了一块内存了,如图2所示。此时,我们可以对这个节点中的data部分存入我们想要存入的数值,而next指针由于此时没有指向任何东西,所以需要将其指向到NULL。
图2 链表初始化

链表初始化完成之后就可以将数据存入链表里面了,还可以对这个链表再增加一个数据节点,增加的方式为,新建一个节点,将上一个节点的next指针指向这个节点,将这个新建的节点的next指针指向NULL。此时的内存分布如图3所示。
图3 链表指向新节点
  链表操作
(1)初始化链表
初始化链表其实就是初始化链表的第一个节点,此时需要做的内容为:
创建一个结构体类型;
创建一个结构体指针作为链表的第一个节点;
为这个节点分配一块内存。
上述的操作代码如图4所示。
图4初始化链表节点
(2)创建并添加新节点
初始化链表之后,我们就可以对这个链表进行数据的存储了,先来做向后追加节点。向后追加节点的步骤很简单,即在一个函数里面声明一个节点,然后将初始化完成之后的头节点中的next指针指向这个新增的节点,而新增节点的next指针则指向NULL。代码如图5所示。
图5 向后追加新节点

这个函数我们还可以修改一下,在ll_append函数的形参列表中,加入需要追加的节点数据。同时,我们可以将链表初始化函数和节点追加函数进行统一,其思路为,判断传入的list变量是否为NULL,如果是NULL,则代表此时的链表还没有被初始化,进而进行初始化,否则只向这个链表添加节点。代码如图6所示。
图6 统一的链表初始化和追加数据函数
(3)遍历链表
此时,我们可以向这个链表里面添加数据了,添加完成数据之后,我们需要对这个链表进行遍历输出数据。
遍历的思路为,已知链表的第一个节点即为链表的起始处,且最后一个节点的next指针势必为NULL,那么我们只需要抓住这两点进行判断。定义一个遍历指针,先指向list处,接着打印其中的数据部份,打印完成后将这个指针指向它自己的next指针,如此循环,直至自己的next指针为NULL,则代表遍历结束。具体代码如图7所示。
图7 遍历链表
(4)释放链表
最后,链表使用完成之后需要释放,直接使用free函数,对节点遍历后,一个个释放即可。但需要注意的是,我们必须保证节点指针在被释放之前,next指针要指向下一个节点,直至next指针为NULL。
图8释放链表


(0)

相关推荐

  • 【数据结构笔记】单链表

    链表是线性表的一种存储结构.关于线性表的概念,可以查看上一篇笔记[数据结构笔记]顺序表--静态分配 什么是链表? 链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针 ...

  • 【链表6】<最新>链表(link list)

    文/Edward 回顾之前讲述的链接两个结构体节点的内容,我们可以简单的将一些存储对象数据的结构体变量链接到一起,然后再去通过next指针遍历整个数据链,这就类似于将一些毫无关联的结构体变量链接成了一 ...

  • 【链表5】<最新>线性表(List)简介

    文 /Edward   结构体数组与线性表A 前面我们使用结构体数组设计出了类似于"表(Table)"数据结构的存储序列,它以整个定长度的结构体数组为单位,并且以每个结构体数组中的 ...

  • 【链表4】<最新>结构体数组实现表(Table)

    文/Edward   表(Table)的概念 在充分了解了前面两小节的准备知识之后,我们接下来就可以言归正传来说链表了. 在讲述链表之前,我们再来详细讲述一下表(Table)这个概念.表(Table) ...

  • leetcode刷题笔记-234. 回文链表(java实现)

    题目描述 请判断一个链表是否为回文链表. 示例 1: 输入: 1->2 输出: false 示例 2: 输入: 1->2->2->1 输出: true 来源:力扣(LeetCo ...

  • Python | 删除链表的节点问题解决方法

    问题描述给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点.返回删除后的链表的头节点.示例 1:输入: head = [4,5,1,9], val = 5输出: [4,1,9]解释: ...

  • C++丨删除链表中间节点的方法详解

    这篇文章主要介绍了C++删除链表中间节点的方法,结合实例形式分析了链表删除中间节点的具体思路与实现技巧,希望在学习上有帮助到大家.   题目: 给定链表头结点head,实现删除链表的中间节点函数. 解 ...

  • 基本数据结构:单链表

    基本数据结构-轻松学习单链表 基本数据结构-轻松学习单链表 展开

  • ​LeetCode刷题实战237:删除链表中的节点

    算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试.所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 ! 今天和大家 ...

  • Go 数据结构和算法篇(一):链表

    前天 以下文章来源于xueyuanjun ,作者xueyuanjun xueyuanjun学院君的订阅号,我会在这里持续更新优质全栈编程技术教程,包括但不限于 Golang.PHP.JavaScrip ...