【数据结构】手撕双向链表

目录

前言

1. 双向链表 

带头双向循环链表的结构

2. 链表的实现

2.1 初始化

2.2 尾插

2.3 尾删

2.4 头插

2.5 头删

2.6 在pos位置之前插入

2.7 删除pos位置

3.双向链表完整源码

List.h

List.c


前言

在上一期中我们介绍了单链表,也做了一些练习题,在一些题中使用单链表会十分繁琐。因为单链表只能正着走,不能倒着走,例如:回文、逆置。本期我们将学习带头双向循环链表。

1. 双向链表 

带头双向循环链表的结构

 特点:带头双向循环链表结构最复杂,一般用在单独存储数据。结构虽然结构复杂,但是使用代码实现以后会发现结构会带来多优势,实现反而简单了。

2. 链表的实现

2.1 初始化

LTNode* LTInit()
{
	LTNode* phead = CreateLTNode(-1);
	phead->next = phead;
	phead->prev = phead;
	return phead;
}

2.2 尾插

带哨兵位的链表尾插时不用判断是否有节点,两种情况的插入相同,而且还不用传递二级指针。

void LTPushBack(LTNode* phead, LTDateType x)
{
	assert(phead);

	LTNode* newnode = CreateLTNode(x);
	phead->prev->next = newnode;
	newnode->prev = phead->prev;
	newnode->next = phead;
	phead->prev = newnode;
}

2.3 尾删

在尾删时我们通过 assert(phead->next != phead);  判断链表是否有节点。同时这个代码就有普遍性,不用单独考虑剩一个节点的情况。

void LTPopBack(LTNode* phead)
{
	assert(phead);
	LTNode* tail = phead->prev;
	LTNode* tailprev = tail->prev;
	free(tail);
	phead->prev = tailprev;
	tailprev->next = phead;
}

2.4 头插

头删重要的是赋值的顺序,顺序错误会找不到后面的节点,导致内存泄漏。带哨兵位的链表不需要传递二级指针,因为改变的是结构体的变量。

void LTPushFront(LTNode* phead, LTDateType x)
{
	assert(phead);
	LTNode* newnode = CreateLTNode(x);
	newnode->next = phead->next;
	phead->next->prev = newnode;
	phead->next = newnode;
	newnode->prev = phead;
}

2.5 头删

我们可以多定义几个指针来保存后面节点的地址,这样就不会造成节点的丢失,不用考虑赋值的顺序,会更加方便。 

void LTPopFront(LTNode* phead)
{
	assert(phead);
	assert(phead->next != phead);

	LTNode* tail = phead->next;
	LTNode* next = tail->next;
	phead->next = next;
	next->prev = phead;
	free(tail);
	tail = NULL;
}

2.6 在pos位置之前插入

void LTInsert(LTNode* pos, LTDateType x)
{
	assert(pos);

	LTNode* posprev = pos->prev;
	LTNode* newnode = CreateLTNode(x);
	posprev->next = newnode;
	newnode->prev = posprev;
	newnode->next = pos;
	pos->prev = newnode;
}

2.7 删除pos位置

void LTErase(LTNode* pos)
{
	assert(pos);

	LTNode* posprev = pos->prev;
	LTNode* posnext = pos->next;
	posprev->next = posnext;
	posnext->prev = posprev;
}

3.双向链表完整源码

List.h

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

typedef int LTDateType;

typedef struct ListNode
{
	LTDateType val;
	struct ListNode* next;
	struct ListNode* prev;
}LTNode;

LTNode* LTInit();

void LTPrint(LTNode* phead);

void LTPushBack(LTNode* phead, LTDateType x);

void LTPushFront(LTNode* phead, LTDateType x);

void LTPopBack(LTNode* phead);

void LTPopFront(LTNode* phead);

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

void LTInsert(LTNode* pos, LTDateType x);

void LTErase(LTNode* pos);

void LTDestroy(LTNode* phead);

List.c

#include"List.h"

LTNode* CreateLTNode(LTDateType x)
{
	LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	newnode->val = x;
	newnode->next = NULL;
	newnode->prev = NULL;
}

LTNode* LTInit()
{
	LTNode* phead = CreateLTNode(-1);
	phead->next = phead;
	phead->prev = phead;
	return phead;
}

void LTPrint(LTNode* phead)
{
	assert(phead);
	LTNode* cur = phead->next;
	printf("<=>哨兵位<=>");
	while (cur != phead)
	{
		printf("%d<=>", cur->val);
		cur = cur->next;
	}
	printf("\n");
}

void LTPushBack(LTNode* phead, LTDateType x)
{
	assert(phead);

	LTNode* newnode = CreateLTNode(x);
	phead->prev->next = newnode;
	newnode->prev = phead->prev;
	newnode->next = phead;
	phead->prev = newnode;
}

