双向循环链表公式
双向不循环链表代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//宏定义一个数据域
#define DATA_LEN 60
//双向不循环链表的节点定义
typedef struct double_link_list
{
//数据域
char data[DATA_LEN]; // 数据域,存储数据长度
//指针域
struct double_link_list *next; //后继指针,指向下一个节点的指针
struct double_link_list *prev; //前驱指针,指向前一个节点的指针
}Double_Link_List, * P_Double; // 定义节点类型和指针类型别名
/* ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 函数声明文件 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */
P_Double Create_New_Node(); //声明一个创建新节点函数
P_Double Retrieve_Add_Node(P_Double head_node); //声明一个检索函数
int Mode_Select(P_Double head_node); //声明一个功能选择函数
int Head_Add_Node(P_Double head_node); //声明一个头插函数
int Ergodic_List_Node(P_Double head_node); //声明一个遍历函数
int Tail_Add_Node(P_Double head_node); //声明一个尾插函数
int Appoint_Add_Node(P_Double head_node); //声明一个指定添加函数
int Del_Add_Node(P_Double head_node); //声明一个指定删除函数
int Destory_Double_Link_list(P_Double head_node); //声明一个摧毁双向链表函数
/* ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 函数声明文件 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ */
// 定义一个函数Create_New_Node,来创建一个新节点
P_Double Create_New_Node()
{
//创建新节点并申请堆内存
P_Double new_node = (P_Double)malloc(sizeof(Double_Link_List));
//判断申请空间是否成功
if(new_node == (P_Double)NULL)
{
perror("malloc ...");
return (P_Double)-1;
}
//清空新节点的数据区域,进行初始化
memset(new_node,0,sizeof(Double_Link_List));
//新节点的指针指向空
new_node->next = (P_Double)NULL;
new_node->prev = (P_Double)NULL;
return new_node;//返回新节点
}
// 创建一个功能函数用来进行检测操作链表的插入、删除、遍历、移动、摧毁
int Mode_Select(P_Double head_node)
{
//判读头节点是否为空
if(head_node == (P_Double)NULL)
{
printf("头节点异常!\n");
return -1;
}
//定义变量,存放用户输入编号
int select_num;
//死循环,直到用户退出
while(1)
{
//显示菜单栏
printf("<<<< 1 头插添加数据节点 >>>>\n");
printf("<<<< 2 尾插添加数据节点 >>>>\n");
printf("<<<< 3 指定检索数据节点 >>>>\n");
printf("<<<< 4 指定添加数据节点 >>>>\n");
printf("<<<< 5 指定删除数据节点 >>>>\n");
printf("<<<< 6 遍历链表数据节点 >>>>\n");
printf("<<<< 7 摧毁双向不循环链表 >>>>\n");
//获取用户输入指令
scanf("%d",&select_num);
switch (select_num)
{
case 1:Head_Add_Node(head_node);break; // 头插法添加数据节点
case 2:Tail_Add_Node(head_node);break; // 尾插法添加数据节点
case 3:Retrieve_Add_Node(head_node);break; // 检索目标数据节点并返回
case 4:Appoint_Add_Node(head_node);break; // 目标位置添加数据节点
case 5:Del_Add_Node(head_node);break; // 指定位置删除节点
case 6:Ergodic_List_Node(head_node);break; // 遍历整个链表并输出显示
case 7:Destory_Double_Link_list(head_node);return 0; // 销毁双向不循环链表
default:printf("没有此项指令,请重新输入!\n");break;
}
}
return 0;
}
// 定义函数 Head_Add_Node,用于在双向不循环链表中头部位置插入节点
int Head_Add_Node(P_Double head_node)
{
//判断头节点是否异常
if(head_node == (P_Double)NULL)
{
printf("头节点异常!\n");
return -1;
}
//创建新节点
P_Double new_node = Create_New_Node();
if(new_node == (P_Double)NULL)
{
printf("创建新节点失败!\n");
return -1;
}
//输入要插入的节点的数据
printf("输入头插数据节点:");
scanf("%s",new_node->data);
while(getchar()!='\n'); //清空输入缓存区
//判断空链表第一次插入节点
if(head_node->next == NULL)
{
head_node->next = new_node; //头节点的下一个指针指向新节点
new_node->prev = head_node; //新节点的上一个前驱指针为头节点
}
//非空情况下
else
{
P_Double second_node = head_node->next; // 定义一个指向第二个节点的指针
new_node->prev = head_node; // 新节点的前驱指向头节点
head_node->next = new_node; // 头节点的后继指向新节点
new_node->next = second_node; // 新节点的后继指向原来第二个节点
second_node->prev = new_node; // 原来第二个节点的前驱指向新节点
}
printf("头插成功!数据:%s---地址:%p\n",new_node->data,new_node);
return 0;
}
//定义函数 Tail_Add_Node,用于在双向不循环链表中尾部位置删除节点
int Tail_Add_Node(P_Double head_node)
{
//判断头节点是否异常
if(head_node == (P_Double)NULL)
{
printf("头节点异常!\n");
return -1;
}
//创建新节点
P_Double new_node = Create_New_Node();
if(new_node == (P_Double)NULL)
{
printf("创建新节点失败");
return -1;
}
//输入尾插数据
printf("输入尾插数据:");
scanf("%s",new_node->data);
//清空输入缓存区
while (getchar()!='\n');
//进行尾插
//定义一个尾插节点,遍历整个双向不循环链表,找到尾节点
P_Double end_node;
for(end_node = head_node; end_node->next !=NULL; end_node = end_node->next);
//尾插
end_node->next = new_node; //尾节点的下一个节点为新节点
end_node = new_node->prev; //新节点的前驱指针指向尾节点
printf("尾插成功!数据:%s---地址:%p\n",new_node->data,new_node);
return 0;
}
//定义函数 Reterieve_Add_Node,用于在双向不循环链表中找到目标节点
P_Double Retrieve_Add_Node(P_Double head_node)
{
//判断头节点是否异常
if(head_node ==(P_Double)NULL)
{
printf("头节点异常!\n");
return (P_Double)-1;
}
//判断链表是否为空
else if(head_node->next == (P_Double)NULL)
{
printf("空链表,无需检索!\n");
return (P_Double)0;
}
else
{
//创建检索的目标数据,并初始化
printf("输入检索的数据:");
char obj_data[DATA_LEN] = "\0";
scanf("%s",obj_data);
//创建临时节点变量,遍历整个链表
for(P_Double tmp_node = head_node->next; tmp_node != NULL; tmp_node = tmp_node->next)
{
//判断是否与输入的目标节点匹配
if(strcmp(tmp_node->data,obj_data)== 0)
{
printf("找到目标节点!数据:%s---地址:%p\n",tmp_node->data,tmp_node);
return tmp_node;
}
}
}
printf("未找到目标节点,重新输入!\n");
return (P_Double)0;
}
//定义函数 Appoint_Add_Node,用于在双向不循环链表中指定添加目标节点
int Appoint_Add_Node(P_Double head_node)
{
//判断链表是否异常
if(head_node == (P_Double)NULL)
{
printf("链表异常,无法添加!\n");
return -1;
}
//判断链表是否为空
else if (head_node->next == NULL)
{
printf("空链表,默认尾插!\n");
if(Tail_Add_Node(head_node) == -1)
{
printf("尾插失败!\n");
return -1;
}
}
else
{
//创建插入目标节点
P_Double obj_node = Retrieve_Add_Node(head_node);
if(obj_node == (P_Double)-1)
{
printf("链表异常,创建目标节点失败!\n");
return -1;
}
else if(obj_node == (P_Double)0)
{
printf("未找到目标节点,重新输入!\n");
return 0;
}
else
{
//创建带插入的新节点
P_Double new_node = Create_New_Node(head_node);
if(new_node == (P_Double)NULL)
{
printf("创建新节点失败!\n");
return -1;
}
printf("输入插入数据:");
scanf("%s",new_node->data);
while(getchar()!='\n');//清空输入缓存区
//判断目标节点的指针的状态
//目标节点为尾节点
if(obj_node->next == NULL)
{
obj_node->next = new_node; //目标节点的下一个指针指向新节点
new_node->prev = obj_node; //新节点的前驱指针指向目标节点
}
else
{
new_node->next = obj_node->next; //新节点的下一个指向目标节点的下一个
obj_node->next->prev = new_node; //新节点的下一个的上一个指向新节点
new_node->prev = obj_node; //新节点的前驱指向目标节点
obj_node->next = new_node; //目标节点的下一个指向新节点
}
printf("指定位置插入成功!数据:%s---地址:%p\n",new_node->data,new_node);
}
}
return 0;
}
// 定义函数 Del_Add_Node,用于删除双向不循环链表中的指定节点
int Del_Add_Node(P_Double head_node)
{
//判断链表是否异常
if(head_node == (P_Double)NULL)
{
printf("链表异常,无法进行删除操作!\n");
return -1;
}
//判断链表是否为空
else if(head_node->next == (P_Double)NULL)
{
printf("空链表,无需删除!\n");
return 0;
}
else
{
//创建待删除的节点
P_Double del_node = Retrieve_Add_Node(head_node);
if(del_node == (P_Double)-1)
{
printf("链表异常,无法删除!\n");
return -1;
}
else if(del_node == (P_Double)0)
{
printf("无此数据,重新输入!\n");
return 0;
}
else
{
//判断删除状态
if(del_node->next == NULL)
{
//del_node是尾节点
del_node->prev->next = NULL; //待删除节点的前一个节点的后继指针指向空
del_node->prev = NULL; //待删除节点的前驱指针指向空
}
else
{
//del_node不是尾节点
del_node->next->prev = del_node->prev; // 将待删除节点的后继节点的前驱指针指向待删除节点的前驱节点
del_node->prev->next = del_node->next; // 将待删除节点的前驱节点的后继指针指向待删除节点的后继节点
del_node->next = NULL; // 将待删除节点的后继指针置为空
del_node->prev = NULL; // 将待删除节点的前驱指针置为空
}
printf("删除成功!\n");
free(del_node);
}
}
return 0;
}
// 定义函数 Ergodic_List_Node,用于遍历双向不循环链表并在用户终端显示
int Ergodic_List_Node(P_Double head_node)
{
//判断头节点是否异常
if(head_node == (P_Double)NULL)
{
printf("头节点异常,无法遍历!");
return -1;
}
//判断是否是空链表
else if(head_node->next == NULL)
{
printf("空链表,无需遍历!\n");
return -1;
}
else
{
//创建临时节点变量,遍历整个链表
printf("-------------------------------------------------------------------------------------\n");
for(P_Double tmp_node = head_node->next; tmp_node != NULL; tmp_node = tmp_node->next)
{
printf("输出遍历的数据:%s----地址:%p\n",tmp_node->data,tmp_node);
}
printf("-------------------------------------------------------------------------------------\n");
}
return 0;
}
// 定义函数 Destroy_Double_Link_list,用于销毁双向不循环链表
int Destory_Double_Link_list(P_Double head_node)
{
// 检查头节点是否异常
if(head_node == (P_Double)NULL)
{
printf("头节点异常!\n");
return -1; // 返回异常值
}
// 检查链表是否为空链表,为空直接释放头节点!
else if(head_node->next == NULL)
{
printf("该链表为空链表,直接释放头节点!\n");
free(head_node);
}
else
{
//定义计数器,记录销毁节点的数量
int sum = 0;
P_Double free_node; //用于临时存放被释放的节点
//循环遍历直到链表末尾
while(head_node->next != NULL)
{
free_node = head_node->next; //将头节点的下一个节点作为被释放的第一个节点
//删除最后后一个
if(free_node->next == NULL)
{
//del_node是尾节点
free_node->prev->next = NULL; //待删除节点的前一个节点的后继指针指向空
free_node->prev = NULL; //待删除节点的前驱指针指向空
printf("摧毁第%d个节点\n",sum);
}
else
{
//更行指针指向,完成节点释放
free_node->next->prev = free_node->prev; //待释放节点的后继节点的前驱指针指向待释放节点的前驱节点
free_node->prev->next = free_node->next; //待释放节点的前驱节点的后继指针指向待释放节点的后继节点
free_node->next = NULL; //待释放节点的后继指针指向空
free_node->prev = NULL; //待释放节点的前驱指针指向空
printf("摧毁第%d个节点\n",sum);
sum++;
}
free(free_node);//释放节点
}
free(head_node);//释放头节点
printf("最后释放头节点!\n");
}
return 0;
}
int main()
{
//创建头节点
P_Double head_node = Create_New_Node();
if(head_node == (P_Double)-1)
{
printf("双向不循环链表创建失败!\n");
return -1;
}
else
{
printf("双向不循环链表创建成功!\n");
}
//选择功能函数
Mode_Select(head_node);
return 0;
}
标签:检索,node,head,遍历,Double,链表,销毁,printf,节点
From: https://www.cnblogs.com/zhengdianshutiao-blogs/p/18200588