单向循环链表的使用
1、单向循环链表
\quad 单向循环链表指得是将链表末尾节点循环地指向链表表头。比如,单向链表变成循环链表的示意图如下所示:
循环链表的操作跟普通链表操作基本上是一致的,只要针对循环特性稍作修改即可,遍历查找节点时,需将遍历的指针指向头节点。比如:
a、初始化单向循环链表
c
single_list_t *single_list_init()
{
single_list_t *head_node = malloc(sizeof(single_list_t));
head_node->next = head_node; // 指向头节点
return head_node;
}
b、节点头插
c
int insert_list_head(int newdata, single_list_t *list)
{
// 申请一个节点 -堆空间
single_list_t *new_node = malloc(sizeof(single_list_t));
// 初始化数据域
new_node->data = newdata;
new_node->next = NULL;
// 插入节点
new_node->next = list->next;
list->next = new_node;
return 0;
}
c、节点尾插
c
int insert_list(int newdata, single_list_t *list)
{
// 申请一个节点 -堆空间
single_list_t *new_node = malloc(sizeof(single_list_t));
// 初始化数据域
new_node->data = newdata;
new_node->next = NULL;
// 定义指针p去找到链表的尾部
single_list_t *p = list;
// 单向循环链表中遍历到最后一个节点的next指向头节点时 ,说明该节点是最末尾节点
while (p->next != list)
{
p = p->next;
}
// 此时p已经到最后一个节点的位置
p->next = new_node;
new_node->next = list;
return 0;
}
d、节点中间插入
c
int insert_list_mid(int olddata, int newdata, single_list_t *list)
{
// 找到要插入的节点
single_list_t *p = list;
while (p->next != list)
{
p = p->next;
if (p->data == olddata)
{
break;
}
}
// 申请一个节点 -堆空间
single_list_t *new_node = malloc(sizeof(single_list_t));
// 初始化数据域
new_node->data = newdata;
new_node->next = NULL;
// p指向最后一个节点
if (p->next == list)
{
if (p->data == olddata)
{
new_node->next = p->next; // 先让新增加的节点指向找到节点的下一个节点
p->next = new_node; // 再将该节点指向新增加的节点
}
else
{
printf("要插入的数据不存在\n");
return -1;
}
}
else // 遍历到中间找到需要插入的节点
{
new_node->next = p->next; // 先让新增加的节点指向找到节点的下一个节点
p->next = new_node; // 再将该节点指向新增加的节点
}
return 0;
}
e、删除节点
c
int list_delnode(int deldata, single_list_t *list)
{
// 定义两个指针去遍历查找要删除的节点
single_list_t *q = list;
single_list_t *p = list->next;
while (p->next != list)
{
// 找到要删除的节点并进行删除
if (p->data == deldata)
{
// 找到后马上删除该节点
q->next = p->next; // 将q指向的节点指向被删除节点的下一个节点
p->next = NULL; // p节点的next指针指向NULL
free(p); // 释放p后此时p是野指针
p = q->next; // 将p指向被删除节点的下一个节点
}
else
{
p = p->next;
q = q->next;
}
}
// 遍历到最后一个节点
if (p->next == list)
{
// 若最后一个节点是要删除的节点,则删除
if (p->data == deldata)
{
q->next = p->next;
p->next = NULL;
free(p);
}
else
{
printf("最后一个节点不是要删除的节点\n");
return 0;
}
}
}
f、修改节点
c
int list_update_node(int old_data, int new_data, single_list_t *list)
{
single_list_t *p = list;
while (p->next != list)
{
p = p->next; // p往后移动
if (p->data == old_data)
{
p->data = new_data;
}
}
return 0;
}
g、遍历链表,打印节点数据
c
int list_show(single_list_t *list)
{
// //定义指针p遍历链表
single_list_t *p = list;
while (p->next != list)
{
p = p->next; // p往后挪动
printf("当前p指向的节点数据:%d\n", p->data);
}
}
2、完整代码
c
#include <stdio.h>
#include <stdlib.h>
// 1.封装一个结构体来表示单链表
typedef struct single_list{
int data;
struct single_list *next;
}single_list_t;
/*@brief:2.初始化单链表-->定义结构体变量 创建头节点
*@param(in): none
*@param(out): none
*@retval: head_node 头节点
*/
single_list_t *single_list_init()
{
single_list_t *head_node = malloc(sizeof(single_list_t));
head_node->next = head_node; // 指向头节点
return head_node;
}
// 头插
int insert_list_head(int newdata, single_list_t *list)
{
// 申请一个节点 -堆空间
single_list_t *new_node = malloc(sizeof(single_list_t));
// 初始化数据域
new_node->data = newdata;
new_node->next = NULL;
// 插入节点
new_node->next = list->next;
list->next = new_node;
return 0;
}
/*@brief:3.插入数据-->尾插(在最后一个有效成员的后面插入数据)
*@param(in): newdata :待插入的数据
list:待插入的链表
*@param(out): none
*@retval: none
*/
int insert_list(int newdata, single_list_t *list)
{
// 申请一个节点 -堆空间
single_list_t *new_node = malloc(sizeof(single_list_t));
// 初始化数据域
new_node->data = newdata;
new_node->next = NULL;
// 定义指针p去找到链表的尾部
single_list_t *p = list;
// 单向循环链表中遍历到最后一个节点的next指向头节点时 ,说明该节点是最末尾节点
while (p->next != list)
{
p = p->next;
}
// 此时p已经到最后一个节点的位置
p->next = new_node;
new_node->next = list;
return 0;
}
/*@brief:3.插入数据-->中间插入
*@param(in): newdata :待插入的数据
olddata:在该节点后插入数据
list:待插入的链表
*@param(out): none
*@retval: none
*/
int insert_list_mid(int olddata, int newdata, single_list_t *list)
{
// 找到要插入的节点
single_list_t *p = list;
while (p->next != list)
{
p = p->next;
if (p->data == olddata)
{
break;
}
}
// 申请一个节点 -堆空间
single_list_t *new_node = malloc(sizeof(single_list_t));
// 初始化数据域
new_node->data = newdata;
new_node->next = NULL;
// p指向最后一个节点
if (p->next == list)
{
if (p->data == olddata)
{
new_node->next = p->next; // 先让新增加的节点指向找到节点的下一个节点
p->next = new_node; // 再将该节点指向新增加的节点
}
else
{
printf("要插入的数据不存在\n");
return -1;
}
}
else // 遍历到中间找到需要插入的节点
{
new_node->next = p->next; // 先让新增加的节点指向找到节点的下一个节点
p->next = new_node; // 再将该节点指向新增加的节点
}
return 0;
}
/*@brief:3.删除节点
*@param(in): deldata :待删除的节点
list:待插入的链表
*@param(out): none
*@retval: none
*/
int list_delnode(int deldata, single_list_t *list)
{
// 定义两个指针去遍历查找要删除的节点
single_list_t *q = list;
single_list_t *p = list->next;
while (p->next != list)
{
// 找到要删除的节点并进行删除
if (p->data == deldata)
{
// 找到后马上删除该节点
q->next = p->next; // 将q指向的节点指向被删除节点的下一个节点
p->next = NULL; // p节点的next指针指向NULL
free(p); // 释放p后此时p是野指针
p = q->next; // 将p指向被删除节点的下一个节点
}
else
{
p = p->next;
q = q->next;
}
}
// 遍历到最后一个节点
if (p->next == list)
{
// 若最后一个节点是要删除的节点,则删除
if (p->data == deldata)
{
q->next = p->next;
p->next = NULL;
free(p);
}
else
{
printf("最后一个节点不是要删除的节点\n");
return 0;
}
}
}
// 修改节点
int list_update_node(int old_data, int new_data, single_list_t *list)
{
single_list_t *p = list;
while (p->next != list)
{
p = p->next; // p往后移动
if (p->data == old_data)
{
p->data = new_data;
}
}
return 0;
}
// 4.遍历链表,打印节点数据
int list_show(single_list_t *list)
{
// //定义指针p遍历链表
single_list_t *p = list;
while (p->next != list)
{
p = p->next; // p往后挪动
printf("当前p指向的节点数据:%d\n", p->data);
}
}
int main(int argc, char const *argv[])
{
// 初始化单链表
single_list_t *my_list = single_list_init();
// 往链表插入数据
insert_list(15, my_list);
insert_list(18, my_list);
insert_list(15, my_list);
insert_list(25, my_list);
insert_list(666, my_list);
insert_list(123, my_list);
insert_list(11111111, my_list);
insert_list_mid(666, 777, my_list);
insert_list_mid(1, 222, my_list);
insert_list_head(999, my_list);
insert_list_head(888, my_list);
printf("============插入的节点============\n");
list_show(my_list);
printf("============插入的节点============\n");
// 删除节点
list_delnode(25,my_list);
printf("============删除后的节点============\n");
list_show(my_list); // 打印数据
printf("============删除后的节点============\n");
// 修改数据
list_update_node(123, 234, my_list);
printf("============修改后的节点============\n");
list_show(my_list); // 打印数据
printf("============修改后的节点============\n");
return 0;
}
/*
执行结果:
要插入的数据不存在
============插入的节点============
当前p指向的节点数据:888
当前p指向的节点数据:999
当前p指向的节点数据:15
当前p指向的节点数据:18
当前p指向的节点数据:15
当前p指向的节点数据:25
当前p指向的节点数据:666
当前p指向的节点数据:777
当前p指向的节点数据:123
当前p指向的节点数据:11111111
============插入的节点============
最后一个节点不是要删除的节点
============删除后的节点============
当前p指向的节点数据:888
当前p指向的节点数据:999
当前p指向的节点数据:15
当前p指向的节点数据:18
当前p指向的节点数据:15
当前p指向的节点数据:666
当前p指向的节点数据:777
当前p指向的节点数据:123
当前p指向的节点数据:11111111
============删除后的节点============
============修改后的节点============
当前p指向的节点数据:888
当前p指向的节点数据:999
当前p指向的节点数据:15
当前p指向的节点数据:18
当前p指向的节点数据:15
当前p指向的节点数据:666
当前p指向的节点数据:777
当前p指向的节点数据:234
当前p指向的节点数据:11111111
============修改后的节点============
*/