关于 双向不循环列表的创建、插入、删除、遍历、检索、销毁

双向循环链表公式

image

双向不循环链表代码

#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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/708874.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件设计原则—依赖倒转原则

高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。 简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。下面看一个例子来理解依赖倒转原则:组装电脑 现要组装一台电脑,需要配件cpu,硬盘,…

关于没有熔断降级导致服务重启问题

场景 1.k8s微服务触发重启 容器配置的健康检查采用actuator curl 127.0.0.1:8080/actuator/health 2.容器重启钩子回调curl -X POST http://127.0.0.1:8080/actuator/shutdown 最终原因是因为调用第三方服务,超时设置3秒,重试3次,三方服务挂起导致tomcat连接池占满,健康检查…

stm32 bootloader的app中断向量偏移设置,HAL库

如何设置Hal库的中断向量偏移看前几篇的 stm32f103c8t6 HAL库更改中断向量表(app部分) - 这一切足够了 - 博客园 (cnblogs.com)我这里bootloader的APP开始地址就是0x08006000,中断向量偏移0x00006000 设置完成之后编译mdk,将生成的bin文件使用ymodem写入0x08006000中 这里设…

c语言程序实验————实验报告九

c语言程序实验————实验报告九实验项目名称: 实验报告8 字符串处理函数 实验项目类型:验证性 实验日期:2024 年 5 月 16 日一、实验目的 1.掌握定义函数的方法 2.掌握函数调用、实参与形参的对应关系、参数的传递方式 3.掌握函数的嵌套调用和递归调用的方法 4.掌握全局变…

Flink精确消费一次

在大数据计算里面,计算引擎是处于承上启下的作用,对上承接数据源,对下承接各种各种数据库,比如mysql、oracle。对于任何数据计算来说要想精确消费一次,就需要支持事务或者幂等,我们最常见的支持事务的就是单点的oracle、mysql数据库,那么Flink作为分布式计算引擎,是如何…

电子传输系统安全-进展1

实验二 电子传输系统安全-进展1 上周任务完成情况完成了上学期电子公文传输系统的重新调试通过 部署了bouncycastle 学习了bouncycastle 将jar包添加到依赖项本周计划将上学期电子公文传输系统重新调试通过 部署bouncycastle 学习bouncycastle 将jar包添加到依赖项参考链接Boun…

【日记】被零食有鸣的工作人员轰出来了……(544 字)

正文今天全在睡觉。早上睡到十点起床,下午又从三点睡到五点,我愿称之为睡觉仙人…… 这就是上班的副作用吗……下午同事一个电话打过来,决定不接。周末同事来电话,准没好事。结果她微信发消息问,要不要出去走走,一个人有点闷。我都惊了,头一回。我还以为又要我做啥事儿呢…

d3d12龙书阅读----绘制几何体(上) 课后习题

d3d12龙书阅读----绘制几何体(上) 课后习题 练习1 完成相应的顶点结构体的输入-布局对象typedef struct D3D12_INPUT_ELEMENT_DESC{一个特定字符串将顶点结构体数组里面的顶点映射到顶点着色器的输入签名LPCSTR SemanticName;语义索引 如果语义名相同的话 使用索引进行区分UI…

SAP PS 打开关闭的项目

1 ) 编辑-状态-关闭-撤销 2) TECO 撤销: ) 编辑-状态-技术完成-撤销

stm32f103c8t6使用bootloader进行ymodem下载和app程序测试,部分总结(暂未测试中断向量偏移问题)

bootloader程序部分(功能测试)print_boot_message();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */uint8_t key_get_state;while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */key_get_state = get_key();switch(key_get_state){case 1: //…

夸克自动签到转存到emby

夸克自动签到不同于之前的阿里盘内夸克签到脚本,这里可以自动转存管理文件,添加到emby中 b站视频地址:https://www.bilibili.com/video/BV1ry411a7Lt 一、准备 你有服务器或者nas等等,有docker或者青龙都行。 由于nas在家关机了,我在外地。就不演示推到emby了。 来自于Cp0…

AI绘画拉取模型失败,DOS开启代理

我用了这么久的代理第一次知道DOS里面要开代理,惭愧惭愧。在我远程拉取模型的时候,挂科学也一直失败。在网上找报错找了很长时间没找到,最后经过一位群友的提示下,才知道问题出在DOS代理上面。直接看文章第一部分就行,要是直接tun不行,再看下面的直接开启tun这个是V2的开…