void LTPushFront(LTNode* phead, LTDateType x)
{
	assert(phead);
	LTNode* newnode = CreateLTNode(x);
	newnode->next = phead->next;
	phead->next->prev = newnode;
	phead->next = newnode;
	newnode->prev = phead;
}

void LTPopBack(LTNode* phead)
{
	assert(phead);
	LTNode* tail = phead->prev;
	LTNode* tailprev = tail->prev;
	free(tail);
	phead->prev = tailprev;
	tailprev->next = phead;
}

void LTPopFront(LTNode* phead)
{
	assert(phead);
	assert(phead->next != phead);

	LTNode* tail = phead->next;
	LTNode* next = tail->next;
	phead->next = next;
	next->prev = phead;
	free(tail);
	tail = NULL;
}

LTNode* LTFind(LTNode* phead, LTDateType x)
{
	assert(phead);

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

void LTInsert(LTNode* pos, LTDateType x)
{
	assert(pos);

	LTNode* posprev = pos->prev;
	LTNode* newnode = CreateLTNode(x);
	posprev->next = newnode;
	newnode->prev = posprev;
	newnode->next = pos;
	pos->prev = newnode;
}

void LTErase(LTNode* pos)
{
	assert(pos);

	LTNode* posprev = pos->prev;
	LTNode* posnext = pos->next;
	posprev->next = posnext;
	posnext->prev = posprev;
}

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;
}

通过上面链表的实现,我们已经感受到了带头双向循环链表的方便和简单,它不需要去考虑链表是否有元素,还可以找到前一个元素,在我们使用中提供很大的便利。

本次的内容到这里就结束啦。希望大家阅读完可以有所收获,同时也感谢各位读者三连支持。文章有问题可以在评论区留言,博主一定认真认真修改,以后写出更好的文章。 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IC设计企业,如何安全、可控、高效的传输设计文档和研发数据?

近年来&#xff0c;半导体的应用领域不断拓展&#xff0c;在全球经济和社会发展中的重要性与日俱增&#xff0c;半导体芯片是数字经济的核心&#xff0c;承载着现代产业发展&#xff0c;具有举足轻重的价值。从半导体行业的角度&#xff0c;IC设计是关键的一环&#xff0c;我国…

中科创达:坚定看好未来十五年的大模型机遇

中科创达是一家成立于2008年的智能操作系统产品和技术提供商&#xff0c;15年前公司成立的时候正赶上了安卓操作系统将功能手机推向了智能手机&#xff0c;截至目前&#xff0c;已赋能超过近9亿台手机走向市场。2014年中科创达开始拓展智能汽车方向&#xff0c;2015年拓展物联网…

CSGO的那些事儿:CS2这么差,为什么不改回CS1?

揭秘csgo饰品涨价背后的残酷真相 1、V社现在更新内容集中在游戏性的修复方面。 所以原来期望的新地图新大行动等&#xff0c;要等到游戏本体趋于稳定后才更新。但是&#xff0c;因为距离下一个大型活动&#xff0c;也就是丹麦major还有5个月时间&#xff0c;那这之间必然要有一…

kubernetes 高可用集群

目录 一、haproxy负载均衡 二、pacemaker高可用 三、部署control-plane 四、部署worker node 实验环境 主机名 IP 角色 docker 192.168.67.10 harbor k8s1 192.168.67.11 control-plane k8s2 192.168.67.12 control-plane k8s3 192.168.67.13 control-plane k8s…

opencv(5): 滤波器

滤波的作用&#xff1a;一幅图像通过滤波器得到另一幅图像&#xff1b;其中滤波器又称为卷积核&#xff0c;滤波的过程称为卷积。 锐化&#xff1a;边缘变清晰 低通滤波&#xff08;Low-pass Filtering&#xff09;&#xff1a; 目标&#xff1a;去除图像中的高频成分&#…

【打卡】牛客网:BM55 没有重复项数字的全排列

自己写的&#xff1a; 虽然题目要求了排序&#xff0c;但是我没排序也可以通过。 class Solution { public:/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定的值即可** * param num int整型vector * return int整型vector<vec…

23届计科,想找Java开发之类,真的是很难吗?

23届计科&#xff0c;想找Java开发之类&#xff0c;真的是很难吗&#xff1f; 你的投递信息(投递多少家&#xff0c;如何跟hr打招呼&#xff0c;已读不回如何应对等)都亮- -下才能知道问题出在 哪。最近很多小伙伴找我&#xff0c;说想要一些Java的资料&#xff0c;然后我根据…

Ubuntu 下C++数字雨

以前写过一个Window下的数字雨&#xff0c;像黑客帝国里那样的01数字&#xff0c;现在补充一版Linux下的。使用了curses库&#xff0c;安装方法与使用方法参照 Linux下curses函数库的详细介绍_libcurses库-CSDN博客 5-linux学习笔记之-----curses-CSDN博客 效果如下&#xf…

