数据结构中的单向不循环链表
单向不循环链表
- 链表就是通过离散的内存,来存储数据,一个数据被称为结点,每一个结点有存放自己的数据以及下一个结点的地址

- 链表的节点
//存储数据类型(可修改),在遍历数据的时候是需要输出的,所以输出类型也需要修改
//链表节点下面是数据的数据类型
typedef int DataType_t;
//带头结点的链表
//1.每一个节点都有自己的元素和连接下一个元素的地址
typedef struct linklist
{
DataType_t data; //链表节点存放的数据
struct linklist *next; //链表节点存放下一个链表节点的地址
}LkList_t;
创建链表

/***************************************************
* 函数名称: LkList_CreatList
* 函数功能: 创建一个新的链表
* 函数参数: None
* 返回结果: 返回链表的地址:创建成功。NULL:创建失败。
* 注意事项: None
* 函数作者:
* 创建日期: 2024/04/22
* 修改历史:
* 函数版本: V1.0
***************************************************/
LkList_t * LkList_CreatList(void)
{
//在堆空间申请一个空间存放链表的头结点
LkList_t * Head = (LkList_t *)calloc(1,sizeof(LkList_t));
if(NULL == Head){
perror("calloc memory for head is failed!!!");
return NULL;
}
//头结点的初始化,数据不需要初始化
Head->next = NULL;
//返回头结点的地址
return Head;
}
创建新结点
/***************************************************
* 函数名称: LkList_NewNode
* 函数功能: 创建一个链表新的节点
* 函数参数:
* @data :创建链表节点时,下面存放的数值
* 返回结果: 返回链表的地址:创建成功。NULL:创建失败。
* 注意事项: 一般都在插入的时候需要使用,不会单独使用
* 函数作者:
* 创建日期: 2024/04/22
* 修改历史:
* 函数版本: V1.0
***************************************************/
LkList_t * LkList_NewNode(DataType_t data)
{
//1.先从堆空间申请内存存放链表节点
LkList_t * New = (LkList_t *)calloc(1,sizeof(LkList_t));
if(NULL == New){
perror("Calloc memory for NewNode is failed!");
return NULL;
}
//初始化链表节点
New->data = data;
New->next = NULL;
//申请成功直接返回
return New;
}
头部插入结点

