目录
一、链式存储结构定义
1、定义:线性表的存储方式分为顺序存储和链式存储。其中链式存储是指将线性表中的元素按照一定的次序链接起来,每个元素包含两个部分:数据域和指针域。其中,数据域用于存储元素的值,指针域用于指向下一个元素的地址。通过指针域之间的链接,可以将线性表中的元素连接成一条链式结构。
2、特点:
- 结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻。
- 访问时只能通过头指针进入链表,并通过每个结点的指针域依次向后顺序扫描其余结点,所以寻找到一个结点和最后一个结点所花费的时间不等。
二、链表的介绍
1、链表分为单链表、循环链表、双向链表 。
- 单链表: 每个结点只包含直接后继的地址信息,结点只有一个指针域的链表。
- 循环链表:单链表的最后一个结点的直接后继为第一给结点(首尾相接)
- 双向链表:单链表中的结点包含直接前驱和后继的地址信息(结点有两个指针域 )
链表中相关术语:
- 头结点:它是链表中的辅助结点,只包含指向第0个数据元素的指针,而没有数据信息,头结点有简化代码的作用,因为它始终指向了第0个元素,便于执行时对元素位置的定位。
- 尾结点:尾结点中存储的地址信息可以用于区分链表类型。尾指针为空:单链表。尾指针指向链表的开头:循环链表。为随机值:非法链表。
- 数据结点:它是链表中代表数据元素的结点,表现为数据域和指针域。
- 指针域:结点中存储数据元素之间的链接信息即下一个结点地址的部分。
- 数据域:结点中存储数据元素的部分。
三、循环链表的实现
1、循环链表的创键
循环链表是一种头尾相接的链表如上图,表中最后一个结点的指针域指向头结点,整个链表形成一个一个环状,循环链表与单链表类似,只不过单链表最后一个结点指向NULL.
/*简单链表的定义*/
typedef struct node //声明结点的类型和指向结点的指针类型
{
DataType data; /*数据域*/
struct node *next; /*指针域*/
}SingleLinkList, SingleLinkNode;
2、 链表初始化
单链表的初始化是指将一个空的单链表开辟一段连续的内存空间,生成新的结点作为头结点,用头指针指向头结点,并将头结点指针域置空。具体代码实现如下:
//init函数接受一个指针的指针SingleLinkList **Head 作为参数表示需要初始化单链表的头结点地址
int init(SingleLinkList **Head)
{
if(1)
{
/*使用malloc()函数为单链表分配一块空间,大小为 sizeof(SingleLinkList)*/
(*Head) = (SingleLinkList*)malloc(sizeof(SingleLinkList));
/*判断内存申请是否成功*/
if(*Head == NULL)
{
printf("申请内存错误, 初始化失败![100001]\n");
return 100001;
}
/*将头结点的next指针指向自身,即(*Head)->next=*Head*/
(*Head)->next=*Head;
/*单链表:(*Head)->next = NULL;*/
/*循环链表:(*Head)->next = *Head;*/
return 0;
}
else
{
printf("该链表已经初始化!请删除后再执行此操作![100002]\n");
return 100002;
}
}
3、 插入算法(头插法)
头插法是将新的元素插入到头结点的后面。具体是先将头结点与首节点联系断开,将首节点的地址(存放在头结点的指针域)赋给要插入的新节点的指针域,这样子新节点就和后面的所有节点连接了起来,起到了保护后面所有节点的作用; 然后将新节点的地址赋值给头结点的指针域,覆盖掉原本存放的首节点的地址,这样操作就完成了对链表的头结点插入元素。
/*2. 插入元素,头插法*/
int insert_head(SingleLinkList **Head, DataType x)
{
SingleLinkNode *newNode;
if(0)
{
printf("链表未初始化![100003]\n");
return 100003;
}
newNode = (SingleLinkNode*)malloc(sizeof(SingleLinkNode));
if(!newNode)
{
printf("申请节点内存空间失败![100004]\n");
return 100004;
}
newNode->data = x;
newNode->next = (*Head)->next;
(*Head)->