数据结构--双向链表

news/2024/9/24 1:41:48/

        在讲双向链表之前,我们先了解一下链表的分类:

        链表的结构⾮常多样,主要分为带头与不带头、单向与双向、循环与不循环。三个种类可以任意搭配,所以总共可以形成八种链表,但是最常用的是单向不带头不循环链表和双向带头循环链表

        1. ⽆头单向⾮循环链表:结构简单,⼀般不会单独⽤来存数据。实际中更多是作为其他数据结构的⼦结构,如哈希桶、图的邻接表等等。另外这种结构在笔试⾯试中出现很多。

        2. 带头双向循环链表:结构最复杂,⼀般⽤在单独存储数据。实际中使⽤的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使⽤代码实现以后会发现结构会带
来很多优势,实现反⽽简单了,后⾯我们代码实现了就知道了。

        前者即单链表,在前一篇文章中已经讲过了,所以我们再来看看双向链表

         注意:这⾥的“带头”跟前⾯我们说的“头节点”是两个概念,实际前⾯的在单链表阶段称呼不严
谨,但是为了同学们更好的理解就直接称为单链表的头节点。带头链表⾥的头节点,实际为“哨兵位”,哨兵位节点不存储任何有效元素,只是站在这⾥“放哨的”。
        “哨兵位”存在的意义:遍历循环链表避免死循环。

双向链表的实现

文件:DoubleListNode.h

//双链表结构体创建
typedef int slDataType;
typedef struct DoubleList
{slDataType data;struct DoubleList* next;struct DoubleList* prev;
}DLN;//双向链表的初始化
void DbleInit(DLN** pphead);//双向链表打印
void DLNPrint(DLN* phead);//双向链表尾插函数
void DbleTailAdd(DLN* phead,int data);//双向链表头插函数
void DbleHeadAdd(DLN* phead, slDataType data);//双向链表头删函数
void DbleHeadDel(DLN* phead);//双向链表尾删函数
void DbleTailDel(DLN* phead);//双向链表查找
DLN* DbleSearch(DLN* phead);//双向链表修改函数
void DbleModify(DLN* phead);//双向链表销毁函数
void DbleStroy(DLN* phead);

文件DoubleListNode.c

//申请新节点
DLN* ListByNode(slDataType data)
{DLN* newnode = (DLN*)malloc(sizeof(DLN));if (newnode == NULL){perror("malloc fail");exit(1);}newnode->data = data;return newnode;
}//双向链表的初始化
void DbleInit(DLN** pphead)
{*pphead = (DLN*)malloc(sizeof(DLN));if (*pphead == NULL){perror("malloc fail");exit(1);}(*pphead)->data = -1;(*pphead)->next = (*pphead);(*pphead)->prev = (*pphead);
}//双向链表打印
void DLNPrint(DLN* phead)
{assert(phead);DLN* pcur = phead->next;while (pcur != phead){printf("%d->",pcur->data);pcur = pcur->next;}printf("\n");
}//双向链表尾插函数
void DbleTailAdd(DLN* phead, slDataType data)
{assert(phead);DLN* newnode = ListByNode(data);newnode->data = data;//尾插新节点newnode->next = phead;newnode->prev = phead->prev;phead->prev->next = newnode;phead->prev = newnode;
}//双向链表头插函数
void DbleHeadAdd(DLN* phead, slDataType data)
{assert(phead);DLN* newnode = ListByNode(data);newnode->next = phead->next;newnode->prev = phead;phead->next->prev = newnode;phead->next = newnode;
}//双向链表头删函数
void DbleHeadDel(DLN* phead)
{assert(phead);DLN* pcur = phead->next;if (pcur == phead){printf("删除失败,不存在有效节点\n");}else{phead->next = pcur->next;pcur->next->prev = phead;free(pcur);pcur = NULL;}
}//双向链表尾删函数
void DbleTailDel(DLN* phead)
{assert(phead);DLN* pcur = phead->next;while (pcur->next != phead){pcur = pcur->next;}phead->prev = pcur->prev;pcur->prev->next = phead;free(pcur);pcur = NULL;
}//双向链表查找
DLN* DbleSearch(DLN* phead,slDataType pos)
{assert(phead);DLN* pcur = phead->next;while (pcur != phead){if (pcur->data == pos){printf("找到了\n");return pcur;}pcur = pcur->next;}printf("没找到\n");return NULL;
}//双向链表修改函数
void DbleModify(DLN* phead,slDataType pos,slDataType data)
{DLN* find = DbleSearch(phead,pos);if (find != NULL){find->data = data;printf("修改成功\n");return;}else{printf("修改失败,未找到该节点\n");}
}//双向链表销毁函数
void DbleStroy(DLN* phead)
{assert(phead);DLN* pcur = phead->next;DLN* next = pcur->next;while (pcur != phead){free(pcur);pcur = next;next = next->next;}printf("销毁成功\n");
}

        这里单独讲解一个点,我们在创建“哨兵位”的时候使用的参数是一级指针的地址,并用二级指针接收,目的是创建一个节点的地址用作节点的链表头部,之后的其他函数均使用一级指针是为了防止头节点被修改。

        测试代码由各位自行书写,我们下期间。


