双向链表知识点(附源代码)

news2024/9/24 11:30:57

双向链表的特点

带头链表⾥的头结点,实际为“哨兵位”,哨兵位结点不存储任何有效元素,只是站在这⾥“放哨的”

例图解析

 双向链表与单链表的区别

双向链表:除了存储的数据外还有两个指针,具有头节点,还有循环的特点(因此就算链表只有一个节点的时候它前后节点是指向自己的而不是为null)。双向链表相比单链表在插入、删除和某些遍历操作上更高效。

单链表:可以有头节点也无头节点,不循环的。

如何构建一个双向链表

1.链表的初始化

双向链表有一个“标兵位”,这里新建的节点当作标兵位,这里有一点注意事项,主要是看进行传二级指针还是找有返回值这两种。如下是具体的代码实现。

void LTInit(LTNode** pphead)
{
    //创建一个头结点(哨兵位)
    pphead = LTBuyNode(-1);
}
//
LTNode* LTInit()
{
	LTNode* phead = LTBuyNode(-1);
	return phead;
}

2.尾插双向链表

尾插例图

尾插的时候一定要注意,不要先改变标兵位的指向,当标兵位置发生改变的时候后面节点的指向会出现指向错误。

3.头插双向链表

头插示意图

这里的头插,插入的是标兵位置后面,并不是首位置,图中可以看出首位置前面插入其实就是尾插而并不是头插。

4.头删双向链表

5.尾删双向链表

6.找到双向链表的指定位置

这里方法较为简单就不进行图像示意图,从“标兵位”后面开始寻找,找到所要寻找的元素进行返回就可以。

7.删除指定位置后面

通过找到的指定位置进行标记,然后通过标记位置对其后面进行插入,方法和尾插时的方法无异。

9.双向链表的销毁

双向表的销毁也是两种方法法一:不用二级指针进行传址,手动制空首元素,因为不进行二级指针传参这样形参的改变并不会改变实参,所以需要进行手动进行制空。

void LTDesTroy2(LTNode* phead)
{
	assert(phead);
	LTNode* pcur = phead->next;
	while (pcur != phead)
	{
		LTNode* Next = pcur->next;
		free(pcur);
		pcur = Next;
	}
	free(phead);
	phead = pcur = NULL;
}

 总结

单链表适合简单的单向遍历操作,内存消耗小;而双链表适合需要双向遍历或者频繁涉及节点前驱访问的场景,但是相应地需要更多的内存空间来存储额外的指针。最后希望各位大佬进行指正,并留下一键三连(点赞,收藏,关注)。

原码

list.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef struct ListNode ListNode;
typedef  int LTDataType;
struct ListNode
{
	LTDataType data;
	ListNode* next;
	ListNode* pre;
};
// 创建返回链表的头结点.
ListNode* ListInit();
// 双向链表销毁
void ListDestory(ListNode* pHead);
//判断是否为空
bool ListEmpty(ListNode* pHead);
// 双向链表打印
void ListPrint(ListNode* pHead);
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x);
// 双向链表尾删
void ListPopBack(ListNode* pHead);
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x);
// 双向链表头删
void ListPopFront(ListNode* pHead);
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);
//双向链表的销毁
void ListDestory(ListNode** pos);

list.c