21. 深度学习 - 拓朴排序的原理和实现

文章目录 Hi,你好。我是茶桁。 上节课&#xff0c;我们讲了多层神经网络的原理&#xff0c;并且明白了&#xff0c;数据量是层级无法超过3层的主要原因。 然后我们用一张图来解释了整个链式求导的过程&#xff1a; 那么&#xff0c;我们如何将这张图里的节点关系来获得它的求…

抖音自动评论脚本,可按关键词,实现批量点赞,按键精灵开源版!

这个脚本是我之前给一个客户开发的&#xff0c;现在用着也没啥意义&#xff0c;开发了很多&#xff0c;我索性就把代码直接分享出来&#xff0c;给一些新手做学习研究用&#xff0c;里面很多结构都是自己花费了很大的心思和心血才弄出来的&#xff0c;所以价值很高。 UI界面&a…

OpenAI GPT5计划泄露

OpenAI的首席执行官萨姆奥特曼在最近接受《金融时报》的专访时&#xff0c;分享了OpenAI未来发展的一些新动向。此外&#xff0c;他还透露了关于即将到来的GPT-5模型以及公司对AGI的长期目标的一些细节。 奥特曼指出&#xff1a; 1.OpenAI正在开发GPT-5&#xff0c;一种更先进的…

QT绘图设备

pixmap绘图设备在磁盘上进行绘图 通过pix.save将图片保存到E盘下 不是主要的绘画设备&#xff0c;可以将绘图指令保存 然后在下边可以调用重现绘图指令

多媒体领域顶会ACM MM 2023 获奖论文一览

ACM 国际多媒体会议是计算机科学领域中多媒体领域的顶级会议&#xff0c;属于CCF A类。今年的ACM MM 2023 已于2023年10月29日至11月2日在加拿大渥太华举行。 ACM MM会议专注于推动多媒体研究和应用&#xff0c;其研究领域广泛涉及触觉、视频、VR/AR、音频、语音、音乐、传感器…

Unity 场景烘培 ——LensFlare镜头光晕(三)

提示&#xff1a;文章有错误的地方&#xff0c;还望诸位大神指出&#xff01; 文章目录 前言一、镜头光晕 (Lens Flares)是什么&#xff1f;二、使用Lens Flares组件总结 前言 一般情况下都会忽略的东西&#xff0c;镜头光晕。理论上不加镜头光晕&#xff0c;也不会有什么影响…

Linux---(七)Makefile写进度条(三个版本)

文章目录 一、前提引入&#x1f397;️下面的代码什么现象&#xff1f;&#x1f397;️下面的代码什么现象&#xff1f; 二、缓冲区三、回车换行&#x1f397;️注意&#x1f397;️图解&#x1f397;️老式回车键造型&#xff08;意思是充当两个动作&#xff09;&#x1f397;…

洛谷 P3131 [USACO16JAN] Subsequences Summing to Sevens S

被普及-卡的没思路真是蒟蒻啊233 优化思路 每次都在枚举(a[r]-a[l-1])%70&#xff0c;所以可以认为数组大小对最终答案没有影响&#xff0c;考虑对前缀和数组取模&#xff0c;那么如果有a[r]的值等于a[l-1]的值相等&#xff08;即余数相等&#xff09;&#xff0c;那么两者相减…

C++实现KNN和K-Means

学校机器学习课程的实验课要求实现KNN和K-Means&#xff1a; &#xff08;平时没听课&#xff09;临时去查了一下KNN和K-Means是啥&#xff0c;然后自己用C写了小例子&#xff0c;想着写都写了那就把代码贴出来吧。 顺便再聊聊自己对于这俩算法的理解。 下面是文心一言的回答…

如何快速下载mysql的不同版本并启动mysql服务?

如何快速下载mysql的不同版本并启动mysql服务&#xff1f; 下载mysql的安装版本 首先我们要使用到迅雷去下载&#xff0c;因为迅雷下载是很快的。在迅雷里面搜索下面的Mysql Installer安装窗口&#xff0c;如下图&#xff1a; 连接&#xff1a;https://dev.mysql.com/downlo…

如何避免被他人“背刺”?

请公主们、王子们&#xff0c;花点时间看一下&#xff0c;谢谢。 在人与人相处中&#xff0c;难免不会碰上与人合作交往&#xff0c;虽然大多数时候我们是选择熟悉一点的朋友&#xff0c;但是也不能掉以轻心&#xff0c;现实生活中也不是不存在被亲戚朋友“背刺”&#xff0c;…

MySQL主从同步

文章目录 MySQL主从同步概述MySQL主从同步原理MySQL主从同步结构模式MySQL主从同步搭建搭建步骤一主一从实验环境master主机slave1主机验证主从同步 一主多从master主机slave2主机验证主从同步 链式复制&#xff08;主从从&#xff09;slave1主机slave2主机验证链式复制 MySQL主…