【C语言|数据结构】双向链表

news2024/10/6 8:24:00

文章目录

    • 前言
    • 1、初步认识双向链表
        • 1.1 定义:
        • 1.2 结构
        • 1.3 节点的存储
    • 2、双向链表的接口函数
        • 2.1 链表的节点的动态申请
        • 2.2 链表的初始化
        • 2.3 尾插
        • 2.4 头插
        • 2.5 头删
        • 2.5 尾删
        • 2.6 在pos节点后面添加数据
        • 2.6 删除pos节点
    • 3、双向链表的实现:

前言

各位小伙伴大家好,即上回的单向链表之后,双向链表来了,他和单向链表的主要区别就是,他有两个指针,同时指向前面一个节点,和后面一个节点,简直是完美,几乎解决的单向链表的大多数难题

1、初步认识双向链表

1.1 定义:

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向前面一个节点和后面一个节点。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。

1.2 结构

在这里插入图片描述

这是带头的双向循环链表。

1.3 节点的存储
typedef int DLDataType;

typedef struct LinkNode
{
	DLDataType data;
	struct LinkNode* next;
	struct LinkNode* prv;
}LNode;

2、双向链表的接口函数

2.1 链表的节点的动态申请
LTNode* LTFound(DLDataType x)
{
	LTNode* newNode = (LTNode*)malloc(sizeof(LTNode));

	if (newNode == NULL)
	{
		perror("LTInit()::malloc()");
		return;
	}

	newNode->next = newNode->prv = newNode;
	newNode->data = x;
	return newNode;
}
2.2 链表的初始化
// 法一:
LTNode* LTInit()
{
	LTNode* newhead = LTFound(-1);

	return newhead;
}
法二:
void LTInit(LTNode** pphead)
{
	LTNode* newhead = LTFound(-1);
	*phead = newhead;
}
2.3 尾插
void LTPushBack(LTNode* phead, DLDataType x)
{
	assert(phead);
	 
	LTNode* cmp = LTFound(x);

	// phead phead->prv cmp
	cmp->next = phead;
	cmp->prv = phead->prv;

	phead->prv->next = cmp;
	phead->prv = cmp;
}

尾插这个节点不管是插入在头节点的前面还是尾节点后面都是一样的

2.4 头插
//头插
void LTPushFront(LTNode* phead, DLDataType x)
{
	assert(phead);

	LTNode* tmp = LTFound(x);

	// phead tmp phead->next

	tmp->next = phead->next;
	tmp->prv = phead;

	phead->next = tmp;
	phead->next->prv = tmp;
}

头插必须插入在头节点的后面才是头插,头节点就是哨兵卫,链表进行操作的时候不能操作哨兵卫,否则就不带头了。

2.5 头删
//头删
void LTPopFront(LTNode* phead)
{
	assert(phead && phead->next != phead);
	
	LTNode* cur = phead->next;
	// phead  cur cur->next

	phead->next = cur->next;
	cur->next = phead;

	free(cur);
	cur = NULL;
}
2.5 尾删
//尾删
void LTPopBack(LTNode* phead)
{
	assert(phead && phead->next != phead);

	LTNode* cur = phead->prv;
	
	// phead cur->prv cur
	phead->prv = cur->prv;
	cur->prv->next = phead;

	free(cur);
	cur = NULL;
}
2.6 在pos节点后面添加数据
//在pos位置之后插入数据
void LTInsert(LTNode* pos, DLDataType x)
{
	assert(pos);

	LTNode* cur = LTCreate(x);

	// pos cur pos->next
	cur->next = pos->next;
	cur->prv = pos;

	pos->next = cur;
	pos->next->prv = cur;

}
2.6 删除pos节点
//删除pos节点
void LTErase(LTNode* pos)
{
	assert(pos);

	// pos->prv pos pos->next

	pos->prv->next = pos->next;
	pos->next->prv = pos->prv;

	free(pos);
	pos = NULL;
}