#include"List.h"
//开辟一个节点
ListNode* LTBuyNode(LTDataType x)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode)); //开节点是开一个节点的空间
	if (newnode == NULL)
	{
		perror("fail!!!");
		exit(1);
	}
	newnode->data = x;
	newnode->next = newnode->pre = newnode;
	return newnode;
}
//初始化
ListNode* ListInit()
{
	ListNode* pHead = LTBuyNode(-1);
	return pHead;
}
//判断是否为空
bool ListEmpty(ListNode* pHead)
{
	assert(pHead);
	return pHead->next == pHead;
}
//尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	ListNode* newnode = LTBuyNode(x);

	newnode->next = pHead;
	newnode->pre = pHead->pre;
	pHead->pre->next = newnode;
	pHead->pre=newnode;
	
}
// 双向链表尾删
void ListPopBack(ListNode* pHead)
{
	assert(pHead);

	assert(!ListEmpty(pHead));
	ListNode* del = pHead->pre;
	pHead->pre = del->pre;
	del->pre->next = pHead;
	free(del);
	del = NULL;
}
//头插入
void ListPushFront(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	ListNode* newnode = LTBuyNode(x); //带头节点的头插
	newnode->next = pHead->next;
	pHead->next->pre = newnode;

	pHead->next = newnode;
	newnode->pre = pHead;


}
// 双向链表头删
void ListPopFront(ListNode* pHead)
{
	ListNode* del = pHead->next;
	pHead->next = del->next;
	del->next->pre = pHead;
	free(del);
	del = NULL;
}
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	ListNode* pcur = pHead->next;
	while (pcur!= pHead)
	{
		
		if (pcur->data == x)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	return NULL;
}
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);
	//pos前插入
	ListNode* newNode = LTBuyNode(x);
	newNode->next = pos;
	pos->pre->next = newNode;
	newNode->pre = pos->pre;
	pos->pre = newNode;
}
// 双向链表在pos的后面进行插入
void ListbackInsert(ListNode* pos, LTDataType x)
{
	assert(pos);
	//pos前插入
	ListNode* newNode = LTBuyNode(x);
	newNode->pre = pos;
	newNode->next = pos->next;
	pos->next->pre = newNode;
	pos->next = newNode;
}
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos)
{
	assert(pos);
	pos->pre->next=pos->next;
	pos->next->pre=pos->pre;
	free(pos);
	pos = NULL;

}
//双向链表的销毁
void ListDestory(ListNode** pHead)
{
	assert(pHead && *pHead);
	ListNode* pcur = (*pHead)->next;
	while (pcur != *pHead)
	{
		ListNode *next= pcur->next;
		free(pcur);
		pcur = next;
	}
	//对头节点进行释放
	free(*pHead);
	*pHead = NULL;
	pcur = NULL;
}
//打印
void ListPrint(ListNode* pHead)
{
	//此处一点要记得头节点其实是一个哨兵位
	ListNode* pcur = pHead->next;
	while (pcur != pHead)
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;
	}
	printf("\n");
}

test.c

#include"List.h"
void ListTest()
{
	ListNode* list = ListInit();
	//尾插
	ListPushBack(list, 1);
	ListPushBack(list, 2);
	ListPushBack(list, 3);
	ListPushBack(list, 4);
	ListPrint(list);
	//双向链表尾删
	ListPopBack(list);
	ListPrint(list);

	//头插入
	ListPushFront(list, 5);
	ListPushFront(list, 6);
	ListPushFront(list, 7);
	ListPrint(list);
	
	//双向链表的头删
	ListPopFront(list);
	ListPrint(list);

	// 双向链表查找
	ListNode* pos = ListFind(list, 6);
	if (pos == NULL)
	{
		printf("未找到!!!\n");
	}
	else
	{
		printf("找到了!!!\n");
	}

	// 双向链表在pos的前面进行插入
	ListInsert(pos, 66);
	ListPrint(list);

	//双向链表在pos的后面进行插入
	ListbackInsert(pos, 88);
	ListPrint(list);

	// 双向链表删除pos位置的节点
	ListErase( pos);
	ListPrint(list);
	ListDestory(&list);
}
int main()
{
	ListTest();
	return;
}

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

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

相关文章

【秋招笔试】24-08-01-用友-秋招笔试题

🍭 大家好这里是清隆Coding ,一枚热爱算法的程序员 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 编程一对一辅导 ✨ 本系列打算持续跟新 秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 ✨ 笔试合集传送们 -> 🧷春秋招笔试合集 ⌚️ 01.物流网络安全节点 问题描述 L…

