【数据结构】链表的分类和双向链表

本篇是基于上篇单链表所作,推荐与上篇配合阅读,效果更加

http://t.csdnimg.cn/UhXEj

1.链表的分类

链表的结构非常多样,以下情况组合起来就有8种(2 x 2 x 2)链表结构:
我们一般叫这个头为哨兵位
我们上回讲的单链表就是不带头单项不循环链表。
今天我们要讲带头双向循环的链表。
不过在次之前容我先为大家画一画8种链表结构:

1.带头单向循环链表:

2.带头单向不循环链表

3.带头双向循环链表

4.带头双向不循环链表

5.不带头单向循环链表

6.不带头单向不循环链表

7.不带头双向循环链表

8.不带头双向不循环链表

虽然有这么多的链表的结构,但是我们实际中最常用还是两种结构: 单链表 双向带头循环链表
1. 无头单向非循环链表:结构简单,⼀般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
2. 带头双向循环链表:结构最复杂,⼀般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了。

2.双向带头循环链表

我们还是经典三个文件:

我们先定义头文件所需要的函数

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>//定义双向链表中节点的结构
typedef int LTDataType;
typedef struct ListNode {LTDataType data;struct ListNode* prev;struct ListNode* next;
}LTNode;//注意,双向链表是带有哨兵位的,插入数据之前链表中必须要先初始化一个哨兵位
//void LTInit(LTNode** pphead);
LTNode* LTInit();
//void LTDesTroy(LTNode** pphead);
void LTDesTroy(LTNode* phead);   //推荐一级(保持接口一致性)void LTPrint(LTNode* phead);//不需要改变哨兵位,则不需要传二级指针
//如果需要修改哨兵位的话,则传二级指针
void LTPushBack(LTNode* phead, LTDataType x);
void LTPushFront(LTNode* phead, LTDataType x);//头删、尾删
void LTPopBack(LTNode* phead);
void LTPopFront(LTNode* phead);//查找
LTNode* LTFind(LTNode* phead, LTDataType x);//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x);
//删除pos位置的数据
void LTErase(LTNode* pos);

首先我们还是得先定义节点,由于是双向链表,所以节点内存在两个节点的地址,一个是前驱节点的(指向其前一个节点),一个是尾结点的(指向其后一个节点)

这一段代码,是为了确保数据类型

我们节点定义成这样:

接下来又是完成各个功能:增,删,查,改。但是,由于我们长线的是带头的链表,所以我们需要对头初始化

3.初始化

我们先定义初始化函数,然后写函数:

void LTInit(LTNode** pphead);
void ltinit(ltnode** pphead) {*pphead = (ltnode*)malloc(sizeof(ltnode));if (*pphead == null) {perror("malloc fail!");exit(1);}(*pphead)->data = -1;(*pphead)->next = (*pphead)->prev = *pphead;
}

和上回写单链表差不多,检测开辟是否成功,成功就接着给数据赋值,由于此时只有一个节点,即哨兵节点,且是循环链表,所以存放的前驱和尾节点就是哨兵节点自己

所以我们可以得出,如果哨兵节点的next指针或者prev指针指向自己,说明当前链表为空。

4.创建新的节点

我们写法和上次差不多

LTNode* LTBuyNode(LTDataType x) {LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));if (newnode == NULL) {perror("malloc fail!");exit(1);}newnode->data = x;newnode->next = newnode->prev = newnode;return newnode;
}

只是这回,多了一个前驱节点,我们定义时间默认前驱和后去节点指向的是本身。

但是既然我们都这么写了一个创建新节点的函数,那么我们可不可以用这个函数直接去进行哨兵节点的创建?

答案是肯定的,我们首先先改变以下我们定义的函数,

LTNode* LTInit();

然后调用创建新节点的函数,得到哨兵节点

LTNode* LTInit() {LTNode* phead = LTBuyNode(-1);return phead;
}

5.头插和尾插

注意:头插,是把新的节点插在第一个节点前,不是哨兵节点前

