双向循环链表公式
双向不循环链表代码
#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;
}