详细|写完这篇文章我终于搞懂链表了 (2)

为了说明问题简单,我们这里的结点只存储整数。

//结点 typedef struct Node { int data; //数据域:存储数据 struct Node *next; //指针域:存储直接后继结点的地址 } Node;

这样的一个结构体就能完美地表示一个结点了,许多结点连在一块就能构成链表了。

一个结点

单链表的结构

单链表由若干的结点单向链接组成,一个单链表必须要有头有尾,因为计算机很“笨”,不像人看一眼就知道头在哪尾在哪。所以我们要用代码清晰地表示出一个单链表的所有结构。

头指针

请先注意 “头” 这个概念,我们在日常生活中拿绳子的时候,总喜欢找“绳子头”,此“头”即彼“头”。

然后再理解 “指针” 这个概念(如不清楚指针,请移步至请移步至文章【如何掌握 C 语言的一大利器——指针?】),指针里面存储的是地址。

那么,头指针即存储链表的第一个结点的内存地址的指针,也即头指针指向链表的第一个结点。

下图是一个由三个结点构成的单链表:

(为了方便理解链表的结构,我会给出每个结点的地址以及指针域的值)

头指针

指针 head 中保存了第一个结点 1 的地址,head 即为头指针。有了头指针,我们就可以找到第一个结点的位置,就可以找到整个链表。通常,头指针的名字就是链表的名字。

即,head(头指针)在手,链表我有

值为 3 的结点是该链表的“尾”,所以它的指针域中保存的值为 NULL,用来表示整个链表到此为止

我们用头指针表示链表的开始,用 NULL 表示链表的结束

头结点

在上面的链表中,我们可以在值为 1 的结点前再加一个结点,称其为头结点。见下图:

头结点

头结点的指针域中一般不存放数据(可以存放如结点数等无关紧要的数据),从这点看,头结点是不同于其他结点的“假结点”。

此时头指针指向头结点,因为现在头结点才是第一个结点

为什么要设立头结点呢?这可以方便我们对链表的操作,后面你将会体会到这一点。

当然,头结点不是链表的必要结构之一,他可有可无,仅凭你的喜好

有无头结点的单链表

既然头结点不是链表的必要结构,这就意味着可以有两种链表:

带头结点的单链表

不带头结点的单链表

再加上头指针,初学链表时,“我们的头”很容易被“链表的头”搞晕。

别晕,看下面两幅图:

不带头结点的单链表

带头结点的单链表

记住以下几条:

头指针很重要,没它不行

虽然头结点可以方便我们的一些操作,但是有没有都行

无论带头结点与否,头指针都指向链表的第一个结点

(后面的操作我们将讨论不带头结点和带头结点两种情况)

空链表 不带头结点

下图是一个不带头结点的空链表:

详细|写完这篇文章我终于搞懂链表了

即头指针中存储的地址为 NULL。

带头结点

下图是一个带头结点的空链表:

详细|写完这篇文章我终于搞懂链表了

此时头指针中存储的是第一个结点——头结点的地址,头结点的指针域中存储的是 NULL 。

(后面的图示将不再给出内存地址)

创造结点

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyjydy.html