数据结构与算法(Java)--栈(Linked_Stack)

博客主页&#xff1a;誓则盟约系列专栏&#xff1a;Java SE关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 线性表&#xff1a;栈 栈的定义 栈&#xff08;Stack&#xff09;是一种特殊的…

谷歌开源最强端侧小模型:2B参数越级跑赢GPT-3.5-Turbo,苹果15Pro运行飞快

谷歌也来卷「小」模型了&#xff0c;一出手就是王炸&#xff0c;胜过了比自己参数多得多的GPT-3.5、Mixtral竞品模型。 点击访问我的技术博客https://ai.weoknow.comhttps://ai.weoknow.com 今年 6 月底&#xff0c;谷歌开源了 9B、27B 版 Gemma 2 模型系列&#xff0c;并且自亮…

嵌入式C++、MQTT、React、Spring Boot和MongoDB:物联网工厂检测系统设计思路(代码示例)

项目概述 随着工业4.0和物联网&#xff08;IoT&#xff09;技术的发展&#xff0c;越来越多的工厂借助智能化手段进行生产数据的采集和实时监控。本项目设计并实现一个物联网工厂检测系统&#xff0c;通过传感器采集关键参数&#xff0c;并利用云平台进行数据存储和分析&#…

Python 教程(九):内置模块与第三方模块

目录 专栏列表前言1. 模块基础目录结构示例模块 mymodule.py 2. 导入模块3. 从模块中导入特定内容3.1 from … import *总结&#xff1a; 4. 包示例包结构moduleone.pymoduletwo.py__init__.py导入包 5. 模块搜索路径6. 内置模块示例 7. 第三方库8. __name__ 属性9. 初始化和清…

开源小项目-基于STM32F103的频率测量实现 V1.1(ADC+TIM+DMA+FFT)

目录 一、快速傅里叶变换&#xff08;FFT&#xff09; 1.1 工作原理 1.2 应用 1.3 FFT官方支持库 二、使用外设简介 2.1 ADC外设 2.2 TIM外设 3.3 DMA外设 三、代码设计过程 3.1 初始化 3.2 DMA中断数据处理 3.3 其他自定义函数 1. 计算信号频率 2. 计算信号幅度…

G-EVAL: NLG Evaluation using GPT-4 with Better Human Alignment

文章目录 题目摘要方法实验分析相关工作结论 题目 G-EVAL:使用GPT-4进行NLG评估&#xff0c;具有更好的人类一致 论文地址&#xff1a;https://arxiv.org/abs/2303.16634 项目地址&#xff1a;https://github.com/nlpyang/geval 摘要 自然语言生成(NLG)系统生成的文本质量难以…

网站开发涉及到的技术内容介绍——前端

