链表最终章双向链表及其应用

1245 字
6 分钟
链表最终章双向链表及其应用

———————————本文旨在交流探讨计算机知识,欢迎交流指正———————————— 上一章,我们介绍了链表的循环扩展,但是,单向链表毕竟是单向查询的,就算是经过循环来查找,终究是效率偏低,下面,我们来介绍一种工程项目中运用更加广泛的一种链表结构:双向链表——: 根据此结构,我们可以发现,虽然代码复杂度增加了,但是由于此结构是双向的,操作更加便捷,下面,我将演示各模块内容: 首先,是结构的构建:

typedef int Element;
typedef struct _node {
Element val;
struct _node *next;
struct _node *prev;
} DNode, DList;
/* 使用一个带头节点的双向循环链表,头节点让用户来管理,提供初始化接口 */
void initDList(DList *header);
void releaseDList(DList *header);
// 实现头插、尾插
void insertDListHeader(DList *header, Element val);
void insertDListRear(DList *header, Element val);
// 显示链表
void showDList(const DList *header);
// 删除一个元素
void delDList(DList *header, Element e);

注:此为.h头文件里的内容,若先用头文件封装再放在.c文件里面使用,最后在main.c文件里面测试,很好的保证了产品内容的安全性与代码便捷性。 1、这一次,为了让代码更加简洁规范,我们使用static的模式构建加入和删除两大基本模块:

//next是已知的待插入位置节点的下一个节点;
//prev是已知的待插入节点的上一个节点(前置节点);
//插入
static void addDNode(DNode *new_node, DNode *prev, DNode *next) {
next->prev = new_node;//待插入节点下一个节点的上一个节点是新节点;
new_node->next = next;//新节点的下一个是上一个节点;
new_node->prev = prev;新节点上一个是前置节点
prev->next = new_node;前置节点下一个是新节点
}
//删除
static void delDNode(DNode *prev, DNode *next) {
next->prev = prev;//某节点下一个节点的前一个是某节点上一个节点;
prev->next = next;//某节点上一个节点的下一个是某节点下一个节点;
}

2、然后,我们再在此基础上完成增删改查的基本操作:

1、初始化:

void initDList(DList* header) {
header->val = 0;//初始化头结点的数值域为0
header->next = header->prev = header;//头结点的前置节点和后置节点都初始化指向头结点
}

2、增添操作:

void insertDListHeader(DList* header, Element val) {
DNode *new_node = malloc(sizeof(DNode));//malloc申请空间建立一个新节点
new_node->val = val;//新节点赋值;
addDNode(new_node, header, header->next);//函数操作
++header->val;
}
//头插法;
void insertDListRear(DList* header, Element val) {
DNode *new_node = malloc(sizeof(DNode));
new_node->val = val;
addDNode(new_node, header->prev, header);
++header->val;
}
//尾插法;

3、删除操作