3、双向链表的实现:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <string.h>

typedef int DLDataType;

typedef struct LinkNode
{
	DLDataType data;
	struct LinkNode* next;
	struct LinkNode* prv;
}LTNode;

//双链表的节点创建
LTNode* LTCreate(DLDataType x)
{
	LTNode* newNode = (LTNode*)malloc(sizeof(LTNode));

	if (newNode == NULL)
	{
		perror("LTInit()::malloc()");
		exit(-1);
	}

	newNode->next = newNode;
	newNode->prv = newNode;
	newNode->data = x;
	return newNode;
}

//初始化
//void LTInit(LTNode** pphead)
//{
//	LTNode* newhead = LTFound(-1);
//}

LTNode* LTInit()
{
	LTNode* newhead = LTCreate(-1);

	return newhead;
}

//销毁链表
void LTDesTroy(LTNode* phead)
{
	assert(phead);

	LTNode* cur = phead->next;

	while (cur != phead)
	{
		LTNode* next = cur->next;
		free(cur);
		cur = next;
	}

	free(phead);
	phead = NULL;
}

//链表的打印
void LTPrint(LTNode* phead)
{
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

//查找pos节点
LTNode* LTFind(LTNode* phead, DLDataType x)
{
	assert(phead);

	LTNode* cur = phead->next;
	while (cur != phead)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

//插入数据之前,链表必须初始化到只有一个头结点的情况
//不改变哨兵位的地址,因此传一级即可
//尾插
void LTPushBack(LTNode* phead, DLDataType x)
{
	assert(phead);

	LTNode* cmp = LTCreate(x);

	// phead phead->prv cmp
	cmp->next = phead;
	cmp->prv = phead->prv;

	phead->prv->next = cmp;
	phead->prv = cmp;
}

//头插
void LTPushFront(LTNode* phead, DLDataType x)
{
	assert(phead);

	LTNode* tmp = LTCreate(x);

	// phead tmp phead->next

	tmp->next = phead->next;
	tmp->prv = phead;

	phead->next = tmp;
	phead->next->prv = tmp;
}


//尾删
void LTPopBack(LTNode* phead)
{
	assert(phead && phead->next != phead);

	LTNode* cur = phead->prv;

	// phead cur->prv cur
	phead->prv = cur->prv;
	cur->prv->next = phead;

	free(cur);
	cur = NULL;
}

//头删
void LTPopFront(LTNode* phead)
{
	assert(phead && phead->next != phead);

	LTNode* cur = phead->next;
	// phead  cur cur->next

	phead->next = cur->next;
	cur->next = phead;

	free(cur);
	cur = NULL;
}

//在pos位置之后插入数据
void LTInsert(LTNode* pos, DLDataType x)
{
	assert(pos);

	LTNode* cur = LTCreate(x);

	// pos cur pos->next
	cur->next = pos->next;
	cur->prv = pos;

	pos->next = cur;
	pos->next->prv = cur;

}

//删除pos节点
void LTErase(LTNode* pos)
{
	assert(pos);

	// pos->prv pos pos->next

	pos->prv->next = pos->next;
	pos->next->prv = pos->prv;

	free(pos);
	pos = NULL;
}


void DLinkListText()
{
	LTNode* phead = LTInit();

	LTPushBack(phead, 1);
	LTPushBack(phead, 2);
	LTPushBack(phead, 3);
	LTPrint(phead);

	LTPushFront(phead, 0);
	LTPushFront(phead, 999);
	LTPrint(phead);

	// LTPopFront(phead);
	// LTPrint(phead);

	LTPopBack(phead);
	LTPrint(phead);

	LTDesTroy(phead);
}
	



int main()
{
	DLinkListText();
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

读人工智能时代与人类未来笔记01_重塑人类社会秩序

1. AlphaZero 1.1. 2017年年底&#xff0c;由谷歌旗下DeepMind公司开发的人工智能程序AlphaZero击败了当时世界上最强大的国际象棋程序Stockfish 1.1.1. AlphaZero对Stockfish的百场战绩是28胜72平0负&#xff0c;可以说获得了压倒性的胜利 1.1.2. …

嵌入式学习-中断控制系统

补充一下前面NVIC内嵌向量中断控制器的知识 中断 中断类型 中断控制 配置中断 优先级 分组问题 中断使能 NVIC相关库函数和作用 库函数 函数名 描述 NVIC_DeInit 将外设 NVIC 寄存器重设为初始值 NVIC_SCBDeInit 将外设 SCB 寄存器重设为初始值 NVIC_PriorityGroupCon…

C++ | Leetcode C++题解之第85题最大矩形

题目&#xff1a; 题解&#xff1a; class Solution { public:int maximalRectangle(vector<vector<char>>& matrix) {int m matrix.size();if (m 0) {return 0;}int n matrix[0].size();vector<vector<int>> left(m, vector<int>(n, 0)…

用 Python 从头开始​​编写线性回归

找到最佳拟合线的方法是使用梯度下降&#xff0c;我们将随机绘制一条线&#xff0c;计算该线的误差 计算误差 给定m和b&#xff0c;我们将计算直线的误差。Eeeor用sigma表示法表示 def compute_error_for_line_given_points(b, m, points):totalError 0for i in range(0, len…

职校智慧校园现状及问题分析

各大中职院校及高职院校是校园信息化的先行者和开拓者&#xff0c;很早就开始注重信息化基础设施建设和信息化人文素养的提升。在过去几年里&#xff0c;随着国家大力发展与扶植职校教育&#xff0c;学校投入相当的经费进行了校园信息通信网络、计算机等基础硬件设备建设&#…

AR系列路由器配置VLAN间通信

AR路由器是华为公司推出的企业级路由器产品系列&#xff0c;具有高可靠性、高性能和易管理等特点。AR 系列路由器提供的功能包括路由转发、安全接入、语音、视频、无线等多种业务&#xff0c;支持各种接入方式和协议&#xff0c;并且可以方便地进行扩展和升级。 实验拓扑图&…

打造清洁宜居家园保护自然生态环境,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建自然生态场景下违规违法垃圾倾倒检测识别系统

自然生态环境&#xff0c;作为我们人类赖以生存的家园&#xff0c;其健康与否直接关系到我们的生活质量。然而&#xff0c;近年来&#xff0c;一些不法分子为了个人私利&#xff0c;在河边、路边等公共区域肆意倾倒垃圾&#xff0c;严重破坏了环境的健康与平衡。这种行为不仅损…

【无标题】能效?性能?一个关于openssl speed速度测试的诡异问题。

问题描述 最近的某个软件用到了openssl&#xff0c;所以就想着测试一下速度。我的电脑是惠普的&#xff0c;CPU是AMD Ryzen 7 PRO 6850HS&#xff0c;系统是Win11。我使用openssl自带的speed测试加密/解密的速度&#xff0c;命令大致如下&#xff1a; openssl speed -evp aes…

中仕公考:公务员考试都有哪些类型?

1、国考&#xff1a;国考即国家公务员考试&#xff0c;是全国统一招考。每年10月份发布公告&#xff0c;11月份笔试&#xff0c;涉及的岗位比较多。 2、省考&#xff1a;省考是各省份公务员考试&#xff0c;主要是地方各级组织的统一考试。分为全国联考和非联考&#xff0c;一…

一键自动生成视频字幕,高效实用的视频后期工具:VideoSrt

VideoSrt&#xff1a;一键高效&#xff1a;专业级视频音频字幕自动生成功能- 精选真开源&#xff0c;释放新价值。 概览 VideoSrt是一款专为高效媒体后期制作设计的工具&#xff0c;它采用了Golang编程语言&#xff0c;并基于lxn/walk GUI库构建&#xff0c;专为Windows环境优…

如何快速变得专业:掌握类的基本概念-类/方法/关键字/变量/数据类型/注释

在李笑来的《财富自由之路》中提到一种初学者快速入门的学习方法&#xff1a;快速掌握最小必要知识。 关于Java的类&#xff0c;最少必要知识就是本文提到的基本概念&#xff0c;掌握了这些基本概念&#xff0c;就对类有了基本的了解&#xff0c;为后续的深入学习和沟通奠定了基…

C++基础与深度解析 | 什么是C++ | C++开发环境与相关工具 | C++编译/链接模型

文章目录 一、什么是C二、C的开发环境与相关工具三、C的编译/链接模型 一、什么是C C是一门比较流行的编程语言&#xff08;高级语言&#xff09;&#xff0c;同时也是一门复杂的语言。从TIOBE 编程社区指数中可以看出&#xff1a;在2024.04中&#xff0c;其编程语言受欢迎程度…

1. 抓娃娃-二分

因为这个限制&#xff0c;所以不用担心线段比区间长 线段一定比区间短的话&#xff0c;想要判断是否线段的二分之一及以上在区间内&#xff0c;则可以转化为线段中点是否在区间内的问题 如果没有那个限制&#xff0c;那么就无法这么考虑了&#xff0c;因为即使中点在区间内&…

C++笔试强训day19

目录 1.小易的升级之路 2.礼物的最大价值 3.对称之美 1.小易的升级之路 链接 模拟就行&#xff0c;唯一可能是难点得就是gcd&#xff08;最大公约数&#xff09; #include <iostream> using namespace std; #define int long long const int N 1e5 10; int arr[N];…

wsl安装Xfce桌面并设置系统语言和输入法

一、安装xfce &#xff08;有相关的依赖都会安装&#xff09; sudo apt -y install xfce4 二、 安装远程连接组件 sudo apt install xrdp -y 并重新启动 Xrdp 服务&#xff1a; sudo systemctl restart xrdp 本地windows系统中请按 winR 键 呼出运行 在运行中输入 mstsc…

考研OSchap4文件管理chap5磁盘管理(部分)

目录 一、整体认知 1.文件的定义 250 2.文件的属性 251 3.文件内部应该如何被组织(逻辑结构) 256 4.文件之间应该如何被组织起来(目录结构) 252 5.OS应该向上提供哪些功能 253 6.文件应该如何存放在外存中(物理结构) 258 7.OS如何管理外存中的空闲块(存储空间的管理) 25…

基于数据挖掘与机器学习揭秘脱发主因

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 基于数据挖掘与机器学习揭秘脱发主因 目录 一、绪论背景描述数据说明内容大概 二、导入包以及数据读取三、数据预览四、探究导致脱发的因素4.1…

Java随笔1

1.编程中组件的概念&#xff1a; 在编程中&#xff0c;组件&#xff08;Component&#xff09;通常指的是一种可重用的、模块化的代码单元&#xff0c;它封装了特定的功能或用户界面元素&#xff0c;并提供了与其他代码进行交互的接口。组件可以看作是对数据和方法的简单封装&…

docker-compose安装emqx集群(最新)(host模式)

机器&#xff1a; 10.60.0.20 10.60.0.21 10.60.0.22 一、三台机子都配置域名&#xff08;/etc/hosts&#xff09; 10.60.0.20 node1.emqx.io 10.60.0.22 node3.emqx.io 10.60.0.21 node2.emqx.io 二、docker-compose.yml&#xff08;10.60.0.21&#xff09; 其他两台机子自…

机器学习(五) ----------决策树算法

目录 1 核心思想 2 决策树算法主要步骤 3 决策树算法的分类 3.1 ID3算法&#xff08;Iterative Dichotomiser 3&#xff09;&#xff1a; 3.1.1 基本步骤 3.1.2 原理 信息增益 3.1.3 注意事项 3.2 C4.5算法&#xff1a; 3.2.1. 信息增益率 计算公式 3.2.2. 构建决策…