上一篇单链表博主已经讲的很详细了,相信掌握单链表的朋友搞定双链表并不困难,所以博主就之给出代码了,如果实在感觉理解困难可以留言,博主会加gif的

#include<stdio.h>
#include<stdlib.h>// 实现单链表的构建、数据添加(头插法和尾插法)、数据删除(包含了数据查找),
//数据的修改(包含了数据查找)、遍历的算法设计;typedef struct _LinkDouble {int data;   //双向链表的数据域int length;   //表示现在双向链表的元素个数_LinkDouble *next;   //指向下一节点的指针域_LinkDouble *pre;   //指向上一节点的指针域 (头结点的 pre为空!) 所以我们初始化的时候做好即可,避免很多意外的错误.
}LinkDouble, LinkNode;//显示欢迎界面
void menue() {printf("****************************************************************\n");printf("*********请选择你要进入的模块*********\n");printf("**1.使用头插法添加元素(最后输出的顺序与输入的顺序是相反的!**\n");printf("-----------------------------------\n");printf("**2.使用尾插法添加元素(最后输出的顺序与输入的顺序是相同的!**\n");printf("-----------------------------------\n");printf("**3.删除双向链表链表中的元素\n");printf("-----------------------------------\n");printf("**4.修改双向链表链表中的元素\n");printf("-----------------------------------\n");printf("**5.清屏,再次显示欢迎界面\n");printf("-----------------------------------\n");printf("**0.退出程序");printf("****************************************************************\n\n\n");
}//初始化双向链表
bool inin_doubleLink(LinkDouble *Lq) {if (!Lq)  return false;   //表示分配空间失败! 所以我们直接返回//初始化指针域 都置为 NULL 是为了避免意外的错误Lq->next = NULL;Lq->pre = NULL;//初始化数据域Lq->length = 0;Lq->data = 0;return true;
}//使用头插法插入元素
bool insert_front(LinkDouble *Lq, LinkNode *node) {if (!node)   return false;   //如果node结点分配的空间失败了,那么就没必要执行后续的步骤了//双向链表和单链表的区别在这里就能体现了,双向链表前插时需要判断一下是否是只有头结点if (Lq->next == NULL) {    //如果整个链表只有一个头结点,我们就进行下面的操作//完成我们的连接操作node->next = Lq->next;node->pre = Lq;Lq->next = node;Lq->length++;} else {node->next = Lq->next;    //指向之前 Lq 指向的结点node->pre = Lq;  //指向 Lq;Lq->next->pre = node;    //让之前Lq指向的结点现在指向我们的nodeLq->next = node; //让 Lq 指向我们的 nodeLq->length++; //让整个链表的长度加一,代表我们插入了一个元素}
}//尾插法
bool insert_last(LinkDouble *Lq, LinkNode *node) {if (!node) return false;  //如果 node 分配空间失败!! 那么就没有必要执行后面的操作 了LinkNode *last = Lq;    //这个用来遍历寻找我们的最后一个节点while (last->next) last = last->next; //跳出循环时,我们其实就已经找到了最后一个节点//开始连接node->next = NULL;last->next = node;node->pre = last;Lq->length++;   //元素长度加一return true;}//遍历
void Print_double(LinkDouble *Lq) {LinkNode *temp = Lq->next;   //代替Lq去遍历printf("现在双向链表的元素有----%d个----依次是 : ", Lq->length);while (temp) {  //跳出循环时就代表我们的遍历完成了printf(" %d ", temp->data);temp = temp->next;    //这个节点遍历完成,我们继续指向下一个节点}printf("\n");}//删除
bool Del_double(LinkDouble *Lq, int element, int *index) {//双向链表的删除不同于单项链表,我们只需要定义一个代替结点来操作即可(双向链表需要两个)LinkNode *temp = Lq->next;   //指向我们的第一个节点if (Lq->next == NULL) return false;    //如果双向链表只有一个头节点,我们没必要执行后面的操作了int i = 0;while (temp) {  //跳出循环时,要么是便利了整个链表都没找到要删除的值,要么就是删除了并返回索引值.if (temp->data == element && temp->next == NULL) {//删除的元素是最后一个结点temp->pre->next = NULL;  //直接把删除结点的上一个点的的指向为空这样就断开了链接//释放我们要删除的结点free(temp);temp->next = NULL;temp->pre = NULL;Lq->length--;  //元素减一*index = i;  //更改索引值return true;} else if (temp->data == element) {//删除的不是最后一个元素//下面两步其实就分离了我们的 temp 了,只是 temp还有所指向而已,等我们释放 temp时置空就行temp->pre->next = temp->next;    //删除结点的前一个节点指向删除结点的后一个节点temp->next->pre = temp->pre;      //删除结点的后一个节点指向删除元素的前一个节点//释放我们要删除的结点free(temp);temp->next = NULL;temp->pre = NULL;Lq->length--;  //元素减一*index = i;  //更改索引值return true;} else {//没找到temp = temp->next;  //指向下一个i++;}}return false;
}
//修改
bool mov_double(LinkDouble *Lq, int element, int new_element) {LinkNode *temp = Lq->next;   //定义一个代替 Lq 去遍历的临时结点 while (temp) { //跳出循环时要么是整个双向链表都没有我们要修改的值,要么是修改完成之后的值if (temp->data == element) {temp->data = new_element;return true;} else {temp = temp->next;  //没找到就继续遍历下面的结点}}return false;
}int main(void) {//定义双向链表的头结点和我们到时候要插入或删除的结点LinkDouble *Lq = (LinkDouble*)malloc(sizeof(LinkDouble));LinkNode *node = NULL;int num = 0;  //要插入或删除的元素的个数int element = 0;     //要删除或修改 的元素的值int new_element = 0; //要修改成为的元素int index = 0;   //返回索引值int choice = 0; //用户要进入的模块//初始化双向链表if (inin_doubleLink(Lq)) {printf("分配空间成功! \n");} else {printf("分配空间失败! 退出程序\n");system("pause");return 0;}menue(); //显示欢迎界面while (1) {printf("请选择你想要进入的模块: ");scanf("%d", &choice);switch (choice) {case 0:printf("期待您的下次使用\n");printf("                   正在退出程序...             \n");_sleep(3000);system("cls");printf("                   退出程序成功...            \n ");system("pause");return 0;case 1:printf("欢迎使用 头插法插入元素!! 请输入你想要添加的元素个数:  ");scanf("%d", &num);for (int i = 0; i < num; i++) {node = (LinkNode*)malloc(sizeof(LinkNode)); //因为要 连接起来 所以每次循环的时候我们都需要分配一个空间printf("请输入你想要插入的元素的值");scanf("%d", &node->data);if (insert_front(Lq, node)) {printf("插入元素 %d 成功, 现在的元素个数是 %d 个哟\n", node->data, Lq->length);} else {printf("插入元素失败! \n");}}Print_double(Lq);break;case 2:printf("欢迎使用 尾插法插入元素!! 请输入你想要添加的元素个数:  ");scanf("%d", &num);for (int i = 0; i < num; i++) {node = (LinkNode*)malloc(sizeof(LinkNode)); //因为要 连接起来 所以每次循环的时候我们都需要分配一个空间printf("请输入你想要插入的元素的值");scanf("%d", &node->data);if (insert_last(Lq, node)) {printf("插入元素 %d 成功, 现在的元素个数是 %d 个哟\n", node->data, Lq->length);} else {printf("插入元素失败! \n");}}Print_double(Lq);break;case 3:printf("请输入你要删除的元素: ");scanf("%d", &element);if (Del_double(Lq, element, &index)) {printf("---------------------\n");printf("删除元素 %d 成功, 它曾经是双向链表中第 %d 个元素\n", element, index + 1);printf("---------------------\n");} else {printf("删除元素失败, 双向链表中不存在该元素! \n");}Print_double(Lq);break;case 4:printf("请输入你想要修改的元素 : ");scanf("%d", &element);printf("请输入要改为的值 :  ");scanf("%d", &new_element);if (mov_double(Lq, element, new_element)) {printf("---------------------\n");printf("修改元素 %d 成功\n", element);printf("---------------------\n");} else {printf("修改元素失败, 双向链表中不存在该元素! \n");}Print_double(Lq);break;case 5:system("cls");    //将屏幕清空 menue();    //显示欢迎界面,方便用户操作Print_double(Lq);    //显示现在单链表内的元素,方便用户观看break;default:printf("输入有误,请重新输入!\n");}}free(Lq);free(node);Lq->next = NULL;Lq->pre = NULL;node->next = NULL;node->pre = NULL;system("pause");return 0;
}

数据结构与算法 完整版双链表相关推荐

  1. 数据结构与算法 完整版单链表(附GIF)

    因为博主认为单链表是非常重要的数据结构,能够熟练使用单链表的话后面的数据结构会越学越轻松,所以博主就把这篇博客做的细致一点,不是很好懂的地方做成 gif 动画,希望大家能理解期中代码的含义 学习链表的 ...

  2. C++数据结构和算法2 栈 双端/队列 冒泡选择插入归并快排 二三分查找 二叉树 二叉搜索树 贪婪 分治 动态规划

    C++数据结构和算法2 栈 双端/队列 冒泡选择插入归并快排 二三分查找 二叉树 二叉搜索树 贪婪 分治 动态规划 博文末尾支持二维码赞赏哦 _ github 章3 Stack栈 和 队列Queue= ...

  3. 数据结构与算法(C++)– 链表(Link)

    数据结构与算法(C++)– 链表(Link) 1.基础知识 表:把具有相同类型的序列 A0, A1, A2, - An 称为表 .n 是表的大小,n=0 称为空表. A0没有前驱,An没有后继. 前驱 ...

  4. 数据结构与算法之反转单向链表和双向链表

    数据结构与算法之反转单向链表和双向链表 目录 反转单向链表和双向链表 1. 反转单向链表和双向链表 题目描述 代码实现 public class Code_ReverseList {public st ...

  5. C4.5决策树生成算法完整版(Python),连续属性的离散化, 缺失样本的添加权重处理, 算法缺陷的修正, 代码等

    C4.5决策树生成算法完整版(Python) 转载请注明出处:©️ Sylvan Ding ID3算法实验 决策树从一组无次序.无规则的事例中推理出决策树表示的分类规则,采用自顶向下的递归方式,在决策 ...

  6. 机器学习笔记——支持向量机SMO算法完整版代码分析

    机器学习笔记--支持向量机SMO算法完整版代码分析 代码大体分析 外循环 参数类 内循环 KKT条件判断 eCache参数 完整SMO代码 添加核函数代码 代码参考书籍:<机器学习实战> ...

  7. 数据结构与算法之线性结构链表

    数据结构与算法之线性结构链表 这一篇文章主要介绍的是通过java实现单链表.循环链表和双向循环链表,仅供自己复习使用,如有什么不足之处,欢迎指出. 单链表: package xianxingjiego ...

  8. 【python】数据结构和算法 + 浅谈单链表与双链表的区别

    有这么一句话说"程序=数据结构+算法",也有人说"如果把编程比作做菜,那么数据结构就好比食材(菜),算法就好比厨艺(做菜的技巧)". 当然这是笼统的说法,不过也 ...

  9. 408考研数据结构与算法之数组、链表、队列、栈知识点和算法详细教程(更新中)

    第一章:数据结构与算法概述 因为数据结构作为计算机专业的专业基础课程,是计算机考研的必考科目之一,如果打算报考计算机专业的研究生,你必须学好它. 数据结构是计算机软考.计算机等级考试等相关考试的必考内 ...

最新文章

  1. ibm刀片服务器虚拟化,IBM POWER刀片服务器的虚拟化解决方案v1.3.ppt
  2. 60分钟入门深度学习工具PyTorch
  3. JetsonTX2上安装tensorflow的心酸史
  4. jdbc连接oracle rac服务器
  5. [转载+原创]Emgu CV on C# (五) —— Emgu CV on 局部自适应阈值二值化
  6. android bitmap上传服务器,Android 上传图片到服务器时将bitmap转换为byte[]最后转换为String...
  7. Windows界面编程-背景图片、透明特效使用
  8. 一款实用的前端截图工具
  9. OC(Open collector) 集电极开路
  10. 如何编写高性能的C#代码(四)字符串的另类骚操作
  11. 不得不看之跳槽加薪利器:2019需求最旺盛的十大IT技能
  12. JavaMail(四):接收邮件
  13. MySQL笔记-死锁原理与分析及InnoDB中如何减少死锁
  14. python的一些问题解决方法
  15. iOS开发之UI控件阴影效果
  16. Mac配置腾讯云服务器SSH秘钥免登陆
  17. 如何根据地理位置获取城市编码 / (高德地图) 获取城市编码API / 经纬度获取城市or城市编码
  18. 在华为做测试员是一种什么体验?带你深入了解华为
  19. 安装Mathtype之后,打开word出现错误的解决方法
  20. kettle-java代码执行hive相关ktr时报错: database type with plugin id [HIVE2] couldn‘t be found!

热门文章

  1. select、poll和epoll的总结对比
  2. Flutter进阶—质感设计之表单输入
  3. 中国摊铺机(车辆)市场趋势报告、技术动态创新及市场预测
  4. 2021-2025年中国制革机械行业市场供需与战略研究报告
  5. linux进程管理内存管理,Linux专业知识四:Linux系统进程管理及查看内存
  6. “我想再当一次 CEO,所以我离开了 IBM。”
  7. 技术人的年货福利:百宝黑皮书在手,2020年技术栈变革一次看透 | 免费下载
  8. 教育行业 A 股 IPO 第一股,如何做成程序员培训这门生意 | 极客头条
  9. 历时3个月,我们是如何为一个开源项目集资300万美元的?
  10. 小白也能看懂的 Java 异常处理