/***************************************************
* 函数名称: LkList_HeadInsertNode
* 函数功能: 在头节点的后面插入新的节点
* 函数参数:
* @Head :头结点的地址
* @data :创建链表节点时,下面存放的数值
* 返回结果: true:插入成功;false:插入失败
* 注意事项: Node
* 函数作者:
* 创建日期: 2024/04/22
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool LkList_HeadInsertNode(LkList_t * Head,DataType_t data)
{
//1.先判断链表是否存在
if(NULL == Head){
printf("Linklist head is not exist!!!\n");
return false;
}
//创建新的节点
LkList_t * New = LkList_NewNode(data);
if(NULL == New){
return false;
}
//如果存在,直接把头结点指向的地址赋值给新的节点下面的地址
New->next = Head->next;
Head->next = New;
return true;
}
尾部插入结点

/***************************************************
* 函数名称: LkList_TailInsertNode
* 函数功能: 在尾部节点的后面插入新的节点
* 函数参数:
* @Head :头结点的地址
* @data :创建链表节点时,下面存放的数值
* 返回结果: true:插入成功;false:插入失败
* 注意事项: Node
* 函数作者:
* 创建日期: 2024/04/22
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool LkList_TailInsertNode(LkList_t * Head,DataType_t data)
{
//1.先判断链表是否存在
if(NULL == Head){
printf("Linklist head is not exist!!!\n");
return false;
}
//创建新的节点
LkList_t * New = LkList_NewNode(data);
if(NULL == New){
return false;
}
//判断是否只有头结点
if(Head->next == NULL){
Head->next = New;
return true;
}
//备份头结点对地址,以免丢失链表
LkList_t *Phead = Head->next;
//寻找尾部节点,判断Phead->next是否为空
while(Phead->next){
Phead = Phead->next;
}
//到了尾部节点可以开始添加
New->next = Phead->next;
Phead->next = New;
return true;
}
中间插入结点

/***************************************************
* 函数名称: LkList_MediumInsertNode
* 函数功能: 在源数据dest_data后面插入data数据
* 函数参数:
* @Head :头结点的地址
* @dest_data :要寻找的链表的数据
* @data :要插入的数据
* 返回结果: true:插入成功;false:插入失败
* 注意事项: Node
* 函数作者:
* 创建日期: 2024/04/23
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool LkList_MediumInsertNode(LkList_t * Head,DataType_t dest_data,DataType_t data)
{
//1.先判断链表是否存在
if(NULL == Head){
printf("Linklist head is not exist!!!\n");
return false;
}
//创建新的节点
LkList_t * New = LkList_NewNode(data);
if(NULL == New){
return false;
}
//备份头结点用来寻找到data结点的位置
LkList_t *Phead = Head->next;
//寻找到数据节点,防止死循环
while((Phead->data != dest_data) && (Phead->next != NULL)){
Phead = Phead->next;
}
//判断是不是没找到
if((Phead->data != dest_data) && (Phead->next == NULL)){
printf("dest_data(%d) is not found!\n",dest_data);
return false;
}
//寻找到数据节点可以在后面插入,无论是在尾还是中间都可以插入
New->next = Phead->next;
Phead->next = New;
return true;
}
头部删除结点

- 在删除结点时,需要判断链表是否为空
/***************************************************
* 函数名称: LkList_IsEmpty
* 函数功能: 判断链表是否为空
* 函数参数:
* @Head :头结点的地址
* 返回结果: true:为空;false:不为空
* 注意事项: Node
* 函数作者:
* 创建日期: 2024/04/23
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool LkList_IsEmpty(LkList_t * Head)
{
return (Head->next == NULL) ? true : false;
}
/***************************************************
* 函数名称: LkList_HeadDelNode
* 函数功能: 把链表的首结点删除
* 函数参数:
* @Head :头结点的地址
* 返回结果: true:删除成功;false:删除失败
* 注意事项: Node
* 函数作者:
* 创建日期: 2024/04/23
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool LkList_HeadDelNode(LkList_t * Head)
{
//1.先判断链表是否存在
if(NULL == Head){
printf("Linklist head is not exist!!!\n");
return false;
}
//判断链表是否为空
if(LkList_IsEmpty(Head)){
printf("Linklist is empty!!!\n");
return false;
}
//定义变量存储当前结点直接让他指向首节点的地址,以便于释放删除的结点
LkList_t *Phead = Head->next;
//寻找到数据节点可以开始删除
Head->next = Phead->next;
Phead->next = NULL;
free(Phead);
Phead = NULL;
return true;
}
尾部删除结点

/***************************************************
* 函数名称: LkList_TailDelNode
* 函数功能: 把链表的首结点删除
* 函数参数:
* @Head :头结点的地址
* 返回结果: true:删除成功;false:删除失败
* 注意事项: Node
* 函数作者:
* 创建日期: 2024/04/23
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool LkList_TailDelNode(LkList_t * Head)
{
//1.先判断链表是否存在
if(NULL == Head){
printf("Linklist head is not exist!!!\n");
return false;
}
//判断链表是否为空
if(LkList_IsEmpty(Head)){
printf("Linklist is empty!!!\n");
return false;
}
//定义变量存储当前结点以及当前结点的直接前驱
LkList_t *Phead = Head->next;
LkList_t *Phead_prev = Head;
//寻找到尾结点,以及尾结点的直接前驱
while(Phead->next){
Phead = Phead->next;
Phead_prev = Phead_prev->next;
}
//寻找到数据节点可以开始删除
Phead_prev->next = NULL;
free(Phead);
Phead = NULL;
return true;
}
中间删除结点

/***************************************************
* 函数名称: LkList_MediumDelNode
* 函数功能: 把这个数据节点删除
* 函数参数:
* @Head :头结点的地址
* @data :要删除的数据节点
* 返回结果: true:删除成功;false:删除失败
* 注意事项: Node
* 函数作者:
* 创建日期: 2024/04/23
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool LkList_MediumDelNode(LkList_t * Head,DataType_t data)
{
//1.先判断链表是否存在
if(NULL == Head){
printf("Linklist head is not exist!!!\n");
return false;
}
//判断链表是否为空
if(LkList_IsEmpty(Head)){
printf("Linklist is empty!!!\n");
return false;
}
//定义变量存储当前结点和当前结点的直接前驱
LkList_t *Phead = Head->next;
LkList_t *Phead_prev = Head;
//寻找到数据节点,并且防止没有这个数据
while((Phead->data != data) && (Phead->next)){
Phead = Phead->next;
Phead_prev = Phead_prev->next;
}
//判断数据是否存在
if((Phead->data != data) && (Phead->next == NULL)){
printf("data(%d) is not exist!!!\n",data);
return false;
}
//寻找到数据节点可以开始删除
Phead_prev->next = Phead->next;
Phead->next = NULL;
free(Phead);
Phead = NULL;
return true;
}
遍历链表
/***************************************************
* 函数名称: LkList_TraNode
* 函数功能: 遍历输出每一个结点的数据
* 函数参数:
* @Head :头结点的地址
* 返回结果: true:遍历成功;false:遍历失败
* 注意事项: Node
* 函数作者:
* 创建日期: 2024/04/23
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool LkList_TraNode(LkList_t * Head)
{
//1.先判断链表是否存在
if(NULL == Head){
printf("Linklist head is not exist!!!\n");
return false;
}
//判断链表是否为空
if(LkList_IsEmpty(Head)){
printf("Linklist is empty!!!\n");
return false;
}
//备份数据,直接给首结点数据
LkList_t * Phead = Head->next;
int i = 1;//输出第几个数据
//遍历到最后的节点,输出数据
while(Phead->next){
printf("[%d]th Node is %d\n",i,Phead->data);
i++;
Phead = Phead->next;
}
printf("[%d]th Node is %d\n",i,Phead->data);
return true;
}
修改链表的数据
- 根据所给对数据,把链表内部的数据修改
/***************************************************
* 函数名称: LkList_DataRecNode
* 函数功能: 根据数据修改节点
* 函数参数:
* @Head :头结点的地址
* @dest_data :需要修改的数据
* @data :修改的数据
* 返回结果: true:修改成功;false:修改失败
* 注意事项: Node
* 函数作者:
* 创建日期: 2024/04/29
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool LkList_DataRecNode(LkList_t * Head,DataType_t dest_data,DataType_t data)
{
//1.先判断链表是否存在
if(NULL == Head){
printf("Linklist head is not exist!!!\n");
return false;
}
//判断链表是否为空
if(LkList_IsEmpty(Head)){
printf("Linklist is empty!!!\n");
return false;
}
//备份头结点对地址,以免丢失链表
LkList_t *Phead = Head->next;
//寻找到数据节点,并且防止没有这个数据
while((Phead->data != dest_data) && (Phead->next)){
Phead = Phead->next;
}
//判断数据是否存在
if((Phead->data != dest_data) && (Phead->next == NULL)){
printf("dest_data(%d) is not exist!!!\n",dest_data);
return false;
}
Phead->data = data;
return true;
}
删除整个链表
/***************************************************
* 函数名称: LkList_Del
* 函数功能: 删除链表
* 函数参数:
* @Head :头结点的地址
* 返回结果: true:删除成功;false:删除失败
* 注意事项: Node
* 函数作者:
* 创建日期: 2024/04/23
* 修改历史:
* 函数版本: V1.0
***************************************************/
bool LkList_Del(LkList_t * Head)
{
//1.先判断链表是否存在
if(NULL == Head){
printf("Linklist head is not exist!!!\n");
return false;
}
//让Head先向前走,然后后面跟着Head的前驱节点,删除前驱节点
LkList_t * Head_prev = Head;
Head = Head->next;
//遍历到最后的节点,输出数据
while(Head){
//Head不为空直接删除直接前驱,
Head_prev->next = NULL;
free(Head_prev);
Head_prev = Head;
Head = Head->next;
}
//Head为空,退出去删除直接前驱和Head本身.
Head_prev->next = NULL;
free(Head_prev);
Head_prev = NULL;
return true;
}

浙公网安备 33010602011771号