http://www.ppmy.cn/news/1429134.html

相关文章

设计模式- 代理模式(Proxy Pattern)结构|原理|优缺点|场景|示例

目录 设计模式(分类) 设计模式(六大原则) 创建型 工厂方法 抽象工厂模式 单例模式 建造者模式 原型模式 结构型 适配器模式 装饰器模式 代理模式 代理模式(Prox…

常用渗透测试checklist

该渗透测试checklist包含以下几个模块: 测试大类、测试项、威胁等级、漏洞描述、修复方案 一、认证与授权类 1.密码明文传输 威胁等级:低危 漏洞描述:密码明文传输一般存在于web网站登录页面,用户名或者密码采用了明文传输&am…

二叉树相关

二叉树相关 力扣104 二叉树最大深度 普通递归遍历力扣 104 递归遍历2二叉树求前序遍历结果二叉树求 每个节点所在层数与每个节点的左右子树上的节点总数力扣 543 二叉树的直径 力扣104 二叉树最大深度 普通递归遍历 int depth 0;int maxDepth 0;public int maxDepth(TreeNod…

Day08React——第八天

useEffect 概念:useEffect 是一个 React Hook 函数,用于在React组件中创建不是由事件引起而是由渲染本身引起的操作,比如发送AJAx请求,更改daom等等 需求:在组件渲染完毕后,立刻从服务器获取频道列表数据…

机器学习(二)之监督学习

前言: 上一节大概讲解了几种学习方式,下面几张就具体来讲讲监督学习的几种算法。 以下示例中和都是权重的意思!!! 注:本文如有错误之处,还请读者指出,欢迎评论区探讨! 1…

学习 Rust 的第六天:所有权问题

大家好, 欢迎来到学习 Rust 的第 6 天,过去 5 天我们学到的内容在几乎每种语言中都是一样的。所有权是 Rust 的一个独特概念。 介绍 所有权是一种独特的内存管理系统,其中每个值都有一个指定的所有者,在所有者超出范围时自动释…

对观察者模式的理解

目录 一、场景1、题目描述 【[案例来源](https://kamacoder.com/problempage.php?pid1075)】2、输入描述3、输出描述4、输入示例5、输出示例 二、实现三、更复杂的场景 【[案例来源](https://refactoringguru.cn/design-patterns/observer/java/example#example-0--listeners-…

STC 8F无线通讯语言模块测试

/*无线通讯语言模块测试PAST 2020 1 15 L142 CODE2257**/ #include <REG52.H> #include <intrins.H> #include "stdio.h" #define uint unsigned int #defi…