数据结构学习笔记——链式存储结构

链表:
线性表的链式存储结构,链表里面有很多个结点,每个结点由存放数据的数据域和表示数据元素之间的逻辑关系的指针域(C/C++这么用)。

单链表:
在每个结点中除了包含数据域之外只设置一个指针域,用于指向其后继结点,这样的链表称为线性单向链表,简称单链表。

双链表:
在每个结点中除了包含数据域之外设置两个指针域,一个用于指向前驱结点,一个用于指向后继结点。

注意:
若一个结点中的某个指针域不需要指向其他任何结点,则将它的值置为空,用常量NULL表示。

在线性表的链式存储中,通常每个链表带有一个头结点,并通过头结点唯一标识该链表,称之为头指针,相应的指向首结点或者开始结点的指针称为首指针,显然,在单链表中,首指针在首结点的前一个元素的指针域里面,也就是头指针的指针域里面;指向尾结点的指针称为尾指针,很明显,在单链表中,尾指针在倒数第二个结点的指针域。
数据结构学习笔记——链式存储结构_第1张图片
链表中,逻辑上相邻的元素对应的存储位置是通过指针来链接的,因而每个结点的存储位置可以任意安排,不必要求相邻,多以当进行插入(修改前一个元素以及插入元素的指针)和删除(只需修改前一个元素的指针)时只需修改相关结点的指针域即可。
数据结构学习笔记——链式存储结构_第2张图片

存储密度:
结点中数据元素所占的存储量/结点所占存储量
即:数据域的大小除以/(数据域大小+指针域大小)

显然,顺序表的存储密度为1(因为指针域大小为0),而链表的存储密度小于1。
单链表:
单链表的元素类型:
假设每个结点的类型用LinkNode表示,每个结点应包括数据域和指针域。声明如图所示:
数据结构学习笔记——链式存储结构_第3张图片

在单链表中增加一个头结点的优点:
1.使首结点的删除和插入与其他结点的操作一致,无需特殊化。
2.无论单链表是否为空都有一个头结点,因此统一了空表和非空表的处理过程。

插入和删除结点的操作:
插入:
假设在两个数据域分别为a,b的结点(已知指针p指向a所在的结点)中间插入一个数据域为c的结点(s指向这个结点),如图所示:数据结构学习笔记——链式存储结构_第4张图片
首先修改s指向的结点的指针域,让其等于p -> next(这是一个指针域,数据域a所在结点的指针域),这样p和s这两个指针指向的结点就都和b所在的结点有了指向关系,这时候就需要把p所指向的结点的指针域的值改为s所指向的结点的地址,也就是s。
修改操作用C/C++描述如下:

s -> next = p ->next;
p -> next = s;

注意顺序不可颠倒

拓展:
单链表中,p ->a 到 p ->b的方法:
for 循环 、 p = p -> next

删除:
在这里删除指在单链表中删除结点p的后继结点,如图所示:
数据结构学习笔记——链式存储结构_第5张图片
删除b所在结点的操作是让a所在的结点的指针域指向c所在结点的地址。
操作用C/C++描述如下:

p -> next = b -> next;

实际上在删除一个结点之后还需要释放其空间,而且如果直接让a所在的结点直接链接c所在的结点,那么我们就不知道b所在的结点的地址了,所以在删除之前,应该用一个指针先指向这个结点,这样子就有两个指针指向这个被处理元素了,在第一个指针没有指向这个结点之后,还会有一个指针指向它,那么就可以利用这个结点来进行删除操作。

q = p ->next;	//用一个指针指向b所在的结点。
p -> next = q -> next // or = b ->next 		//从结点中删除b所在的结点,让
//a所在的结点后面直接是c所在的结点。
free(q);	//释放空间

你可能感兴趣的:(数据结构,数据结构,链表)