暴力数据结构之双向链表

1.定义双向链表结构的节点

typedef int LTDataType;//定义双向链表结构的节点
typedef struct ListNode
{LTDataType data;struct ListNode* prev;struct ListNode* next;
}LTNode;

首先创建一个结构体,然后包含数据以及prev和next指针用来指向前一个节点和后一个节点

其中使用typedef 可以方便修改数据类型。


2.初始化和申请节点

//初始化
void LTInit(LTNode** pphead)
{//给双向链表一个哨兵位*pphead = LTBuyNode(-1);
}

首先动态开辟一块内存空间,将开辟好的空间用来保存node,初始条件下由于只有哨兵位一个节点,所以node->next和node->prev都指向node节点本身,形成一个双向链表。

//申请节点
LTNode* LTBuyNode(LTDataType x)
{LTNode* node = (LTNode*)malloc(sizeof(LTNode));if (node == NULL){perror("malloc fail!");exit(1);}node->data = x;node->next = node->prev = node;return node;
}

3.尾插和头插

由于双向链表,只有哨兵位固定不变,所以找尾节点就是找哨兵位前一个节点,即phead->prev,就代表的是尾节点

所以尾插就是先创建一个新节点,接入尾节点与哨兵位之间,然后将尾节点和哨兵位分别接入新节点之中,具体可以用下图来表示。(黑色为第一步,红色为第二步)

注意:

   1.插入数据之前,链表必须初始化到只有一个头结点的情况
   2.不改变哨兵位的地址,因此传一级即可 

//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);//先接入新节点newnode->prev = phead->prev;newnode->next = phead;//再将原节点指向新节点phead->prev->next = newnode;phead->prev = newnode;
}

头插可以理解为在哨兵位后第一个节点插入新节点,然后哨兵位和原来的第一个节点分别指向新插入的节点,组成新的链表,具体可以如下图解释:(黑色为第一步,红色为第二步)

//头插
void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);//首先接入新节点newnode->next = phead->next;newnode->prev = phead;//后将原节点指向新节点phead->next->prev = newnode;phead->next = newnode;
}

4.尾删和头删 

尾删首先要找出删除节点,并且保证链表不能只有一个哨兵位,所以要先使待删除节点孤立,然后释放并且置为空,将待删除节点的前一个节点视作尾节点,形成新的链表。

注意:

        孤立链表节点就是将当前节点与后一个节点的连接断开再断开与前一个节点的连接,顺序不            可颠倒,否则会丢失节点。

//尾删
void LTPopBack(LTNode* phead)
{//链表有效且不能只有一个哨兵位assert(phead && phead->next != phead);//存储要删除的节点,即尾节点LTNode* del = phead->prev;//将尾节点与链表断开,尾节点的前一个节点与哨兵位链接,组成新的链表del->prev->next = phead;phead->prev = del->prev;//释放要删除的尾节点并置为NULLfree(del);del = NULL;
}

头删同样要保证链表不能只有一个哨兵位,然后将要删除的节点孤立,并且将待删除节点的前一个节点当做头节点,形成新的链表。

//头删
void LTPopFront(LTNode* phead)
{assert(phead && phead->next != phead);LTNode* del = phead->next;//将要删除的节点剔除,下一个节点与哨兵位组成新的链表phead->next = del->next;del->next->prev = phead;//删除节点并且置为NULLfree(del);del = NULL;
}

5.打印和销毁

打印就是遍历链表中所有数据后打印出来,销毁就是依次释放节点中的数据后将该节点置为NULL 

//打印双向链表
void LTPrint(LTNode* phead)
{LTNode* pcur = phead->next;while (pcur != phead){printf("%d->",pcur->data);pcur = pcur->next;}printf("\n");
}
//销毁
void LTDesTroy(LTNode* phead)
{assert(phead);LTNode* pcur = phead->next;while (pcur != phead){LTNode* next = pcur->next;free(pcur);pcur = next;}//此时pcur指向phead,而phead还没有被销毁free(phead);phead = NULL;
}

6.在pos节点之后插入数据

首先将pos节点插入链表中,然后将待插入位置的前一个节点与后一个节点分别于pos节点连接。

注意:

         pos节点先指向待插入位置的后一个节点,然后指向前一个节点,否则节点会丢失。 

//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* newnode = LTBuyNode(x);//在pos节点之后先插入数据newnode->next = pos->next;newnode->prev = pos;//然后pos节点与原来pos之后的节点一起指向新插入的节点,组成新链表pos->next->prev = newnode;pos->next = newnode;
}

7.删除pos节点

删除节点就是将pos节点的后一个节点与前一个节点直接连接,然后free(pos),最后置为NULL 

//删除pos节点
void LTErase(LTNode* pos)
{//pos理论上来说不能为phead,但是没有参数phead,无法增加校验assert(pos);//将pos的后一个节点和前一个节点连接,直接剔除pos节点pos->next->prev = pos->prev;pos->prev->next = pos->next;//删除pos节点free(pos);pos = NULL;
}

