【数据结构】双链表的定义和操作

目录

1.双链表的定义

2.双链表的创建和初始化

3.双链表的插入节点操作

4.双链表的删除节点操作

5.双链表的查找节点操作

6.双链表的更新节点操作

7.完整代码


🌈嗨!我是Filotimo__🌈。很高兴与大家相识,希望我的博客能对你有所帮助。

💡本文由Filotimo__✍️原创,首发于CSDN📚。

📣如需转载,请事先与我联系以获得授权⚠️。

🎁欢迎大家给我点赞👍、收藏⭐️,并在留言区📝与我互动,这些都是我前进的动力!

🌟我的格言:森林草木都有自己认为对的角度🌟。

1.双链表的定义

双链表是一种常见的数据结构,它由一系列节点组成,每个节点包含两个指针,一个指向前一个节点,另一个指向后一个节点。与单链表不同的是,双链表的节点可以双向访问,因此可以在任意位置快速插入、删除和查找元素。

一个双链表通常包含以下属性和操作:
头节点(head):指向第一个节点的指针。
尾节点(tail):指向最后一个节点的指针。
节点(node):包含数据和两个指针的数据单元。
插入(insert):在指定位置插入一个新的节点。
删除(delete):删除指定位置的节点。
查找(search):根据给定的值查找节点。
遍历(traverse):按顺序访问链表中的每个节点。

2.双链表的创建和初始化

创建一个双链表需要定义一个结构体,包含数据域和前后指针域。初始化时要注意将头结点的前后指针均指向 NULL。

struct DNode {int data;  //数据域struct DNode *prior;  //前驱指针域struct DNode *next;   //后继指针域
};struct DNode *createList() {struct DNode *head = (struct DNode*)malloc(sizeof(struct DNode));head->prior = NULL;head->next = NULL;return head;
}

定义结构体struct DNode表示双向链表的节点。
该节点包括三个成员变量:
int data表示节点的数据域,可以存储整数类型的数据。
struct DNode *prior表示指向前一个节点的指针域。
struct DNode *next表示指向后一个节点的指针域。

在createList函数内部,首先通过malloc函数动态分配了一块内存,大小为一个struct DNode结构体的大小。然后将分配的内存强制转换为struct DNode*类型,并将其赋值给head指针变量,作为链表的头节点。

3.双链表的插入节点操作

在插入节点时,需要将新节点插入到某个节点之前或之后,通过修改前后指针实现。具体操作分为两步,先将新节点的前后指针赋值,然后修改它前后节点的指针。需要注意判断特殊情况,如插入到空链表、插入到头结点等。

void insertNode(struct DNode *p, int data) {if (p == NULL) return;struct DNode *newNode = (struct DNode*)malloc(sizeof(struct DNode));newNode->data = data;newNode->prior = p;newNode->next = p->next;if (p->next != NULL) p->next->prior = newNode;p->next = newNode;
}

函数insertNode接受两个参数:指向双向链表结点的指针p和要插入的数据data。

如果p不为空,则创建一个新的双向链表结点newNode,通过malloc函数动态分配内存。然后,将新节点的data字段设置为传入的data值。再将新节点的prior字段设置为指向p,将新节点的next字段设置为指向p->next。

检查p的下一个结点是否为空,如果不为空,则将下一个结点的prior字段指向新节点newNode。最后将p的next指针指向新结点newNode,完成插入操作。这样,插入操作就将新节点插入到了链表中p结点之后的位置。

4.双链表的删除节点操作

在删除节点时,需先找到要删除的节点,然后修改前后节点的指针。在执行 free 操作后,需要将指针置为 NULL,避免出现野指针。

void deleteNode(struct DNode *p) {if (p == NULL) return;p->prior->next = p->next;if (p->next != NULL) p->next->prior = p->prior;free(p);p = NULL;
}

如果p不为空,将p结点的前驱结点的next指针指向p结点的后继结点,断开p结点与前后结点的连接。即p->prior->next = p->next。

检查p结点的后继结点是否为空,如果不为空,则将后继结点的前驱指针指向p结点的前驱结点,断开p结点与后继结点的连接。即p->next->prior = p->prior。

使用free函数释放了指针p指向的内存,将p结点从链表中删除。

将指针p设置为NULL,确保不再引用已经删除的结点。

5.双链表的查找节点操作

查找节点时,可以采用遍历的方法进行查找。需要注意判断特殊情况,如链表为空等。

struct DNode *findNode(struct DNode *head, int data) {if (head == NULL) return NULL;struct DNode *p = head->next;while (p != NULL) {if (p->data == data) return p;p = p->next;}return NULL;
}

如果head不为空,代码将p指针初始化为head结点的下一个结点,即head->next。

使用while循环遍历链表,如果指针p指向的结点的data字段等于要查找的数据data,则直接返回该结点的指针p,表示查找成功。