一、网站开发涉及前后端交互模式 一般来说网站项目分为两种【前后端不分离、前后端分离】,其中前后端不分离的项目是(后端语言可以直接与前端的html等内容糅合在一起,后端语言可以操作数据进行动态渲染前端的html文件进行展示)。后端分离的项目是(后端语言不会直接对前端的…

c++| c++11左右值引用,完美转发,可变参数模板

c| c11的新特性 左&#xff0c;右值引用什么是左值&#xff0c;右值左值引用和右值引用右值引用解决什么问题呢&#xff1f;移动构造万能引用形式 完美转发格式 lambada表达式格式 可变参数模板可变参数模板实现打印不同类型emplace_push以list的emplace_back的实现举例 左&…

掌握 HTTP 请求的艺术:理解 cURL GET 语法

在 Web 开发和服务器通信领域&#xff0c;掌握 HTTP 请求对于寻求有效与 Web 服务和 API 交互的开发人员至关重要。在众多可用于发出 HTTP 请求的工具中&#xff0c;cURL 脱颖而出&#xff0c;成为全球开发人员信赖的强大且多功能的命令行工具。在这篇博文中&#xff0c;我们将…

MySQL分组查询有关知识总结

目录 4. 分组查询&#xff08;group by&#xff09; 4.1 概述 4.2 分组函数 4.2.1 单个使用 4.2.2 组合使用 4.2.3 注意&#xff01; 4.3 group by 4.3.1 单个字段 4.3.2 多个字段 4.3.3 提醒&#xff01; 4.4 having 4.5 分组查询演示 4. 分组查询&#xff08;…

海外仓怎么入局?货代还有发展的空间吗?

很多货代小伙伴可能都有一个疑惑&#xff1a;海外仓虽然火爆&#xff0c;但是怎么入局呢&#xff1f;显然&#xff0c;自建海外仓的试错代价太高了&#xff0c;成本高、选址难、管理起来更是一地鸡毛。既然无法自建&#xff0c;那转换赛道&#xff0c;管理别人的仓库&#xff0…

iOS面试之属性关键字(二):常见面试题

Q:ARC下&#xff0c;不显式指定任何属性关键字时&#xff0c;默认的关键字都有哪些&#xff1f; 对应基本数据类型默认关键字是:atomic,readwrite,assign 对于普通的 Objective-C 对象:atomic,readwrite,strong Q&#xff1a;atomic 修饰的属性是怎么样保存线程安全的&#x…

如何将本地下载的切片电影进行合成一个视频

合成后的时长1&#xff1a;41 没有合成前是50个电影切片 注明:电影切片不是真实的切片名称而是自定义从0-50的数字 import requests # with open("电影.m3u8","r") as f: # n0 # for line in f: # if line.startswith("#"): …

SpringBoot项目如何安装Selenium自动化(详解)

目录 一、打开intellij idea&#xff0c;创建Maven项目 二、添加依赖 三、在Test路径下创建自动化文件 3.1 项目结构 3.2 代码 四、运行自动化 前言&#xff1a; java版本最低要求为8。电脑至少已安装一种浏览器&#xff0c;如&#xff1a;Chrome&#xff08;推荐&#xff09;、…

十日Python项目——第五日(商品数据)

#前言&#xff1a; 在最近十天我会用Python做一个购物类项目&#xff0c;会用到DjangoMysqlRedisVue等。 今天是第五天&#xff0c;主要负责撰写响应具体的商品数据。若是有不懂大家可以先阅读我的前四篇博客以能够顺承。 若是大家基础有不懂的&#xff0c;小编前面已经关于…

RJ45空包弹网口描述与应用

RJ45空包弹网口&#xff0c;通常指的是RJ45接口的空芯线缆&#xff08;通常称为“空包”&#xff09;和相应的连接器。这种线缆和连接器组合常用于网络布线中&#xff0c;特别是在需要将网络信号从一端传输到另一端&#xff0c;同时保持信号完整性和隔离性的场合。 描述&#…

C++初阶:list的使用和模拟实现

关于list可以先看一下这个文档&#xff1a;list文档 一.list的介绍和使用 1.1 list的介绍 list实际上就是链表&#xff0c;是带头双向循环链表。 1.2 list的使用 list的使用跟我们以前用C语言实现时的一样。push&#xff0c;pop&#xff0c;insert等等。 1.2.1list的构造 …

【从零开始一步步学习VSOA开发】开发环境搭建

开发环境搭建 开发 VSOA 首先需要搭建开发环境&#xff0c;这里讲解 Windows 下 C/C 开发环境搭建方法。 下载 IDE 并申请授权码 SylixOS 的开发和部署需要 RealEvo-IDE 的支持&#xff0c;因此您需要先获取 RealEvo-IDE 的安装包和注册码。 RealEvo-IDE 分为体验版和商业版…

简单的 微服务netflix 学习

简单的 微服务netflix 学习 一.Eureka 学习 1. 服务简单搭建 1.1 首先确定pom文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-…