数据结构——双向链表

双向链表实质上是在单向链表的基础上加上了一个指针指向后面地址

单向链表请参考http://t.csdn.cn/3Gxk9

物理结构
首先我们看一下两种链表的物理结构
在这里插入图片描述
我们可以看到:双向在单向基础上加入了一个指向上一个地址的指针,如此操作我们便可以向数组一样操作了,而且尾插也更加方便,复杂度从原来的O(n)变为O(1),并且查找也可以运用二分查找。

一些基础操作

头插

在这里插入图片描述

头删

在这里插入图片描述

尾插

在这里插入图片描述

尾删

在这里插入图片描述

接下来我们来进行代码实现

头文件以及要实现的函数声明

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef int LTDataType;
typedef struct Slist
{
	LTDataType val;
	struct Slist* next;
	struct Slist* random;
}ListNode;

// 创建返回链表的头结点.
ListNode* ListCreate();
// 双向链表销毁
void ListDestory(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);
// 扩容
ListNode* my_malloc(LTDataType x);

函数实现

#include "dslist.h"

ListNode* my_malloc(LTDataType x)//由于后续要频繁使用到扩容,所以我们直接创一个扩容函数
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	newnode->val = x;
	newnode->random = NULL;
	newnode->next = NULL;
	return newnode;
}

ListNode* ListCreate()  //创建一个双向链表
{
	ListNode* head = (ListNode * )malloc(sizeof(ListNode));
	head->val = -1;    
	head->next= NULL;
	head->random = NULL;
	return head;
}

void ListDestory(ListNode* pHead)  //销毁这个双线链表
{
	while (pHead)//将每个节点都free掉
	{
		ListNode* mid = pHead;
		pHead = pHead->next;
		mid->next = NULL;
		free(mid);
	}
}

void ListPrint(ListNode* pHead)   //打印双向链表
{
	ListNode* mid = pHead;
	while (mid)  //循环一个一个打印
	{
		printf("%d->", mid->val);
		mid = mid->next;
	}
	printf("NULL");
}

void ListPushBack(ListNode* pHead, LTDataType x)    //尾插
{
	ListNode* newnode = my_malloc(x);
	if (pHead->next == NULL)       //判断链表是否为空,如果为空则只需要插入一个。
	{
		newnode->random = pHead;    //由于循环链表,需要将头节点的random指向插入元素  
		newnode->next = NULL;
		pHead->next = newnode;
		pHead->random = newnode;
	}
	else             //如果不为空则正常尾插
	{
		ListNode* mid = pHead->random;    //由于双向  头节点的random指针直接指向尾部,所以不需要循环找尾
		mid->next = newnode;
		newnode->random = mid;
		pHead->random = newnode;
	}
}

void ListPopBack(ListNode* pHead)   //尾删
{
	if (pHead->next == NULL)   //判断是否为空
	{
		return;
	}
	else
	{
		ListNode* mid = pHead->random;   //正常尾删
		pHead->random = mid->random;
		mid->random->next = NULL;
		free(mid);
	}
}

void ListPushFront(ListNode* pHead, LTDataType x)    //头插
{
	if (pHead->next == NULL) //如果为空  则相当于尾插  调用尾插函数即可
	{
		ListPushBack(pHead, x);
	}
	else    //不为空正常头插
	{
		ListNode* nownode = my_malloc(x);   
		nownode->next = pHead->next;     //将nownode  的next指向  phead的next
		nownode->random = pHead;     //nownode的random指向  phead
		pHead->next = nownode;          //phead的next指向nownode
		nownode->next->random = nownode;
	}
}

void ListPopFront(ListNode* pHead)    //头删
{
	if (pHead->next == NULL)
	{
		return;
	}
	else
	{
		if (pHead->next == pHead->random)
		{
			ListPopBack(pHead);
		}
		else
		{
			ListNode* mid = pHead->next;
			pHead->next = mid->next;
			mid->next->random = pHead;
			free(mid);
		}

	}
}

ListNode* ListFind(ListNode* pHead, LTDataType x)   //寻找元素
{
	ListNode* left = pHead->next;
	ListNode* right = pHead->random;
	while (left && right)    //二分查找
	{
		if (left->val == x)
		{
			return left;
		}
		if (right->val == x)
		{
			return right;
		}
		left = left->next;
		right = right->random;
	}
	return NULL;
}