如果没有查找到要找的数据,即p到达链表结尾指针为NULL,则返回NULL,表示查找失败。

6.双链表的更新节点操作

更新节点操作与单链表类似,具体步骤为先查找要更新的节点,然后修改其数据域的值即可。

void updateNode(struct DNode *p, int newData) {if (p != NULL) {p->data = newData;}
}

首先检查指针p是否为空,如果不为空,则将指针p所指向的结点的data字段更新为新的数据newData。如果结点p为空,则不进行任何操作。

7.完整代码

#include <stdio.h>
#include <stdlib.h>//双链表结构体定义
struct DNode {int data;  //数据域struct DNode *prior;  //前驱指针域struct DNode *next;   //后继指针域
};//创建双链表
struct DNode *createList() {struct DNode *head = (struct DNode*)malloc(sizeof(struct DNode));head->prior = NULL;head->next = NULL;return head;
}//插入节点
void insertNode(struct DNode *p, int data) {if (p == NULL) return;struct DNode *newNode = (struct DNode*)malloc(sizeof(struct DNode));newNode->data = data;newNode->prior = p;newNode->next = p->next;if (p->next != NULL) p->next->prior = newNode;p->next = newNode;
}//删除节点
void deleteNode(struct DNode *p) {if (p == NULL) return;p->prior->next = p->next;if (p->next != NULL) p->next->prior = p->prior;free(p);p = NULL;
}//查找节点
struct DNode *findNode(struct DNode *head, int data) {if (head == NULL) return NULL;struct DNode *p = head->next;while (p != NULL) {if (p->data == data) return p;p = p->next;}return NULL;
}//更新节点
void updateNode(struct DNode *p, int newData) {if (p != NULL) {p->data = newData;}
}//遍历双链表
void traverseList(struct DNode *head) {if (head == NULL) return;struct DNode *p = head->next;while (p != NULL) {printf("%d ", p->data);p = p->next;}printf("\n");
}//测试双链表
int main() {struct DNode *head = createList();  //创建链表//插入节点insertNode(head, 1);insertNode(head, 2);insertNode(head, 3);insertNode(head, 4);traverseList(head);  //遍历链表struct DNode *p = findNode(head, 2);  //查找节点if (p != NULL) {printf("Found node: %d\n", p->data);updateNode(p, 5);  //更新节点printf("After updated, the list is:\n");traverseList(head);  //遍历链表}deleteNode(findNode(head, 3)); //删除节点printf("After deleted, the list is:\n");traverseList(head);  //遍历链表return 0;
}

输出结果如下:

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

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

相关文章

WPF-UI HandyControl 控件简单实战

文章目录 前言UserControl简单使用新建项目直接新建项目初始化UserControlGeometry:矢量图形额外Icon导入最优解决方案 按钮Button切换按钮ToggleButton默认按钮图片可切换按钮加载按钮切换按钮 单选按钮和复选按钮没有太大特点&#xff0c;就不展开写了总结 DataGrid数据表格G…

详细了解stm32---按键

提示&#xff1a;永远支持知识文档免费开源&#xff0c;喜欢的朋友们&#xff0c;点个关注吧&#xff01;蟹蟹&#xff01; 目录 一、了解按键 二、stm32f103按键分析 三、按键应用 一、了解按键 同学们&#xff0c;又见面了o(*&#xffe3;▽&#xffe3;*)ブ&#xff0c;最…

C++ Qt开发:Tab与Tree组件实现分页菜单

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍tabWidget选择夹组件与TreeWidget树形选择组件…

升华 RabbitMQ:解锁一致性哈希交换机的奥秘【RabbitMQ 十】

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 升华 RabbitMQ&#xff1a;解锁一致性哈希交换机的奥秘【RabbitMQ 十】 前言第一&#xff1a;该插件需求为什么需要一种更智能的消息路由方式&#xff1f;一致性哈希的基本概念&#xff1a; 第二&…

【Linux】MySQL 数据库安装配置教程(Ubuntu 22.04)

前言 MySQL是一个流行的开源关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;广泛用于Web应用程序的后端数据存储&#xff0c;如许多动态网站、电子商务系统和在线出版物等。 MySQL具有高性能、可靠性和易用性的特点&#xff0c;它支持大型数据库&#xff0c;…

【Java】使用递归的方法获取层级关系数据demo

使用递归来完善各种业务数据的层级关系的获取 引言&#xff1a;在Java开发中&#xff0c;我们通常会遇到层层递进的关系型数据的获取问题&#xff0c;有时是树状解构&#xff0c;或金字塔结构&#xff0c;怎么描述都行&#xff0c;错综复杂的关系在程序中还是可以理清的。 这…

uniGUI之上传文件UniFileUploadButton

TUniFileUploadButton主要属性&#xff1a; Filter: 文件类型过滤&#xff0c;有图片image/* audio/* video/*三种过滤 MaxAllowedSize: 设置文件最大上传尺寸&#xff1b; Message&#xff1a;标题以及消息文本&#xff0c;可翻译成中文 TUniFileUploadButton控件 支持多…

