C语言---双向链表(详解)---数据结构

2023-10-27

双向链表所需要头文件

首先重定义类型名 意义我前几篇讲过几次了,这里就不在赘述了,(顺序表,单链表的开头都有说明)

 

然后我们需要一个结构体

结构体包含 : 存储数据的 a 指向一个节点的指针 next 指向上一个节点的指针 prve

双向链表实现的函数功能有 :1.申请动态内存空间 2.初始化 3.双向链表的头,尾的插入与删除,在合法的任意位置进行插入和删除 4.释放链表,5.打印链表

1.申请动态内存空间

因为进行插入和初始化需要用到此函数 所以我们要先实现此功能

1.先申请一个动态内存,并名为newnode

2.把x存入newnode存放数据的a中

3.把newnode的上,下指针都置为空

4.最后再返回此申请的空间

2.初始化

我们先创建一个链表的头 并且把上,下指针置空,并且返回链表的头

并且我们再命名一个plist,用来接收,之后穿参数的时候,就可以直接用pilst

 3.双向链表的尾部插入

1.先创建一个指针 指向头的一个节点

2.申请一块内存 用来插入

因为双向链表的优势 ,我们不需要像单链表那样依次遍历找到最后一个节点,双向链表,表头,的上一个就是链表的最后一个节点

所以我们可以一步就找到表尾

尾插入原理:

找到表尾后,1.在表尾后再插入一个新数据(用next指针指向newnode(新数据)),2.把新数据指向原先的表尾(用prve指向原先的表尾)就完成了一次的连接

1.再让现在的表尾 (就是newnode(新数据))指向表头(newnode->next=phead(表头))  2.(再让表头指向上一个的指针(就是prve)指向newnode(新数据))     

这里可能会有点绕,需要读者慢慢理解,但是原理是简单的 就是让1个数据与它的上一个数据和下一个数据进行对接

4.双向链表的尾部删除

 原理:

1.找到表尾,再找到表尾的上一个数据(倒数第二个数据)

2.然后让倒数第二个数据与表头对接,倒数第二个数据就成为了表尾数据,

3.再把原先的表尾数据进行释放

end就是最后一个节点,cur就是倒数第二个节点

1.让cur指向下一个的指针指向表头 

2.把表头的指向上一个的指针指向cur

3.释放原先的表尾,并且把指针置空

 读者要搞清楚 next 和prve的作用 再搞清楚end和cur的位置,最后运用他们进行对接

5.双向链表的头部插入