头插和尾插,头删和尾删的思路整体和单链表一致,我就不详细说明了,直接上代码

定义函数:

void LTPushBack(LTNode* phead, LTDataType x);
void LTPushFront(LTNode* phead, LTDataType x);

函数代码示例:

//尾插
void LTPushBack(LTNode* phead, LTDataType x) {assert(phead);LTNode* newnode = LTBuyNode(x);//phead phead->prev(ptail)  newnodenewnode->next = phead;newnode->prev = phead->prev;phead->prev->next = newnode;phead->prev = newnode;
}
//头插
void LTPushFront(LTNode* phead, LTDataType x) {assert(phead);LTNode* newnode = LTBuyNode(x);//phead newnode phead->nextnewnode->next = phead->next;newnode->prev = phead;phead->next->prev = newnode;phead->next = newnode;
}

不懂的你们可以再看看图:

6.头删和尾删

定义函数:

void LTPopBack(LTNode* phead);
void LTPopFront(LTNode* phead);

函数代码示例:

//尾删
void LTPopBack(LTNode* phead) {assert(phead);//链表为空:只有一个哨兵位节点assert(phead->next != phead);LTNode* del = phead->prev;LTNode* prev = del->prev;prev->next = phead;phead->prev = prev;free(del);del = NULL;
}
//头删
void LTPopFront(LTNode* phead) {assert(phead);assert(phead->next != phead);LTNode* del = phead->next;LTNode* next = del->next;//phead del nextnext->prev = phead;phead->next = next;free(del);del = NULL;
}

7.查找

整体思路还是遍历,和单链表十分相似

定义函数:

LTNode* LTFind(LTNode* phead, LTDataType x);

函数代码示例:

LTNode* LTFind(LTNode* phead, LTDataType x) {assert(phead);LTNode* pcur = phead->next;while (pcur != phead){if (pcur->data == x) {return pcur;}pcur = pcur->next;}return NULL;
}

8.在pos位置之后插入数据

这个和单恋表的也很相似,多了一个prev指针而已,写的时候要注意顺序,函数定义我就不写了

函数代码示例:

//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x) {assert(pos);LTNode* newnode = LTBuyNode(x);//pos newnode pos->nextnewnode->next = pos->next;newnode->prev = pos;pos->next->prev = newnode;pos->next = newnode;
}

9.删除pos位置的数据

这个和单链表还是一样的,遍历整个表,然后相爱指针指向的地址,然后释放内存

函数代码示例:

void LTErase(LTNode* pos) {assert(pos);//pos->prev pos  pos->nextpos->next->prev = pos->prev;pos->prev->next = pos->next;free(pos);pos = NULL;
}

10.打印

这个其实是用来看每个节点中间的数据的,我们可以通过前驱节点或者尾节点实现正序或逆序打印,这一步也是遍历然后看哨兵节点是否是下一位,是就中断,我这里之举一种例子,另一种只要将next改成prev

函数代码示例:

void LTPrint(LTNode* phead) {//phead不能为空assert(phead);LTNode* pcur = phead->next;while (pcur != phead){printf("%d->", pcur->data);pcur = pcur->next;}printf("\n");
}

11.销毁

这个链表的销毁和点链表不大一样,因为存在哨兵节点,所以我们要分开释放内存

函数代码示例:

void LTDesTroy(LTNode* phead) {//哨兵位不能为空assert(phead);LTNode* pcur = phead->next;while (pcur != phead){LTNode* next = pcur->next;free(pcur);pcur = next;}//链表中只有一个哨兵位free(phead);phead = NULL;
}

最后还是一如既往的测试环节就交给大家了。推荐阅读完http://t.csdnimg.cn/UhXEj

然后再阅读这个

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

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

相关文章

三星S24未破智能手机藩篱,AI Phone继续期待黑马

匆忙离开深圳机场的时候&#xff0c;《智物》遇到几位熟悉的老朋友。习惯了在中国市场边缘生存的&#xff0c;全球第一代智能手机企业三星公司&#xff0c;刚刚在此地录制完了新旗舰手机三星S24系列的发布会视频。 贵为全球第一大智能手机品牌的三星发布会居然不是直播。韩式套…