void ListInsert(ListNode* pos, LTDataType x)
{
	ListNode* newnode = my_malloc(x);
	ListNode* mid = pos->random;
	mid->next = newnode;
	pos->random = newnode;
	newnode->next = pos;
}

void ListErase(ListNode* pos)
{
	ListNode* next = pos->next;
	ListNode* last = pos->random;
	next->random = last;
	last->next = next;
	free(pos);
}

有什么疑惑欢迎大家留言。

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

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

相关文章

STM32 4G学习

硬件连接 ATK-IDM750C模块可直接与正点原子 MiniSTM32F103开发板板载的ATK模块接口&#xff08;ATK-MODULE&#xff09;进行连接。 功能说明 ATK-IDM750C是正点原子&#xff08;ALIENTEK&#xff09;团队开发的一款高性能4G Cat1 DTU产品&#xff0c;支持移动4G、联通4G和…

健启星|医学营养的市场先行者

随着《“健康中国2030”规划纲要》、《国民营养计划&#xff08;2017-2030年&#xff09;》等政策的陆续发布&#xff0c;标志着以传统药物治疗为中心的医疗模式时代正式转型到以预防和康复为中心的新的医学营养时代。在此背景下&#xff0c;符合时代需求的特医食品成为“医学营…

vxe table: 实现tree表格,并且自定义展示指定行

要求&#xff0c;数据中必须有唯一的id字段&#xff0c;并且row-config.KeyField 要指定这个id字段。否则在自定义展开行时展开不生效。并不影响tree的渲染 数据有两种形式 普通数据结构tree 状结构&#xff0c; 以树状结构为例: 首先我们要将普通结构的数据&#xff0c;按…

JMeter 的并发设置教程

JMeter 是一个功能强大的性能测试工具&#xff0c;可以模拟许多用户同时访问应用程序的情况。在使用 JMeter 进行性能测试时&#xff0c;设置并发是非常重要的。本文将介绍如何在 JMeter 中设置并发和查看报告。 设置并发 并发是在线程组下的线程属性中设置的。 线程数&#…

CentOS 7 构建 LVS-DR 群集 nginx负载均衡

1、基于 CentOS 7 构建 LVS-DR 群集。 DS&#xff08;Director Server&#xff09;&#xff1a;DIP 192.168.231.132 & VIP 192.168.231.200 [root132 ~]# nmcli c show NAME UUID TYPE DEVICE ens33 c89f4a1a-d61b-4f24-a260…

实现Jenkins自动发包配置

参考抖音&#xff1a;Java不良人 其中的视频演示代码 不推荐把jenkins端口一直开放&#xff0c;推荐使用时候放开&#xff08;版本不太新&#xff0c;避免漏洞攻击&#xff09; [rootVM-4-12-centos soft]# docker-compose -v Docker Compose version v2.19.1docker-compose.…

零基础看懂免费开源的Stable Diffusion

文章目录 前言Diffusion模型推理过程训练过程 Stable Diffusion模型参考 前言 前面一篇文章主要讲了扩散模型的理论基础&#xff0c;还没看过上篇的小伙伴可以点击查看&#xff1a;DDPM理论基础。这篇我们主要讲一下一经推出&#xff0c;就火爆全网的Stable Diffusion模型。St…

策略模式(C++)

定义 定义一系列算法&#xff0c;把它们一个个封装起来&#xff0c;并且使它们可互相替换((变化)。该模式使得算法可独立手使用它的客户程序稳定)而变化(扩展&#xff0c;子类化)。 ——《设计模式》GoF 使用场景 在软件构建过程中&#xff0c;某些对象使用的算法可能多种多…

神码ai伪原创【php源码】

大家好&#xff0c;小编为大家解答python必备常用英语词汇笔记的问题。很多人还不知道python中常用的英语单词&#xff0c;现在让我们一起来看看吧&#xff01; 火车头采集ai伪原创插件截图&#xff1a; 一.什么是注释 注释是对一段代码的解释&#xff0c;不参与程序运行&…

dubbo之整合SpringBoot

