1. 链表的概念
线性表的链式存储就叫做链表,链表的物理储存地址是离散的。
那么如何去确定一个链表呢?
设有n个结点,每个结点之间是不连续的,并且每个结点之间是有指针相连的,此时,能不能判断这个结构为链表?
答案是不能。
它有可能是树,因为树的存储也是离散存储的,而且树中每个结点也是有指针相连的,因此根据以上两个条件并不能判断出链表。
我们知道,链表像一个链子一样,这就说明,链表的每个结点都只有一个前驱结点,和一个后继结点,并且首结点没有前驱结点,尾结点也没有后继结点。此时才可称这个结构为链表。
总结一下,就是链表的定义
1,是离散储存;
2,每个结点之间有指针相连
3,链表的每个结点都只有一个前驱结点,每个结点都只有一个后继结点,并且首结点没有前驱结点,尾结点也没有后继结点。
2. 什么是头结点
一般的,把链表的第一个存放有效数据的结点称之为首结点,而把最后一个存放有效数据的结点称之为尾结点。
由于操作的需要,使其更加方便,往往要在首结点之前再加一个结点,那么就称这个结点为头结点。
如果有一个指针变量指向了头结点,存放头结点的地址,那么这个指针变量被称之为头指针,同样的,当一个指针指向尾结点时,称之为尾指针。
那么问题来了,头结点是否与链表中的结点性质相同?
上述说到,增加头指针的一个目的是能更加方便操作链表,头结点并没有存放任何有效数据,因为第一个存放有效数据的结点一定为首结点。但是,头结点的数据类型与首结点是相同的。头结点只添加在第一个有效结点之前。
3. 链表的分类
常见的链表有单链表、双链表、循环链表、非循环链表等。
这里讲的是以单链表为例子。
其中,双链表是指有两个指针域的链表。
循环链表是指能通过链表中任意一个结点去寻找该链表的所有结点的链表。
4. 链表的代码实现
既然已经了解了什么是链表,那么,该怎么用代码实现?
一个链表应该具有两部分,一个部分是存放有效数据的,另一个部分是存放指针的,否则,就不能通过指针,来指向下一个结点。
存放有效数据的叫做数据域,存放指针的叫做指针域。
这里以C语言为例,我们可以用结构体来实现链表
struct Node
{
int data;//数据域
*pNext;//指针域
}NODE,*PNODE;
此时,有个问题,指针应该指向哪里?是指向下一个结点整体还是下一个结点的某个元素?
链表的每个结点是通过指针相连的,那么指针应该指向的是下一个结点整体而非其中某个成员
链表中每个结点的数据类型应该是相同的,所以上述代码可以更改一下
struct Node
{
int data;//数据域
struct Node *pNext;//指针域
/*
struct Node 不是指向本身 而是该结点的指针
指向了与该结点数据类型一样的另一个结点
*/
}NODE,*PNODE;
在 *pNext前增加struct Node表示的是该结点的指针指向了与该结点数据类型一样的另一个结点,而不是指向它本身。
(未完待续)