【嵌入式学习】C++QT-Day2-C++基础

笔记 见我的博客&#xff1a;https://lingjun.life/wiki/EmbeddedNote/19Cpp 作业 自己封装一个矩形类(Rect)&#xff0c;拥有私有属性:宽度(width)、高度(height)&#xff0c; 定义公有成员函数: 初始化函数:void init(int w, int h) 更改宽度的函数:set_w(int w) 更改高度…

PowerBI商业智能分析引入,带你了解什么是商务智能

一、商务智能工具 什么是Power BI &#xff1f;Power Bl是微软开发的一个软件&#xff0c;它是从获取数据、数据清洗、数据图表搭建、数据分析、共享发布为一体的软件&#xff0c;无论你的数据是简单的Excel电子表格&#xff0c;还是复杂庞大的数据库&#xff0c;Power Bl都可…

Linux-共享内存

文章目录 前言一、system V共享内存申请共享内存挂载共享内存删除共享内存挂载删除共享内存 二、示例代码三.运行效果 前言 在这之前我们已经学习了两种进程间通信方式&#xff1a;匿名管道和命名管道。 从我们之前的学习已经知道&#xff0c;想让多个进程间进行通信就需要让他…

sql管理工具archery简介

在平时的工作过程中&#xff0c;我们肯定会遇到使用sql平台的场景&#xff0c;业内也有很多工具&#xff0c;类似阿里云的dms&#xff0c;但是这个是和云厂商绑定的&#xff0c;我们可能一般没有用到阿里云组件就比较困难了&#xff0c;那还有什么选项了&#xff0c;经过调研&a…

创建第一个 Spring 项目(IDEA社区版)

文章目录 创建 Spring 项目创建一个普通的 Maven 项目添加 Spring 依赖IDEA更换国内源 运行第一个 Spring 项目新建启动类存储 Bean 对象将Bean注册到Spring 获取并使用 Bean 对象 创建 Spring 项目 创建一个普通的 Maven 项目 首先创建一个普通的 Maven 项目 添加 Spring 依…

Windows11 Copilot助手开启教程(免费GPT-4)

Windows11上开启Copilot助手教程踩坑指南 Copilot介绍Copilot开启步骤1、更新系统2、更改语言和区域3、下载 ViVeTool 工具4、开启Copilot 使用 Copilot介绍 Windows Copilot 是 Windows 11 中的一个新功能&#xff0c;它可以让你与一个智能助理进行对话&#xff0c;获取信息&…

05-Seata下SQL使用限制

