【数据结构】双向循环链表的使用

双向循环链表的使用

  • 1.双向循环链表节点设计
  • 2.初始化双向循环链表-->定义结构体变量 创建头节点
    • (1)示例代码:
    • (2)图示
  • 3.双向循环链表节点头插
    • (1)示例代码:
    • (2)图示
  • 4.双向循环链表节点尾插
    • (1)示例代码:
    • (2)图示
  • 5.双向循环链表节点中间插入
    • (1)示例代码:
    • (2)图示
  • 6.双向循环链表删除节点
    • (1)示例代码:
    • (2)图示
  • 7.双向循环链表修改节点数据
    • (1)示例代码:
  • 8.双向循环链表遍历
  • 9.完整示例代码

1.双向循环链表节点设计

typedef struct double_list{int data;struct double_list *next;struct double_list *prev;
}double_list_t;

2.初始化双向循环链表–>定义结构体变量 创建头节点

(1)示例代码:

double_list_t *double_list_init()
{double_list_t *head_node = malloc(sizeof(double_list_t));if (head_node != NULL){head_node->next = head_node;head_node->prev = head_node;}else{printf("[double_list_init]申请头节点失败\n");}return head_node;
}

(2)图示

在这里插入图片描述

3.双向循环链表节点头插

(1)示例代码:

int insert_list_head(int newdata, double_list_t *list)
{// 申请一个节点 -堆空间double_list_t *new_node = malloc(sizeof(double_list_t));if (new_node == NULL) {printf("[insert_list_head]申请新的节点失败\n");return -1; // 申请内存失败}// 初始化数据域new_node->data = newdata;new_node->next = NULL;new_node->prev = NULL;// 当链表为空时if (list->next == list){list->next = new_node;new_node->next = list;new_node->prev = list;list->prev = new_node;// printf("[insert_list_head]当链表为空时\n");}// 链表不为空时else{// 插入节点new_node->next = list->next;list->next = new_node;new_node->next->prev = new_node;new_node->prev = list;// printf("[insert_list_head]当链表不为空时\n");}return 0;
}

(2)图示

在这里插入图片描述
在这里插入图片描述

4.双向循环链表节点尾插

(1)示例代码:

int insert_list_tail(int newdata, double_list_t *list)
{// 申请一个节点 -堆空间double_list_t *new_node = malloc(sizeof(double_list_t));if (new_node == NULL) {printf("[insert_list_tail]申请新的节点失败\n");return -1; // 申请内存失败}// 初始化数据域new_node->data = newdata;new_node->next = NULL;new_node->prev = NULL;// 定义指针p去找到链表的尾部double_list_t *p = list;while (p->next != list){p = p->next;}// 此时p已经到最后一个节点的位置new_node->next = list;p->next = new_node;list->prev = new_node;new_node->prev = p;return 0;
}

(2)图示

在这里插入图片描述

5.双向循环链表节点中间插入

(1)示例代码:

int insert_list_mid(int olddata, int newdata, double_list_t *list)
{// 找到要插入的节点double_list_t *p = list;while (p->next != list){p = p->next;if (p->data == olddata){break;}}// 申请一个新的节点 -堆空间double_list_t *new_node = malloc(sizeof(double_list_t));// 初始化数据域new_node->data = newdata;new_node->next = NULL;new_node->prev = NULL;// p指向最后一个节点if (p->next == list){// 如果最后一个节点是要插入的数据if (p->data == olddata){new_node->next = p->next; p->next = new_node;  new_node->prev = p;}else{printf("[insert_list_mid]要插入的数据不存在\n");return -1;}}else // 遍历到中间找到需要插入的节点{new_node->next = p->next; p->next = new_node;   new_node->prev = p;   new_node->next->prev = new_node;}return 0;
}

(2)图示

在这里插入图片描述

6.双向循环链表删除节点

(1)示例代码:

int list_delnode(int deldata, double_list_t *list)
{// p指向链表的头节点double_list_t *p = list;while (p->next != list){// 找到要删除的节点并进行删除if (p->data == deldata){p->prev->next = p->next;     p->next->prev = p->prev;double_list_t *temp = p->next; // 将temp指针指向p的下一个节点 p->next = NULL;p->prev = NULL;free(p);    // 释放p后此时p是野指针p = temp;   // p往后移动}else{p = p->next;}  }// 遍历到最后一个节点if (p->next == list){// 若最后一个节点是要删除的节点,则删除if (p->data == deldata){p->prev->next = list;p->next = NULL;list->prev = p->prev;p->prev = NULL;free(p);}else{printf("[list_delnode]最后一个节点不是要删除的节点\n");return 0;}}
}

(2)图示

在这里插入图片描述
在这里插入图片描述

7.双向循环链表修改节点数据

(1)示例代码:

int list_update_node(int old_data, int new_data, double_list_t *list)
{double_list_t *p = list;while (p->next != list){p = p->next;  // p往后移动if (p->data == old_data){p->data = new_data;}}return 0;
}

8.双向循环链表遍历

int list_show(double_list_t *list)
{double_list_t *p = list; //p指向头结点while (p->next != list){p = p->next;printf("[list_show]当前p指向的节点数据:%d\n", p->data);}
}

9.完整示例代码

#include <stdio.h>
#include <stdlib.h>// 1.封装一个结构体来表示双向循环链表
typedef struct double_list{int data;struct double_list *next;struct double_list *prev;
}double_list_t;// 2.初始化双向循环链表-->定义结构体变量 创建头节点
double_list_t *double_list_init()
{double_list_t *head_node = malloc(sizeof(double_list_t));if (head_node != NULL){head_node->next = head_node;head_node->prev = head_node;}else{printf("[double_list_init]申请头节点失败\n");}return head_node;
}// 头插
int insert_list_head(int newdata, double_list_t *list)
{// 申请一个节点 -堆空间double_list_t *new_node = malloc(sizeof(double_list_t));if (new_node == NULL) {printf("[insert_list_head]申请新的节点失败\n");return -1; // 申请内存失败}// 初始化数据域new_node->data = newdata;new_node->next = NULL;new_node->prev = NULL;// 当链表为空时if (list->next == list){list->next = new_node;new_node->next = list;new_node->prev = list;list->prev = new_node;// printf("[insert_list_head]当链表为空时\n");}// 链表不为空时else{// 插入节点new_node->next = list->next;list->next = new_node;new_node->next->prev = new_node;new_node->prev = list;// printf("[insert_list_head]当链表不为空时\n");}return 0;
}
/*@brief:3.插入数据-->尾插(在最后一个有效成员的后面插入数据)*@param(in):  newdata :待插入的数据  list:链表头节点*@param(out):  *@retval:    
*/
int insert_list_tail(int newdata, double_list_t *list)
{// 申请一个节点 -堆空间double_list_t *new_node = malloc(sizeof(double_list_t));if (new_node == NULL) {printf("[insert_list_tail]申请新的节点失败\n");return -1; // 申请内存失败}// 初始化数据域new_node->data = newdata;new_node->next = NULL;new_node->prev = NULL;// 定义指针p去找到链表的尾部double_list_t *p = list;while (p->next != list){p = p->next;}// 此时p已经到最后一个节点的位置new_node->next = list;p->next = new_node;list->prev = new_node;new_node->prev = p;return 0;
}// 节点中间插入链表
int insert_list_mid(int olddata, int newdata, double_list_t *list)
{// 找到要插入的节点double_list_t *p = list;while (p->next != list){p = p->next;if (p->data == olddata){break;}}// 申请一个新的节点 -堆空间double_list_t *new_node = malloc(sizeof(double_list_t));// 初始化数据域new_node->data = newdata;new_node->next = NULL;new_node->prev = NULL;// p指向最后一个节点if (p->next == list){// 如果最后一个节点是要插入的数据if (p->data == olddata){new_node->next = p->next; p->next = new_node;  new_node->prev = p;}else{printf("[insert_list_mid]要插入的数据不存在\n");return -1;}}else // 遍历到中间找到需要插入的节点{new_node->next = p->next; p->next = new_node;   new_node->prev = p;   new_node->next->prev = new_node;}return 0;
}
// 删除节点
int list_delnode(int deldata, double_list_t *list)
{// p指向链表的头节点double_list_t *p = list;while (p->next != list){// 找到要删除的节点并进行删除if (p->data == deldata){p->prev->next = p->next;     p->next->prev = p->prev;double_list_t *temp = p->next; // 将temp指针指向p的下一个节点 p->next = NULL;p->prev = NULL;free(p);    // 释放p后此时p是野指针p = temp;   // p往后移动}else{p = p->next;}  }// 遍历到最后一个节点if (p->next == list){// 若最后一个节点是要删除的节点,则删除if (p->data == deldata){p->prev->next = list;p->next = NULL;list->prev = p->prev;p->prev = NULL;free(p);}else{printf("[list_delnode]最后一个节点不是要删除的节点\n");return 0;}}
}
// 修改节点
int list_update_node(int old_data, int new_data, double_list_t *list)
{double_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(double_list_t *list)
{double_list_t *p = list; //p指向头结点while (p->next != list){p = p->next;printf("[list_show]当前p指向的节点数据:%d\n", p->data);}
}int main(int argc, char const *argv[])
{// 初始化单链表 ,指向链表的头节点double_list_t *my_list_head = double_list_init();// 往链表插入数据insert_list_head(2, my_list_head);insert_list_head(3, my_list_head);insert_list_head(4, my_list_head);insert_list_tail(15, my_list_head);insert_list_tail(16, my_list_head);insert_list_tail(17, my_list_head);insert_list_head(2, my_list_head);insert_list_tail(15, my_list_head);insert_list_tail(15, my_list_head);insert_list_tail(15, my_list_head);insert_list_mid(5, 6, my_list_head);insert_list_mid(2, 88, my_list_head);insert_list_mid(17, 15, my_list_head);printf("============插入的节点============\n");list_show(my_list_head);printf("============插入的节点============\n");// 删除节点list_delnode(25, my_list_head);list_delnode(15, my_list_head);list_delnode(2, my_list_head);printf("============删除后的节点============\n");list_show(my_list_head); // 打印数据printf("============删除后的节点============\n");// 修改数据list_update_node(16, 116, my_list_head);printf("============修改后的节点============\n");list_show(my_list_head); // 打印数据printf("============修改后的节点============\n");return 0;
}
/*
执行结果:
[insert_list_mid]要插入的数据不存在
============插入的节点============
[list_show]当前p指向的节点数据:2
[list_show]当前p指向的节点数据:88
[list_show]当前p指向的节点数据:4
[list_show]当前p指向的节点数据:3
[list_show]当前p指向的节点数据:2
[list_show]当前p指向的节点数据:15
[list_show]当前p指向的节点数据:16
[list_show]当前p指向的节点数据:17
[list_show]当前p指向的节点数据:15
[list_show]当前p指向的节点数据:15
[list_show]当前p指向的节点数据:15
[list_show]当前p指向的节点数据:15
============插入的节点============
[list_delnode]最后一个节点不是要删除的节点
[list_delnode]最后一个节点不是要删除的节点
============删除后的节点============
[list_show]当前p指向的节点数据:88
[list_show]当前p指向的节点数据:4
[list_show]当前p指向的节点数据:3
[list_show]当前p指向的节点数据:16
[list_show]当前p指向的节点数据:17
============删除后的节点============
============修改后的节点============
[list_show]当前p指向的节点数据:88
[list_show]当前p指向的节点数据:4
[list_show]当前p指向的节点数据:3
[list_show]当前p指向的节点数据:116
[list_show]当前p指向的节点数据:17
============修改后的节点============
*/

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

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

相关文章

【深度学习】卷积网络代码实战ResNet

ResNet (Residual Network) 是由微软研究院的何凯明等人在2015年提出的一种深度卷积神经网络结构。ResNet的设计目标是解决深层网络训练中的梯度消失和梯度爆炸问题&#xff0c;进一步提高网络的表现。下面是一个ResNet模型实现&#xff0c;使用PyTorch框架来展示如何实现基本的…

【51项目】51单片机自制小霸王游戏机

视频演示效果&#xff1a; 纳新作品——小霸王游戏机 目录&#xff1a; 目录 视频演示效果&#xff1a; 目录&#xff1a; 前言&#xff1a; 一、连接方式&#xff1a; 1.1 控制引脚 1.2. 显示模块 1.3. 定时器 1.4. 游戏逻辑与硬件结合 1.5. 中断处理 二、源码分析&#xff1a…

2024/12/29 黄冈师范学院计算机学院网络工程《路由期末复习作业一》

一、选择题 1.某公司为其一些远程小站点预留了网段 172.29.100.0/26&#xff0c;每一个站点有10个IP设备接到网络&#xff0c;下面那个VLSM掩码能够为该需求提供最小数量的主机数目 &#xff08; &#xff09; A./27 B./28 C./29 D./30 -首先审题我们需要搞清楚站点与网…

【OpenCV】使用Python和OpenCV实现火焰检测

1、 项目源码和结构&#xff08;转&#xff09; https://github.com/mushfiq1998/fire-detection-python-opencv 2、 运行环境 # 安装playsound&#xff1a;用于播放报警声音 pip install playsound # 安装opencv-python&#xff1a;cv2用于图像和视频处理&#xff0c;特别是…

Vue2: table加载树形数据的踩坑记录

table中需要加载树形数据,如图: 官网给了两个例子,且每个例子中的tree-props都是这么写的: :tree-props="{children: children, hasChildren: hasChildren}" 给我一种错觉,以为数据结构中要同时指定children和hasChildren字段,然而,在非懒加载模式下,数据结…

深度学习模型预测值集中在某一个值

深度学习模型&#xff0c;训练过程中&#xff0c;经常遇到预测的结果集中在某个值&#xff0c;而且在学习的过程中会变&#xff0c;样例如下。 主要有如下解决方案 1、更换relu ->tanh 或者其他激活函数 2、更改随机种子&#xff0c;估计是没有初始化好&#xff0c;或者调…

图书项目:整合SSM

步骤&#xff1a; pom文件&#xff1a;导包&#xff0c;写入静态资源导出配置&#xff0c;连接数据库 建包&#xff1a;controller dao/mapper pojo service 配置文件&#xff1a;mybatis-config.xml applicationContext.xml&#xff08;Spring的配置文件&#xff09; datab…

javacript中function (res) {}与箭头函数表达式(res) =>{}的区别

javacript中function (res) {}与(res) &#xff1e;{}的区别 function (res) {} 代码演示 let shape {name:长方形,say:function(){console.log(我是this.name)setTimeout(function(){console.log(3秒后输出我是: this.name); //this.name为undefined}, 3000)} }shape.sa…

Docker安装(Docker Engine安装)

一、Docker Engine和Desktop区别 Docker Engine 核心组件&#xff1a;Docker Engine是Docker的核心运行时引擎&#xff0c;负责构建、运行和管理容器。它包括守护进程&#xff08;dockerd&#xff09;、API和命令行工具客户端&#xff08;docker&#xff09;。适用环境&#…

【卡通风格的的登录界面】

卡通风格的的登录、注册界面模板&#xff0c;使用uni-app编写&#xff0c;直接复制粘贴即可。 废话不多说&#xff0c;代码如下&#xff1a; login.vue文件 <template><view class"content"><view class"login-form"><view class&quo…

【AI】最近有款毛茸茸AI生成图片圈粉了,博主也尝试使用风格转换生成可爱的小兔子,一起来探索下是如何实现的

应用名称&#xff1a;一键变身毛茸茸小兔子 体验地址&#xff1a;点击跳转体验 模型名称&#xff1a;Kolors&#xff0c;点击跳转 背景 Gitee AI最近发起了一个社群挑战赛。 如果最近你也没什么好点子&#xff0c;想练习又无从下手&#xff0c;怎么办呢&#xff1f; 没关系&a…

重学 Android 自定义 View 系列(十):带指针的渐变环形进度条

前言 该篇文章根据前面 重学 Android 自定义 View 系列(六)&#xff1a;环形进度条 拓展而来。 最终效果如下&#xff1a; 1. 扩展功能 支持进度顺时针或逆时针显示在进度条末尾添加自定义指针图片使用线性渐变为进度条添加颜色效果 2. 关键技术点解析 2.1 进度方向控制的…

Oracle 23ai 图形界面安装

新年的第一篇博客&#xff0c;展示下Oracle 23ai的图形化安装。 主要给大家看下界面&#xff0c;安装的过程与19c没什么不同。 安装前 安装Oracle Database Preinstallation RPM&#xff1a; sudo dnf install oracle-database-preinstall-23aioracle用户有了&#xff1a; …

跳转至系统设置下某个子模块 - 鸿蒙 Harmony

有时候遇到一些需要预授权系统权限才可访问的功能,可以通过如下方式先跳转至系统设置下的某个子页面进行配置,具体如下 code 所示参考: 具体跳转到设置的子设置页面如下也有注释,可供参考使用 /*** 访问系统设置: 子目录* */ static accessSystemSettingSubDirectory(uriKey?:…

el-table 实现纵向多级表头

为了实现上图效果&#xff0c;最开始打算用el-row、el-col去实现&#xff0c;但发现把表头和数据分成两大列时&#xff0c;数据太多时会导致所在格高度变高。但由于每一格数据肯定不一样&#xff0c;为保持高度样式一致&#xff0c;就需要我们手动去获取最高格的高度之后再设置…

2024年度总结答疑

大家好&#xff0c;我是大师兄。在2024年的最后一天&#xff0c;让我们一起来复盘总结&#xff0c;回顾我们在学习和工作中的能力提升、经验教训以及如何在未来做得更好。 过去一年&#xff0c;我们努力提升了学习和工作能力&#xff0c;学习了新的技术和知识&#xff0c;积极参…

flutter组件————Row和Column

Row和Column 在Flutter中&#xff0c;Row 和 Column 是两个非常常用的布局组件&#xff0c;它们用于按照水平或垂直方向排列子组件。 Row Row 组件是一个将子组件沿水平方向&#xff08;从左到右&#xff09;排列的控件。它通常用于创建一行中的多个小部件&#xff0c;比如文…

苹果解锁工具iToolab UnlockGo 中文安装版(附教程+补丁) 2024年6月ios17.4.1可用(记得点赞)解压密码请看文章!!! 评论区获取最新链接

UnlockGo 允许您非常轻松地绕过 iPhone 的密码并获得对设备的完全访问权限。它在以下场景中很有用。 在几分钟内删除 iPhone/iPad 上的各种锁定。 解锁 4 位/6 位密码、Touch ID 和 Face ID 删除没有密码的 iCloud 免费锁 无需密码即可从 iPhone/iPad/iPod 中删除 Apple ID…

[最佳方法] 如何将视频从 Android 发送到 iPhone

概括 将大视频从 Android 发送到 iPhone 或将批量视频从 iPhone 传输到 Android 并不是一件容易的事情。也许您已经尝试了很多关于如何将视频从 Android 发送到 iPhone 15/14 的方法&#xff0c;但都没有效果。但现在&#xff0c;通过本文中的这 6 种强大方法&#xff0c;您可…

driftingblues2

修改网卡配置信息 首先kali终端运行以下命令查看靶机ip 这里我们发现并没有查到靶机的ip&#xff0c;这时我们重启靶机 打开靶机&#xff0c;按下e键&#xff0c;进入到如下界面 将ro替换为rw signie init/bin/bash 替换完毕后&#xff0c;按下Ctrl键X键&#xff0c;进入如下…