目录 zookeeper安装 1.拉取ZooKeeper镜像 2.新建文件夹 3.挂载本地文件夹并启动服务 4.查看容器 5.进入容器&#xff08;zookeeper&#xff09; Dubbo Admin安装 1.下载dubbo-admin 2.zip包解压 3.修改配置文件 4.打包项目 5.启动jar 6.访问 构建项目 api模块 1.创建…

无涯教程-Perl - getservbyport函数

描述 此功能转换协议PROTO的服务编号PORT,在标量context中返回服务名称,并在列表context中返回名称和相关信息- ($name,$aliases,$port_number,$protocol_name) 该调用基于/etc/services文件返回这些值。 语法 以下是此函数的简单语法- getservbyport PORT, PROTO返回值 …

将vsCode 打开的多个文件分行(栏)排列,实现全部显示,便于切换文件

目录 1. 前言 2. 设置VsCode 多文件分行(栏)排列显示 1. 前言 主流编程IDE几乎都有排列切换选择所要查看的文件功能&#xff0c;如下为Visual Studio 2022的该功能界面&#xff1a; 图 1 图 2 当在Visual Studio 2022打开很多文件时&#xff0c;可以按照图1、图2所示找到自…

伺服系统::编码器

一、主要分类 二、组成与原理 光电编码器 磁编码器&#xff1a;N-->磁感元件&#xff08;0&#xff09;&#xff1b;S-->磁感元件&#xff08;1&#xff09;》脉冲 增量编码器的分辨率、倍频与细分技术 (99 封私信 / 81 条消息) 编码器有什么分类&#xff1f; - 知乎 (z…

安卓:UDP通信

目录 一、介绍 网络通信的三要素&#xff1a; &#xff08;1&#xff09;、IP地址&#xff1a; IPv4: IPv6: IP地址形式&#xff1a; IP常用命令&#xff1a; IP地址操作类: &#xff08;2&#xff09;、端口&#xff1a; &#xff08;3&#xff09;、协议: UDP协…

搭建Docker环境

目录 一、docker环境搭建 1、卸载旧版本docker 2、安装依赖和设置仓库 3、安装docker 4、启动并加入开机启动 5、验证是否安装成功 二、利用docker搭建nginx 1、拉取镜像 2、启动容器&#xff0c;部署nginx 一、docker环境搭建 1、卸载旧版本docker yum remove docke…

SD NAND FLASH : 什么是pSLC?

一、什么是pSLC pSLC&#xff08;Pseudo-Single Level Cell&#xff09;即伪SLC&#xff0c;是一种将MLC/TLC改为SLC的一种技术&#xff0c;现Nand Flash基本支持此功能&#xff0c;可以通过指令控制MLC进入pSCL模式&#xff0c;存储时在MLC的每个单元中仅存储1bit数据&#x…

基于k8s job设计与实现CI/CD系统

方案一&#xff1a;Jenkinsk8sCICD 方案二&#xff1a;kanikok8s jobCICD CICD 基于K8s Job设计流水线 CI方案 工具镜像 云原生镜像打包工具 kaniko的使用 与Jenkins对比 可用性与易用性

IntelliJ IDEA 2021/2022关闭双击shift全局搜索

我这里演示的是修改&#xff0c;删除是右键的时候选择Remove就好了 IDEA左上角 File-->Settings 找到Navigate -->Search Everywhere &#xff0c;右键添加快捷键。 OK --> Apply应用

高端百度地图开发1:自定义水滴头像(自定义标注覆盖物、Overlay覆盖类)

自定义水滴头像&自定义标注覆盖物 一、引入百度地图JSAPI库二、构建map容器1. CSS样式表2.HTML容器 三、核心代码1.百度地图API功能2.定义构造函数并继承Overlay3.初始化自定义覆盖物4.绘制覆盖物5.添加覆盖物 自定义标注覆盖物&#xff08;Custom Overlay&#xff09;是百…

从小白到大神之路之学习运维第78天-------Kubernetes集群应用部署测试

第四阶段 时 间&#xff1a;2023年8月11日 参加人&#xff1a;全班人员 内 容&#xff1a; Kubernetes集群应用部署测试 目录 应用部署测试 应用部署测试 下面我们部署一个简单的Nginx WEB服务&#xff0c;该容器运行时会监听80端口。 &#xff08;一&#xff09;环境…