我们先找到两个位置 一个是表头 一个是表头的下一个节点(这个节点才是真正存放数据的节点,表头只是其带头作用,里面只是存放0,并且打印链表都是从表头的一个节点开始打印

找到两个位置之后,创建一个动态内存 进行插入

接下来大致原理就是 让插入的数据表头表头的下一个节点在他们两个中间插入(就是对接)

表头原先指向的是表头的下一个节点1.现在我们让表头指向下一个节点的指针指向插入的数据

 2.让插入的数据指向上一个节点的指针指向表头  3.让插入的数据指向下一个节点的指针指向原先表头的下一个节点(进行对接)

6.双向链表的头部删除

头部删除也是删除表头的下一个节点

那么我们要找到两个位置 1.表头,2.表头的下一个节点的下一个节点(就是要删除的位置的下一个节点)

这里我们把表头命名为cur 把表头的下一个节点的下一个节点(就是要删除的位置的下一个节点)命名为end

1.然后我们让 cur和end进行对接

 2.然后释放要删除数据

把cur指向下一个节点的指向指向end 把end指向上一个节点的指针指向cur

7.双向链表的查找

 这里我们只需要从表头的下一个节点开始一直到表尾,进行遍历,如果找到就返回改位置。如果知道表尾都没找到(就是循环结束的时候)那么我们就返回空(NULL)

然后我们用pos来接收 

 7.对pos的前一个位置进行插入数据

我们首先需要先对pos进行判断,如果找到了,才开始插入,若找不到,就不执行函数

因为是插入数据 所以我们要先申请一个内存

又因为我们已经得到了pos的位置,所以我们可以直接找到pos的上一个数据

原理在于找两个位置 一个是pos 一个是pos的上一个数据

pos我们已经有了它的位置 pos的上一个位置我们只需要用指针指向它就可以了

pos的上一个位置命名为end

然后让新数据pos的上一个数据pos中间进行插入(就是对接) 

8.对pos这个位置进行删除

 因为我们有了pos的位置

那么我们用指针 next和prve找到 pos的上一个位置(命名为cur),和pos的下一个位置(end)进行对接

然后再释放掉pos,为把pos置空

 9.链表的打印

从表头的下一个数据开始,进行遍历,并依次打印

10.链表的释放 

因为链表的内存是一块块申请的,所以我们要遍历,并且释放

先从找到表头的下一个节点(命名为end),再找到表头的下一个节点的下一个节点(命名为cur)

先释放表头的下一个节点再把cur赋值给end,就此循环。就把表头以后的数据全释放完了,

最后把表头给释放,并且置空,就可以了。

双向链表的全部函数功能就实现好了!

这里添加一个注释

之所以双向链表传参不用(&)取地址 是因为SL* plist=ListCreate(); 这里是用指针接收,指针接收的就是地址,我们传参数的时候就是用地址传入了。

不用二级指针是因为我们不需要改变这个双向链表的哨兵位,只是改变它的指向,这个哨兵位是不会变的(不管头插、尾插、头删、尾删)

而单链表的头插,头删是会改变这个头的,比如(头删)释放这个头,让下一个节点成为头,这些都是会改变头的,所以我们要传二级指针。

接下来是代码段 ,需要自取。

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

typedef int STDataType;

typedef struct linode
{
	STDataType a;
	struct linode* next;
	struct linode* prve;
}SL;

SL* Bylist(STDataType x)//申请动态内存
{
	SL* newnode = (SL*)malloc(sizeof(SL));
	newnode->a = x;
	newnode->next = NULL;
	newnode->prve = NULL;

	return newnode;
}

SL* ListCreate()//初始化
{
	SL* phead = Bylist(0);
	phead->next = phead;
	phead->prve = phead;

	return phead;
}

void ListDestory(SL* pHead)//释放链表
{
	SL* end = pHead->next;
	while (end != pHead)
	{
		SL* cur = end->next;
		free(end);
		end = cur;
	}
	free(pHead);
	pHead = NULL;
}

void ListPrint(SL* pHead)//打印链表
{
	SL* end = pHead->next;
	while (end != pHead)
	{
		printf("%d->", end->a);
		end = end->next;
	}
	printf("phead");
}

void ListPushBack(SL* pHead, STDataType x)//尾插
{
	SL* end = pHead->prve;
	SL* newnode = Bylist(x);
	//因为双向链表的优势 所以我们不需要依次遍历,头的上一个就是最后一个节点
	end->next = newnode;
	newnode->prve = end;
	newnode->next = pHead;
	pHead->prve = newnode;
}

void ListPopBack(SL* pHead)//尾删
{
	SL* end = pHead->prve;//找到最后一个节点
	SL* cur = end->prve;//最后一个节点的上一个
	cur->next = pHead;
	pHead->prve = cur;
	free(end);
	end = NULL;
}

void ListPushFront(SL* pHead, STDataType x)//头插
{
	SL* end = pHead;
	SL* cur = end->next;
	SL* newnode = Bylist(x);
	end->next = newnode;
	newnode->prve = end;
	newnode->next = cur;
	cur->prve = newnode;
}

void ListPopFront(SL* pHead)//头删
{
	SL* cur = pHead->next;
	SL* end = cur->next;
	pHead->next = end;
	end->prve = pHead;
	free(cur);
}

SL* ListFind(SL* pHead, STDataType x)//查找
{
	SL* cur = pHead->next;
	while (cur != pHead)
	{
		if (cur->a == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

void ListInsert(SL* pos, STDataType x)//插入
{
	SL* newnode = Bylist(x);
	SL* end = pos->prve;
	end->next = newnode;
	newnode->prve = end;
	newnode->next = pos;
	pos->prve = newnode;
}

void ListErase(SL* pos)//删除
{
	SL* cur = pos->prve;
	SL* end = pos->next;
	cur->next = end;
	end->prve = cur;
	free(pos);
	pos - NULL;
}

void Intenode()
{
	// 创建返回链表的头结点.
	SL* plist= ListCreate();


//	 双向链表尾插
	ListPushBack(plist, 1);
	ListPushBack(plist, 2);
	ListPushBack(plist, 3);
	ListPushBack(plist, 4);

//	 双向链表尾删
	ListPopBack(plist);

//	 双向链表头插
	ListPushFront(plist, 5);
	ListPushFront(plist, 6);
	ListPushFront(plist, 7);
	ListPushFront(plist, 8);

//	 双向链表头删
	ListPopFront(plist);

//	 双向链表查找
	SL* pos=ListFind(plist, 5);
	if (pos)
	{
	// 双向链表在pos的前面进行插入
		ListInsert(pos, 50);
	}

//	 双向链表删除pos位置的节点
	ListErase(pos);

//	// 双向链表打印
	ListPrint(plist);

//	// 双向链表销毁
	ListDestory(plist);
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言---双向链表(详解)---数据结构 的相关文章

  • 实战分享:基于python PyQt5的视频监控系统 完整代码数据 课程设计

    代码视频讲解 PyQt5的视频监控系统 基于python PyQt5的视频监控系统 完整代码可直接运行 哔哩哔哩 bilibili import sys import cv2 from PyQt5 Qt import from PyQt5
  • pandoc 使用_如何使用Pandoc撰写研究论文

    pandoc 使用 本文深入探讨了如何使用 主要是 Markdown语法来撰写研究论文 我们将介绍如何创建和引用节 图形 在Markdown和LaTeX中 和参考书目 我们还将讨论麻烦的案例 以及为什么在LaTeX中编写它们是正确的方法 研
  • CGAL配置的一点心得(各种错误的解决办法)

    这几天由于项目关系 花了些时间配置了一下CGAL 说实话走了不少弯路 谈谈我的心得吧 具体流程我不想讲 这种东西网上博客一搜一大把 而且都有一定的参考价值 当然最值得推荐的还是官网http www cgal org download win
  • 新能源汽车涨价的背后,究竟有哪些原因?

    新能源车企宣布涨价 前段时间 不仅油价接连上涨 新能源车企也接连宣布调价 根据不完全统计 今年2月后 已有超过16家车企因原料价格上涨宣布提价 下面云恒制造小编带大家来看一下 主要新能源车企涨价情况 其余车企如岚图 极氪等内部正在酝酿涨价

随机推荐

  • dbnull mysql_关于.net:无法将’System.DBNull’类型的对象强制转换为’System.String’类型...

    本问题已经有最佳答案 请猛点这里访问 我正在使用MVC3 ASP 并已将我的web config文件配置为以root用户身份登录MYSQL数据库 我创建了许多存储过程 我可以很好地连接 我现在想要将此登录用户更改为公共用户 称为tempus
  • g.729a 音频编解码算法

    g 729 spirit dsp定义 音频压缩编码 1 什么是语音编码技术 其发展与现状是怎样的 答 语音信号的数字化传输 一直是通信的发展方向之一 采用低速率语音编码技术进行语音传输比语音信号模拟传输有诸多优点 现代通信的发展趋势决定了语
  • 深入理解Https如何保证通信安全

    作为一名ABC搬运工 我相信很多人都知道Https 也都知道它是用来保证通信安全的 但是如果你没有深入了解过Https 可能并不知道它是如何保证通信安全的 我也是借着这次机会 和大家分享下我深入了解的一个过程 本文主要带着以下几个问题进行探
  • Ubuntu18.04更换源及类似问题解决方案

    Ubuntu18 04更换源及类似问题解决方案 文章目录 Ubuntu18 04更换源及类似问题解决方案 1 前言 2 Ubuntu18 04 LTS 更换国内源 3 最后 1 前言 目前部分开发板使用的Ubuntu操作系统 使用Qt RO
  • WSL重启方法

    WSL Ubuntu18 04 LTS 重启方法 以管理员权限运行cmd gt gt net stop LxssManager 停止 gt gt net start LxssManager 启动
  • 抓取一闪而过的提示消息文本

    前端业务操作出现一闪而过的message提示信息 它们有一个特点就是显示1 2s后会自动消失 例如下图1 图1 这些消息不像 alert 警告框 confirm 确认框 和prompt 提示框 那样 需要用户手动点击确定或取消按钮后才消失
  • 华为od机考真题-HJ32密码截取(中等)

    求最大回文子串 while 1 try str1 input if len str1 1 print 1
  • 渗透测试学习目录

    网络攻击防范 课程介绍 1 HTML 01 HTML标签和文本属性 02 form表单 input 标签 属性 03 a标签 img标签 table标签 04 无序列表和有序列表 05 frameset frame 框架的使用 2 div
  • VS离线安装NuGet包

    VS离线安装NuGet包 以VS 2017为例 一 下载NuGet包 官方NuGet包下载网址 https www nuget org 1 搜索需要下载的包名称 点击进入包详情页面 2 点击Download package 下载离线包 3
  • [NOI2011]阿狸的打字机【AC自动机fail树+树状数组】

    题目链接 P2414 题目给出N个字符串 我们现在想知道的是第x个字符串在第y个字符串中出现的次数是多少次 求每个字符在其余字符中出现次数 想到从AC自动机上走 其实可以看作是求它的后缀的前缀中有多少个是满足的 换言之 我们可以去fail树
  • 日前日内多阶段多时间尺度源荷储协调调度(matlab代码)

    多阶段多时间尺度的源荷储协调调度的优势是考虑新能源出力的波动性与随机性 减少需求响应负荷的不确定性会对电网制定的日前调度计划准确性的影响 也就是能够更加精准的进行调度和分析 优化结果的可用性更强 在这方面论文里面 金力的 考虑特性分布的储能
  • 如何利用excel中的数据源制作数据地图

    关于这个问题 制作数据地图的方法已不新奇 总体来说有这么几类方案 一类方案 直接在excel里制作 优势 个人小数据量应用较为方便简单 缺点 需要熟悉VBA 且更强大的功能对VBA水平要求较高 1 绘制地图图形 VBA宏语言 思路 用插入图
  • MOS管相关知识

    MOS管 MOS管的英文全称叫MOSFET Metal Oxide Semiconductor Field Effect Transistor 即金属氧化物半导体型场效应管 属于场效应晶体管中的绝缘栅型 MOS管是场效应管的一种 在一般电子
  • 版本号自动生成方法

    只需把 AssemblyInfo cs文件中的 assembly AssemblyVersion 1 0 0 0 改成 assembly AssemblyVersion 1 0 另外还需要把 assembly AssemblyFileVer
  • 什么是负载均衡,看完文章秒懂

    一 负载均衡简介 1 1 大型网站面临的挑战 大型网站都要面对庞大的用户量 高并发 海量数据等挑战 为了提升系统整体的性能 可以采用垂直扩展和水平扩展两种方式 垂直扩展 在网站发展早期 可以从单机的角度通过增加硬件处理能力 比如 CPU 处
  • 运行时报错“version `GLIBCXX_3.4.29‘ not found”底层原理分析

    文章目录 1 报错的现象 2 为什么程序有的报找不到某个版本的动态库 有的报找不到动态库文件 2 1 找不到动态库 2 2 找不到某个版本的动态库 2 2 1 报错的原因 2 2 2 动态库的版本是如何指定的 程序又是如何记录依赖的动态库版
  • DecimalField的使用

    DecimalField 类 DecimalField max digits 无 decimal places 无 选项 固定精度的十进制数 在Python中表示一个 十进制的实例 有两个必需的参数 DecimalField max dig
  • 浏览器插件下载“Download failed. Please check your connection.”解决方法

    第一步 查看错误原因 Download failed Please check your connection 下载失败 请检查您的连接 第二步 根据问题根源查看connects相关设置 第三步 分析原因 我是开启了Manual proxy
  • NeRF必读:Instant-NGP----RTX3090单卡就能玩转NeRF

    前言 NeRF从2020年发展至今 仅仅三年时间 而Follow的工作已呈井喷之势 相信在不久的将来 NeRF会一举重塑三维重建这个业界 甚至重建我们的四维世界 开头先吹一波 NeRF的发展时间虽短 有几篇工作却在我研究的领域开始呈现万精油
  • C语言---双向链表(详解)---数据结构

    双向链表所需要头文件 首先重定义类型名 意义我前几篇讲过几次了 这里就不在赘述了 顺序表 单链表的开头都有说明 然后我们需要一个结构体 结构体包含 存储数据的 a 指向一个节点的指针 next 指向上一个节点的指针 prve 双向链表实现的