C语言实现双向链表

embedded/2025/3/3 18:04:41/

 1、概念

        单向链表的构成使得节点的访问要按照链表的方向进行,某一单元的后继单元可以直接通过链指针(next指针)找到,但是想要找到其前驱单元,必须从链头重新开始查找。如果在节点中增加一个指针域指向其前驱节点,可以在牺牲空间代价的前提下,减少操作时间的代价。在单向链表基础上增加指向前驱单元指针(previous指针)的链表叫做双向链表

        上图仅是个人理解,结合下面的代码所做的理解图,如有错误,请指正,在此先谢过。个人有自己的图示理解更好,便于理解后续的双向链表的相关操作的实现。

 2、代码实现

2.1、双向链表结构定义

/* 定义双向链表节点结构体 */
typedef struct DListNode {int data;				/* 数据域 */struct DListNode* prev;	/* 前驱指针 */struct DListNode* next;	/* 后继指针 */
} DListNode;/* 定义双向链表 */
typedef struct {DListNode* head;		/* 头指针 */DListNode* tail;		/* 尾指针(可选,非必须) */
} DLinkedList;

2.2、基本操作实现

2.2.1、创建新节点

/*** @brief 创建双向链表新节点* @param val -- 新节点的数据* @return -- 创建的新节点*/
DListNode* CreateNode(int val)
{DListNode* newNode = (DListNode*)malloc(sizeof(DListNode));if (newNode == NULL) {printf("内存分配失败!\n");exit(1);}newNode->data = val;newNode->prev = NULL;newNode->next = NULL;return newNode;
}

2.2.2、插入操作

2.2.2.1、头部插入
/*** @brief 头部插入* @param list -- 已有的链表* @param val -- 头部插入节点的数据*/
void InsertAtHead(DLinkedList* list, int val)
{DListNode* newNode = CreateNode(val);if (list->head == NULL) {					/* 空链表 */list->head = newNode;list->tail = newNode;					/* 若维护尾指针 */} else {newNode->next = list->head;				/* 新节点的后继指向原头节点 */list->head->prev = newNode;				/* 原头节点的前驱指向新节点 */list->head = newNode;					/* 更新头指针 */}
}
2.2.2.2、尾部插入
/*** @brief 尾部插入* @param list -- 已有的链表* @param val -- 尾部插入节点的数据*/
void InsertAtTail(DLinkedList* list, int val)
{DListNode* newNode = CreateNode(val);if (list->head == NULL) {					/* 空链表 */list->head = newNode;list->tail = newNode;} else {DListNode* cur = list->head;while (cur->next != NULL) {				/* 找到尾节点 */cur = cur->next;}cur->next = newNode;					/* 原尾节点的后继指向新节点 */newNode->prev = cur;					/* 新节点的前驱指向原尾节点 */list->tail = newNode;					/* 更新尾指针 */}
}
2.2.2.3、指定位置插入
/*** @brief 指定位置插入* @param list -- 已存在的链表* @param index -- 插入位置* @param val -- 新插入节点的数据*/
void InsertAtIndex(DLinkedList* list, int index, int val)
{if (index < 0) return;if (index == 0) {							/* 头部插入 */InsertAtHead(list, val);return;}DListNode* newNode = CreateNode(val);DListNode* cur = list->head;for (int i = 0; cur != NULL && i < index - 1; i++) {/* 移动到目标位置前一个节点 */cur = cur->next;}if (cur == NULL) {							/* 索引超出范

http://www.ppmy.cn/embedded/169679.html

相关文章

SVN 简介

SVN 简介 引言 版本控制系统(Version Control System,VCS)是软件开发过程中不可或缺的工具之一。它能够帮助开发者管理代码的版本,追踪代码变更,协同工作,以及确保代码的稳定性和安全性。Subversion(简称SVN)是一种流行的版本控制系统,本文将为您详细介绍SVN的基本概…

LeetCode 0132.分割回文串 II:动态规划

【LetMeFly】132.分割回文串 II&#xff1a;动态规划 力扣题目链接&#xff1a;https://leetcode.cn/problems/palindrome-partitioning-ii/ 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是回文串。 返回符合要求的 最少分割次数 。 示例 …

阿里管理三板斧课程和管理工具包(视频精讲+工具文档).zip

阿里管理三板斧课程和管理工具包&#xff08;视频精讲工具文档&#xff09;&#xff0c;共18课。 阿里管理三板斧工具包 阿里绩效考核文档 阿里人力资源实践全集文档 阿里文化构建工具包 阿里正委体系工具包 阿里三板斧.pdf 阿里三板斧-学员手册.pdf 第1集 三板斧的底层逻辑.…

版图自动化连接算法开发 00001 ------ 直接连接两个给定的坐标点

版图自动化连接算法开发 00001 ------ 直接连接两个给定的坐标点 引言正文定义坐标点的类绘图显示代码直接连接两个坐标点引言 由于人工智能的加速普及,每次手动绘制版图都会觉得特别繁琐,作者本人在想可否搞一个自动化连接器件端口的算法,后期可以根据一些设定的限制进行避…

代码随想录算法训练营第33天 | 62. 不同路径 63. 不同路径 II 343. 整数拆分 96. 不同的二叉搜索树

62. 不同路径 题目链接&#xff1a; 62. 不同路径 - 力扣&#xff08;LeetCode&#xff09; 代码 class Solution:def uniquePaths(self, m: int, n: int) -> int:dp [[1]*n for _ in range(m)]for i in range(1,m):for j in range(1,n):dp[i][j] dp[i-1][j] dp[i][j…

【OpenCV C++】图像清晰度增强:拉普拉斯锐化,SUM锐化,普通锐化

文章目录 1 普通锐化2. 拉普拉斯 锐化3 SUM锐化1 普通锐化 void sharpenImage(const cv::Mat& frame,float a, float b) {定义一个3x3的锐化核cv

算法日记33:15届蓝桥C++B组R格式(快速幂50%/高精度100%)

一、题目 二、题解一&#xff1a;快速幂&#xff08;50%样例&#xff09; 1、解题思路&#xff1a; 1&#xff09;通过题目我们可以采取最朴素的想法就是先模拟题目的说明 2&#xff09;并且我们发现有乘方出现( ∗ 2 n *2^n ∗2n)&#xff0c;因此我们可以考虑使用快速幂来…

计算机视觉 |解锁视频理解三剑客——SlowFast

一、引言 在如今这个信息爆炸的时代&#xff0c;视频数据呈指数级增长&#xff0c;从日常的社交媒体分享&#xff0c;到安防监控的海量记录&#xff0c;再到智能驾驶中的环境感知&#xff0c;视频无处不在。视频理解作为计算机视觉领域的关键研究方向&#xff0c;旨在让计算机…