链表的概念
链表,别名:链式存储结构
链表的特点:
-
不限制数据的物理存储状态
-
存储的数据物理位置是随机的不是连续的
-
-
每个数据存储时都配备一个指针,用于指向自己的直接后继元素--->前驱和后继
使用链表存储数据{1,2,3}
图示:
链式存储结构
数据元素随机存储,并通过指针表示数据之间逻辑关系的存储结构就是链式存储结构
链表的组成部分
-
数据元素本身,数据域
-
指向直接后继元素的指针,指针域
链表中元素存储结构示意图:
特点:
-
上诉结构在链表中称为节点。链表实际存储的是一个一个的节点,真正的数据元素包含在这些节点中
节点存储结构图示:--->简单结构
C语言实现节点的结构体
typedef struct Link{
char element; //数据域
struct Link * next; //指针域,指向直接后继元素
}link;
/*
link为节点名,每个节点都是一个 link 结构体
类似宏,一个link就包含数据域和指针域,指针域是一个指针变量
*/
Go实现:
/*
创建链表的节点结构体:
1、数据域
2、指针域--->一个指针变量,属于该结构体的指针变量
*/
type Link struct {
/*创建数据域*/
element int
/*创建指针域--->一个指针变量,属于该结构体*/
*Link
}
由于指针域中的指针要指向的也是一个节点,因此要声明为 Link 类型(这里要写成 struct Link*
的形式)
头节点、头指针、首元节点
一个完整的链表由以下几个部分构成:
-
头指针:一个普通的指针。永远指向链表第一个节点的位置。用于指明链表的位置,便于后期找到链表并使用表中的数据
-
节点:
-
头节点:不存任何数据的空节点,通常作为链表的第一个节点--->头节点是必须的。方便解决某些实际问题
-
首元节点:链表中称第一个存有数据的节点为首元节点--->只是一个称谓,没有实际意义
-
其他节点:链表中其他的节点
-
链表中有头节点时,头指针指向头节点;反之,若链表中没有头节点,则头指针指向首元节点。
完整链表的结构图示:
链表的创建
创建一个链表需要做的事情:
-
声明一个头指针
-
声明一个头节点
-
创建多个存储数据的节点
创建一个存储 {1,2,3,4}
且无头节点的链表示例代码:--->要结合上面的结构体来看
//初始化link结构体
link * initLink(){
link * p = NULL; //创建一个头指针--->该指针式link结构体的一个实例。包含了数据域和指针域
link * temp = (link*) malloc(sizeof(link)); //创建首元节点--->第一个拥有数据的节点--->也是一个link结构体的实例
//首元节点初始化--->获取结构体成员
temp->elem = 1;
temp->next = NULL;
//使头指针指向首元节点
p = temp;
//从第二个节点开始创建节点
for(int i=2;i<5;i++){
//创建一个新节点并且初始化
link *a = (link*)malloc(sizeof(link));
//初始化数据域与指针域
a->elem = i;
a->next = NULL;
//将上诉的首元节点与新节点建立逻辑关系
temp->next = a; //next是结构体的一个link结构体指针,a本身就是一个结构体
//指针temp每次都指向新链表的最后一个节点,其实就是 a节点,写temp=a也对
temp = temp->next;
}
//返回建立的节点,只返回头指针p即可。通过头指针找到整个链表
return p;
}
创建一个含头节点的链表示例代码:
link * initLink(){
link * p = NULL; //这是一个头指针
link * f = (link*)malloc(sizeof(link)); //这是一个头节点
p = f; //这是让头指针指向头节点--->赋值操作
//开始创建其他节点
for(int i=1;i<5;i++){
//创建其他节点
link * a=(link)malloc(sizeof(link));
//初始化数据域和指针域
a->elem = i; //这是数据域
a->next = NULL; //这是指针域
//让头节点与首元节点发生逻辑联系--->用头指针的指针域指向首元节点
f->next=a;
//指针每次都指向新链表的最后一个节点
f=f->next //其实就是f=a->next
}
//返回头指针
return p;
}
调用 initLink 函数,创建一个存储 {1,2,3,4}
的链表示例代码:
如果使用带有头节点创建链表的方式,则输出链表的 display 函数需要做适当地修改:--->交换输出和指向的顺序,先指向在输出
void display(link *p){
//将temp指向头节点
link * temp = p;
//只要temp指针指向的结点的next不是Null,就执行输出语句
while(temp){
temp = temp->next; //指向下一个节点指针域
printf("%d", temp->elem);
}
printf("\n")
}