数据结构—双链表

双链表就是带头-循环-双向的链表,下面我们来实现一下双链表

双链表的初始化

双链表由数据(data)、指向下一节点的指针(next)、指向上一节点的指针(prev)组成

cpp 复制代码
LTNode* LTBuyNode(LTDataType x)
{
	LTNode* tmp = (LTNode*)malloc(sizeof(LTNode));
	if (tmp == NULL)
	{
		perror("LTBuyNode");
		exit(1);
	}
	//空双向链表表示哨兵位两个指针指向他自己
	// 不代表指针为空指针
	//因为双向链表是循环的,所以头结点的两个指针均指向他自己
	tmp->data = x;
	tmp->next = tmp;
	tmp->prev = tmp;
	return tmp;
}
void LTInit(LTNode** pphead)
{
	*pphead = LTBuyNode(-1);
}

双链表中插入数据

在双链表的尾部插入数据

cpp 复制代码
//哨兵位的节点不能被删除也不能被修改,所以传一级指针即可
//先修改新节点的两个指针,在修改哨兵位的指针
void LTPushBack(LTNode* phead, LTDataType x)
{
	//将新节点插入到头节点前面
	LTNode* tmp = LTBuyNode(x);
	tmp->next = phead;
	tmp->prev = phead->prev ;
	//先修改尾节点指向新节点,再修改尾节点为新节点
	phead->prev->next = tmp;
	phead->prev = tmp;
}

在双链表的头部插入数据

cpp 复制代码
void LTPushFront(LTNode* phead, LTDataType x)
{
	//将新节点插入到第一个有效节点的前面就是头插
	//还是先修改新节点的两个指针
	LTNode* newNode = LTBuyNode(x);
	newNode->prev = phead;
	newNode->next = phead->next;
	phead->next->prev = newNode;
	phead->next = newNode;
}

在双链表指定位置之后插入数据

cpp 复制代码
void LTInsert(LTNode* pos, LTDataType x)
{
	//在指定位置之后插入节点
	//依旧是先修改新节点的指针
	assert(pos);
	LTNode* newNode = LTBuyNode(x);
	newNode->prev = pos;
	newNode->next = pos->next;
	pos->next->prev = newNode;
	pos->next = newNode;
}

双链表删除数据

删除双链表尾部的数据

cpp 复制代码
void LTPopBack(LTNode* phead)
{
	//将倒数第二个节点的下一个节点改成头节点
	//将头结点的上一个节点改成倒数第二个节点
	assert(phead);
	LTNode* tmp = phead->prev;
	tmp->prev->next = phead;
	phead->prev = tmp->prev;
	free(tmp);
	tmp = NULL;
}

删除双链表头部的数据

cpp 复制代码
void LTPopFront(LTNode* phead)
{
	assert(phead);
	LTNode* tmp = phead->next;
	phead->next = tmp->next;
	tmp->next->prev = phead;
	free(tmp);
	tmp = NULL;
}

删除双链表指定位置的数据

cpp 复制代码
void LTErase(LTNode* pos)
{
	assert(pos);
	//pos不能是哨兵位
	//这里虽然对pos指针进行了修改,但是为了保证
	//函数接口的一致性,所以传一级指针。
    //但是这样并不会对实参置空,所以要在主函数中对实参置空
	pos->next->prev = pos->prev;
	pos->prev->next = pos->next;
	free(pos);
	pos = NULL;
}

查找双链表中的数据

cpp 复制代码
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;
}

双链表的销毁

cpp 复制代码
void LTDestroy(LTNode* phead)
{
	//这里同样为了函数接口一致性,传递一级指针
	//在主函数中需要释放掉实参的内存
	assert(phead);
	LTNode* pcur = phead->next;
	LTNode* prev = phead->next;
	while (prev != phead)
	{
		pcur = pcur->next;
		free(prev);
		prev = pcur;
	}
	free(phead);
	phead = NULL;
}
相关推荐
小灰灰搞电子5 分钟前
Qt 队列容器 QQueue 的详解与示例
开发语言·qt·qqueue
码哥DFS20 分钟前
算法练习day1-备战2027届秋招
前端·javascript·数据结构·算法
ACP广源盛1392462567331 分钟前
GSV6155@ACP# Type-C 视频信号转换芯片:技术架构、工程痛点适配与落地场景分析
大数据·c语言·开发语言·人工智能·分布式·嵌入式硬件·架构
MartinYeung532 分钟前
[论文学习]Skill-MAS:面向自动多智能体系统的元技能进化
大数据·人工智能·学习
阳光九叶草LXGZXJ35 分钟前
达梦数据库-报错-11-cmd 13 validate error
linux·运维·数据库·sql·学习
光子物联单片机35 分钟前
STM32传感器模块编程实践(二十一)DIY语音控制小车套件模型
c语言·stm32·单片机·嵌入式硬件·mcu
程序员-Benothing38 分钟前
Java集合:List实现类深度对比
java·开发语言·后端·面试·list
wabs66640 分钟前
关于图论【卡码网108.多余的边的思考】
数据结构·算法·图论
~光~~40 分钟前
【嵌入式linux学习_OV8858 bring up】L1_从Sensor到RK3588发生了什么
linux·运维·学习
酷在前行1 小时前
【R论文复刻】Nature Communications 冲积图进阶:状态转移、流带排序与多面板排版(保姆级教程)
开发语言·r语言