云原生之深入解析Linkerd Service Mesh的功能和使用

一、简介 Linkerd 是 Kubernetes 的一个完全开源的服务网格实现&#xff0c;它通过为你提供运行时调试、可观测性、可靠性和安全性&#xff0c;使运行服务更轻松、更安全&#xff0c;所有这些都不需要对代码进行任何更改。Linkerd 通过在每个服务实例旁边安装一组超轻、透明的…

MX6ULL学习笔记(十二)Linux 自带的 LED 灯

前言 前面我们都是自己编写 LED 灯驱动&#xff0c;其实像 LED 灯这样非常基础的设备驱动&#xff0c;Linux 内 核已经集成了。Linux 内核的 LED 灯驱动采用 platform 框架&#xff0c;因此我们只需要按照要求在设备 树文件中添加相应的 LED 节点即可&#xff0c;本章我们就来学…

Python基础05-函数

零、文章目录 Python基础05-函数 1、函数的作用及其使用步骤 &#xff08;1&#xff09;函数的作用 在Python实际开发中&#xff0c;我们使用函数的目的只有一个“让我们的代码可以被重复使用” 函数的作用有两个&#xff1a; ① 代码重用&#xff08;代码重复使用&#xf…

【AI工具】GitHub Copilot IDEA安装与使用

GitHub Copilot是一款AI编程助手&#xff0c;它可以帮助开发者编写代码&#xff0c;提供代码建议和自动完成功能。以下是GitHub Copilot在IDEA中的安装和使用步骤&#xff1a; 安装步骤&#xff1a; 打开IDEA&#xff0c;点击File -> Settings -> Plugins。在搜索框中输…

windows10 php8连接sql server

一、环境安装 文章目录 一、环境安装1.安装php拓展2.在 Windows 上安装PHP驱动程序3.在 Windows 上安装ODBC驱动 二、php连接sqlserver三、注意事项数据库相关设置相关语法sqlsrv_fetch_array 的示例&#xff1a;sqlsrv_fetch 的示例&#xff1a;echo 和 print_r 的不同 所用资…

Webrtc 学习交流

花了几周的时间研究了一下webrtc &#xff0c;并开发了一个小项目&#xff0c;用来点对点私密聊天 交流传输文件等…后续会继续扩展其功能。 体验地址&#xff0c;大狗子的ID,我在线时可以连接测试到我 f3e0d6d0-cfd7-44a4-b333-e82c821cd927 项目特点 除了交换信令与stun 没…

ES6 面试题 | 01.精选 ES6 面试题

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

Mybatis 动态SQL的插入操作

需求 : 根据用户的输入情况进行插入 动态SQL:根据需求动态拼接SQL 用户往表中插入数据,有的数据可能不想插入,比如不想让别人知道自己的性别,性别就为空 insert into userinfo(username,password,age,gender,phone) values(?,?,?,?,?); insert into userinfo(username,…

LVS-DR模式部署

目录 一、部署信息 二、部署LVS-DR模式 三、测试 四、DR模式 LVS负载均衡群集 一、部署信息 DR 服务器&#xff1a;172.16.114.70 Web 服务器1&#xff1a;172.16.114.80 Web 服务器2&#xff1a;172.16.114.60 vip&#xff1a;172.16.114.200 客户端&#xff1a;172.16.11…

STM32与Freertos入门(五)任务案例

1、实现功能 通过两个按键任务分别控制不同的点灯案例 创建 4 个任务&#xff1a;在点灯任务的基础上在创建两个按键任务&#xff1a; Task_led&#xff1a;间隔 500ms 闪烁 LE1&#xff1b; Task_led2&#xff1a;间隔 1000ms 闪烁 LED2&#xff1b; Task_key&#xff1a;如…

【Java系列】详解多线程(三)—— 线程安全(上篇)

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【Java系列专栏】【JaveEE学习专栏】 本专栏旨在分享学习Java的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 一…

​SQL (关系型) 数据库-fastapi集成

SQL (关系型) 数据库 - FastAPI FastAPI不需要你使用SQL(关系型)数据库。 但是您可以使用任何您想要的关系型数据库。 在这里&#xff0c;让我们看一个使用着SQLAlchemy的示例。 您可以很容易地将SQLAlchemy支持任何数据库&#xff0c;像&#xff1a; PostgreSQLMySQLSQLi…

vue3 setup语法糖写法基本教程

前言 官网地址&#xff1a;Vue.js - 渐进式 JavaScript 框架 | Vue.js (vuejs.org)下面只讲Vue3与Vue2有差异的地方&#xff0c;一些相同的地方我会忽略或者一笔带过与Vue3一同出来的还有Vite&#xff0c;但是现在不使用它&#xff0c;等以后会有单独的教程使用。目前仍旧使用v…