void delDList(DList* header, Element e) {
// 1. 找到这个元素,就可以删除,不需要再找到前置节点
DNode *pos = header->next;
while (pos != header && pos->val != e) {
pos = pos->next;
}
// 2. 找到没有?
if (pos != header) { // 找到
delDNode(pos->prev, pos->next);
pos->next = pos->prev = NULL;
free(pos);
--header->val;
} else {
printf("Not find %d element!\n", e);
}

4、展示函数(若对工程有疑问和对const有疑问可以看本专栏的第一篇内容)

void showDList(const DList* header) {
DNode *pos = header->next;
printf("show: ");
while (pos != header) {
printf("\t%d", pos->val);
pos = pos->next;
}
printf("\n");
}
//简单的循环打印,不过多赘述;

5、最后,是销毁链表的函数:

void releaseDList(DList* header) {
DNode *pos = header->next;
DNode *tmp = NULL;
while (pos != header) {
tmp = pos;
delDNode(pos->prev, pos->next);
pos = pos->next;
free(tmp);
--header->val;
}
}
//逐个销毁

最后附上各文件代码: 1、doubleList.h:

#ifndef DOUBLE_LIST_H
#define DOUBLE_LIST_H
typedef int Element;
typedef struct _node {
Element val;
struct _node *next;
struct _node *prev;
} DNode, DList;
/* 使用一个带头节点的双向循环链表,头节点让用户来管理,提供初始化接口 */
void initDList(DList *header);
void releaseDList(DList *header);
// 实现头插、尾插
void insertDListHeader(DList *header, Element val);
void insertDListRear(DList *header, Element val);
// 显示链表
void showDList(const DList *header);
// 删除一个元素
void delDList(DList *header, Element e);
#endif //DOUBLE_LIST_H

2、doubleList.c

#include "doubleList.h"//doubleList.h文件封装的函数名
#include
#include
static void addDNode(DNode *new_node, DNode *prev, DNode *next) {
next->prev = new_node;
new_node->next = next;
new_node->prev = prev;
prev->next = new_node;
}
static void delDNode(DNode *prev, DNode *next) {
next->prev = prev;
prev->next = next;
}
void initDList(DList* header) {
header->val = 0;
header->next = header->prev = header;
}
void releaseDList(DList* header) {
DNode *pos = header->next;
DNode *tmp = NULL;
while (pos != header) {
tmp = pos;
delDNode(pos->prev, pos->next);
pos = pos->next;
free(tmp);
--header->val;
}
}
void insertDListHeader(DList* header, Element val) {
DNode *new_node = malloc(sizeof(DNode));
new_node->val = val;
addDNode(new_node, header, header->next);
++header->val;
}
void insertDListRear(DList* header, Element val) {
DNode *new_node = malloc(sizeof(DNode));
new_node->val = val;
addDNode(new_node, header->prev, header);
++header->val;
}
void showDList(const DList* header) {
DNode *pos = header->next;
printf("show: ");
while (pos != header) {
printf("\t%d", pos->val);
pos = pos->next;
}
printf("\n");
}
void delDList(DList* header, Element e) {
// 1. 找到这个元素,就可以删除,不需要再找到前置节点
DNode *pos = header->next;
while (pos != header && pos->val != e) {
pos = pos->next;
}
// 2. 找到没有?
if (pos != header) { // 找到
delDNode(pos->prev, pos->next);
pos->next = pos->prev = NULL;
free(pos);
--header->val;
} else {
printf("Not find %d element!\n", e);
}
}

3、main.c

#include
#include "doubleList.h"
DList stu_table;
int main() {
initDList(&stu_table);
for (int i = 0; i < 5; ++i) {
// insertDListHeader(&stu_table, i + 100);
insertDListRear(&stu_table, i + 100);
}
insertDListHeader(&stu_table, 60);
insertDListHeader(&stu_table, 80);
showDList(&stu_table);
printf("====================\n");
delDList(&stu_table, 102);
showDList(&stu_table);
releaseDList(&stu_table);
printf("num: %d\n", stu_table.val);
showDList(&stu_table);
return 0;
}

————————————希望能对你有所帮助!!!————————————————

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!

打赏
链表最终章双向链表及其应用
https://firefly.cuteleaf.cn/posts/knowledge/链表最终章双向链表及其应用/
作者
Firefly
发布于
2026-06-21
许可协议
CC BY-NC-SA 4.0
相关文章 智能推荐
1
拓展单向循环链表
数据结构 —————————————本文旨在讨论计算机知识欢迎指正——————————————— 书接上回:我们已经了解了链表如何编写与前置节点和头指针两种表示方式,下面,我们来了解进阶写法———如何实现单向循环链表。 下面,我们来梳理一下循环链表的实现方式: 这是朴素的链表实现形式: 这是我们理想中的循环...
2
链表的实现与介绍
数据结构 ——————————————本文旨在交流计算机知识,欢迎指正————————————— 首先,我们回顾一下上一期讲的顺序表: 顺序表是一种物理结构上连续的,一整块连续空间的逻辑表,但是,试想一下,如果每次我们都是申请在一块整块空间里面的顺序表,但是我们并不知道堆空间里面我们malloc一块空间之后我...
3
附录对于头结点单向链表的优化方法
数据结构 ————————————本文旨在交流学习计算机知识,欢迎交流讨——————————— 上一章,我们浅显的讨论了链表的结构,本文在上一章的链表的基础上做出了些许优化,可配合食用。 回到正题,我们已经了解链表的结构,它是一种非连续空间存储的线性表,主要依靠地址域访问下一个元素并通过遍历操作进行增删改查。...
4
顺序表的实现与介绍及部分工程思想的思考
数据结构 ——————————本文旨在讨论和探究计算机知识,欢迎指正———————————— 首先,我们来聊聊什么是线性表: 线性表,顾名思义,是一种具有线性结构的数据排布形式 ,是一个类似数组的东西,在逻辑上一个接一个有序的整块链接,区别于链表的无序分布链接。 如图,我们可以得出,顺序表是一条线一样的结构...
5
数据结构之树及树的存储
数据结构 ——————————————本栏目旨在交流计算机知识————————————————— 上一章节,我们介绍了线性的数据结构:表,栈,队列。接下来,我们将进入下一章节——树结构的学习。 首先,我们先介绍一下树的基本概念: 结点:使⽤树结构存储的每一个数据元素都被称为“结点”。例如图中的A就是一个结点。...
随机文章 随机推荐
Profile Image of the Author
Firefly
Hello, I'm Firefly.
公告
欢迎来到我的博客!这是一则示例公告。
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
33
分类
7
标签
25
总字数
56,127
运行时长
0
最后活动
0 天前
站点信息
构建平台
Vercel
博客版本
Firefly v6.12.3
文章许可
CC BY-NC-SA 4.0

文章目录