8.查找

查找就是遍历链表后,找到符合的数据就返回当前位置,否则返回一个NULL 

//查找节点
LTNode* LTFind(LTNode* phead, LTDataType x)
{LTNode* pcur = phead->next;while (pcur != phead){if (pcur->data == x){//找到了返回下标return pcur;}pcur = pcur->next;}//没找到返回空指针return NULL;
}

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

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

相关文章

【opencv】示例-points_classifier.cpp 使用不同机器学习算法在二维空间中对点集进行分类...

#include "opencv2/core.hpp" // 包含OpenCV核心功能的文件 #include "opencv2/imgproc.hpp" // 包含OpenCV图像处理功能的文件 #include "opencv2/ml.hpp" // 包含OpenCV机器学习模块的文件 #include "opencv2/highgui.hpp" // 包含O…

卷积神经网络(CNN)笔记——多图深入理解

梗直哥、梗直哥丶的个人空间-梗直哥丶个人主页-哔哩哔哩视频 过去十年,卷积神经网络(CNN)如同科技领域的明星,以其卓越的表现撑起了人工智能的半边天。这种创新的网络模型,不仅在计算机视觉、语音识别等传统领域大放异彩,更为人工智能的快速发展和广泛应用奠定了坚实的基础。…

Day19-【Java SE进阶】网络编程

一、网络编程 1.概述 可以让设备中的程序与网络上其他设备中的程序进行数据交互(实现网络通信的)。java.net,*包下提供了网络编程的解决方案! 基本的通信架构 基本的通信架构有2种形式:CS架构(Client客户端/Server服务端)、BS架构(Browser浏览器/Server服务端)。 网络通信的…

【新版】系统架构设计师 - 知识点 - 结构化开发方法

个人总结,仅供参考,欢迎加好友一起讨论 文章目录 架构 - 知识点 - 结构化开发方法结构化开发方法结构化分析结构化设计 数据流图和数据字典模块内聚类型与耦合类型 架构 - 知识点 - 结构化开发方法 结构化开发方法 分析阶段 工具:数据流图、…

从0到1实现RPC | 12 限流

在服务提供者provider端添加限流逻辑 限流:指定时间内请求数超过指定阈值时就抛出异常。 在ProviderInvoker的调用过程中,添加限流逻辑: 使用滑动窗口SlidingTimeWindow统计30s的请求数;每个服务service对应一个滑动窗口&#…

神经网络--反向传播算法推导

神经网络–反向传播算法推导 文章目录 神经网络--反向传播算法推导概述神经网络模型反向传导算法 概述 以监督学习为例,假设我们有训练样本集 ( x ( i ) , y ( i ) ) (x^{(i)},y^{(i)}) (x(i),y(i)),那么神经网络算法能提供一种复杂且非线性的假设模型 …

route路由命令、ip route命令、default默认路由(0.0.0.0 )

文章目录 3. route语法3.1 查看路由表3.1 参数解释 3.2 添加路由记录3.2.1 添加到达单个目标主机的路由3.2.2 添加到达目标网络的路由3.2.3 添加默认路由 3.3 删除路由记录 4. ip route4.1 查看路由4.1.1 不带条件4.1.2 带条件 4.2 添加路由4.3 删除路由4.4 清空路由表&#xf…

elasticsearch7安全配置--最低安全等级,用户名密码

上一篇博客在centos7上安装了elasticsearch7 接下来对elasticsearch进行安全方面的配置 minimal security 最低安全等级,用户名密码 首先开启xpack vim config/elasticsearch.yml xpack.security.enabled: true由于我是单机配置的,还加了如下配置 d…

JavaScript:事件循环机制(同步、异步)(单、多线程)

事件循环机制: 多进程和多线程 1. 进程:程序的一次执行, 它占有一片独有的内存空间 2. 线程: CPU的基本调度单位, 是程序执行的一个完整流程 3. 进程与线程 * 一个进程中一般至少有一个运行的线程: 主线程 * 一个进程中也可以同时运行多个线程, 我们…

ADC的认识

ADC介绍 Q:ADC是什么? A:全称:Analog-to-Digital Converter,指模拟/数字转换器 ADC的性能指标 量程:能测量的电压范围分辨率:ADC能辨别的最小模拟量,通常以输出二进制数的位数表示&#xf…

有限差分法求解一维、二维波动方程

差分格式方法是数值计算方法中微分以及偏微分导数的一种离散化方法。具体来说,它使用相邻两个或者多个数值点的差分来取代偏微分方程中的导数或偏导数。选择差分格式是离散化偏微分方程的第一步,通过这种离散化,我们可以将连续空间区域上的问…

面试通关秘籍:一面到终面的秘密

在当今竞争激烈的职场中,面试已经成为求职者和企业之间互相了解和选择的重要环节。面试过程常常被划分为多个阶段,包括一面(初次面试)、二面(二次面试)、三面(深入面试)以及终面&…