不支持 SQL 嵌套不支持多表复杂 SQL(自1.6.0版本&#xff0c;MySQL支持UPDATE JOIN语句&#xff0c;详情请看不支持存储过程、触发器部分数据库不支持批量更新&#xff0c;在使用 MySQL、Mariadb、PostgreSQL9.6作为数据库时支持批量&#xff0c;批量更新方式如下以 Java 为例 …

k8s架构、工作流程、集群组件详解

目录 k8s概述 特性 作用&#xff08;为什么使用&#xff09; k8s架构 k8s工作流程 k8s集群架构与组件 核心组件详解 Master节点 Kube-apiserver Kube-controller-manager Kube-scheduler 存储中心 etcd Node Kubelet Kube-Proxy 网络通信模型 容器引擎 k8s核…

Java-NIO篇章(5)——Reactor反应器模式

前面已经讲过了Java-NIO中的三大核心组件Selector、Channel、Buffer&#xff0c;现在组件我们回了&#xff0c;但是如何实现一个超级高并发的socket网络通信程序呢&#xff1f;假设&#xff0c;我们只有一台内存为32G的Intel-i710八核的机器&#xff0c;如何实现同时2万个客户端…

http接口测试—自动化测试框架设计

一、测试需求描述 对服务后台一系列的http接口功能测试。 输入&#xff1a;根据接口描述构造不同的参数输入值&#xff08;Json格式&#xff09; 输出&#xff1a;字符串&#xff08;传入的方式传入的字符串&#xff09; http://localhost:8090/lctest/TestServer 二、程序设计…

C4.5决策树的基本建模流程

C4.5决策树的基本建模流程 作为ID3算法的升级版&#xff0c;C4.5在三个方面对ID3进行了优化&#xff1a; &#xff08;1&#xff09;它引入了信息值&#xff08;information value&#xff09;的概念来修正信息熵的计算结果&#xff0c;以抑制ID3更偏向于选择具有更多分类水平…

SpringCloud Aliba-Seata【下】-从入门到学废【8】

目录 1.数据库创建 1.seata_account库下建表 2.seata_order库下建表 3.seata_storage库下建表 4.在每个库下创建回滚日志 2.创建订单模块 2.1建工程 2.2加pom 2.3改yml 2.4file.conf 2.5registry.conf 2.6domain 2.7Dao 2.8Service 2.9controller 2.10confi…

BGP路由反射-数据中心IDC项目经验

一、背景描述 R1,R2,R3在AS200区域内&#xff0c;R1和R2,R1和R3建立OSPF&#xff0c;宣告接口互联. AS200区域内&#xff0c;R1和R2建立IBGP, R1和R3建立IBGP R2和R4建立EBGP, R3和R5建立EBGP。 网络拓扑&#xff1a; 二、故障现象 R1和R2可以收到来自AS100区域R4的E…

pytorch实战-6手写数字加法机-迁移学习

1 概述 迁移学习概念&#xff1a;将已经训练好的识别某些信息的网络拿去经过训练识别另外不同类别的信息 优越性&#xff1a;提高了训练模型利用率&#xff0c;解决了数据缺失的问题&#xff08;对于新的预测场景&#xff0c;不需要大量的数据&#xff0c;只需要少量数据即可…

Unity通用渲染管线升级URP、HDRP

Unity通用渲染管线升级URP、HDRP 一、Build-in Pipline升级到 URP 一、Build-in Pipline升级到 URP 安装URP包 升级所有材质&#xff08;升级完成后材质会变成紫红色&#xff0c;Shader丢失&#xff0c;此为正常现象&#xff09; 创建 UniversalRenderPipelineAsset 配置文…

Nacos 在云原生架构下的演进

作者&#xff1a;之卫 背景 Nacos 提供的最核心能力是动态服务发现与动态配置管理能力&#xff0c;在云原生环境下&#xff0c;借助云产品&#xff0c;如 EDAS&#xff08;企业级分布式应用服务&#xff09;平台中&#xff0c;我们可以很轻松地使用 K8s 来托管 Nacos 体系的微…

蓝桥杯(Python)每日练Day5

题目 OJ1229 题目分析 题目完全符合栈的特征&#xff0c;后进先出。如果能够熟练使用列表的9种方法那么这道题很容易解出。 题解 a[]#存衣服 nint(input()) for i in range(n):llist(input().split())#判断每一步的操作if len(l[0])2:a.append(l[1])else:while a.pop()!l…

大数据平台红蓝对抗 - 磨利刃,淬精兵!

背景 目前大促备战常见备战工作&#xff1a;专项压测&#xff08;全链路压测、内部压测&#xff09;、灾备演练、降级演练、限流、巡检&#xff08;监控、应用健康度&#xff09;、混沌演练&#xff08;红蓝对抗&#xff09;&#xff0c;如下图所示。随着平台业务越来越复杂&a…

LabVIEW探测器CAN总线系统

介绍了一个基于FPGA和LabVIEW的CAN总线通信系统&#xff0c;该系统专为与各单机进行系统联调测试而设计。通过设计FPGA的CAN总线功能模块和USB功能模块&#xff0c;以及利用LabVIEW开发的上位机程序&#xff0c;系统成功实现了CAN总线信息的收发、存储、解析及显示功能。测试结…