数据结构 | 带头双向循环链表专题

数据结构 | 带头双向循环链表专题

前言

前面我们学了单链表,我们这次来看一个专题带头的双向循环链表~~

文章目录

  • 数据结构 | 带头双向循环链表专题
  • 前言
    • 带头双向循环链表的结构
    • 实现双向链表
      • 头文件的定义
      • 哨兵位初始化
      • 创建节点
      • 尾插
      • 尾删
      • 头插
      • 头删
      • 打印
      • 查找
      • 指定位置前插入
      • 删除指定位置
      • 销毁链表

带头双向循环链表的结构

在这里插入图片描述

  • 注意:这里的“带头”跟前面我们说的“头节点”是两个概念,实际前面的在单链表阶段称呼不严
    谨,但是为了同学们更好的理解就直接称为单链表的头节点。
  • 带头链表里的头节点,实际为“哨兵位”,哨兵位节点不存储任何有效元素,只是站在这里“放哨
    的”

哨兵位存在的意义:

  • 遍历循环链表避免死循环。

  • 每个节点有三部分内容:
    • 保存数据的val
    • 保存下一个节点的地址next指针
    • 保存前一个节点的地址prev指针

实现双向链表

我们需要实现以下功能

头文件的定义

List.h

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

// 带头+双向+循环链表增删查改实现
typedef int LTDataType;
typedef struct ListNode
{
	LTDataType _val;
	struct ListNode* _next;
	struct ListNode* _prev;
}ListNode;

//哨兵位初始化
ListNode* ListInit();

// 创建返回链表的头结点.
ListNode* ListCreate(ListNode* pHead);
// 双向链表销毁
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);

哨兵位初始化

  • 这里我们初始化成-1代表是哨兵位,然后让前驱指针和next指针指向自己
ListNode* ListInit()
{
	ListNode* pHead = ListCreate(-1);
	pHead->_next = pHead;
	pHead->_prev = pHead;
	return pHead;
}

创建节点

  • malloc一个节点,然后让新节点的next和prev赋值为空,将值给了val,最后返回空间
ListNode* ListCreate(LTDataType* x)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	if (newnode == NULL)
	{
		perror("malloc fail!\n");
		exit(-1);
	}
	newnode->_val = x;
	newnode->_next = NULL;
	newnode->_prev = NULL;
	return newnode;
}

尾插

void ListPushBack(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	ListNode* tail = pHead->_prev;
	ListNode* newnode = ListCreate(x);
	// phead   tail   newnode
	tail->_next = newnode;
	newnode->_prev = tail;
	newnode->_next = pHead;
	pHead->_prev = newnode;
}

尾删

void ListPopBack(ListNode* pHead)
{
	assert(pHead);
	assert(pHead->_next != pHead);
	ListNode* tail = pHead->_prev;
	ListNode* tailprev = tail->_prev;
	free(tail);
	tailprev->_next = pHead;
	pHead->_prev = tailprev;
}

头插

void ListPushFront(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	ListNode* cur = pHead->_next;
	ListNode* newnode = ListCreate(x);
	pHead->_next = newnode;
	newnode->_prev = pHead;
	newnode->_next = cur;
	cur->_prev = newnode;
}

头删

void ListPopFront(ListNode* pHead)
{
	assert(pHead);
	assert(pHead->_next != pHead);
	ListNode* first = pHead->_next;
	ListNode* second = first->_next;
	pHead->_next = second;
	second->_prev = pHead;
	free(first);
	first = NULL;
}

打印

void ListPrint(ListNode* pHead)
{
	ListNode* tail = pHead->_next;
	printf("哨兵位->");
	while (tail != pHead)
	{
		printf("%d->", tail->_val);
		tail = tail->_next;
	}
	printf("NULL\n");
}

查找

ListNode* ListFind(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	ListNode* cur = pHead->_next;
	while (cur != pHead)
	{
		if (cur->_val == x)
		{
			return cur;
		}
		cur = cur->_next;
	}
	return NULL;
}

指定位置前插入

void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);
	ListNode* newnode = ListCreate(x);
	ListNode* prev = pos->_prev;
	prev->_next = newnode;
	newnode->_prev = prev;
	pos->_prev = newnode;
	newnode->_next = pos;
}

删除指定位置

void ListErase(ListNode* pos)
{
	assert(pos);
	ListNode* prev = pos->_prev;
	ListNode* next = pos->_next;
	prev->_next = next;
	next->_prev = prev;
	free(pos);
	pos = NULL;
}

销毁链表

void ListDestory(ListNode* pHead)
{
	assert(pHead);
	ListNode* cur = pHead->_next;
	while (cur != pHead)
	{
		ListNode* next = cur->_next;
		free(cur);
		cur = next;
	}
	free(pHead);
	pHead = NULL;
}
  • 顺序表和双向链表的分析
不同点顺序表链表(单链表)
存储空间上物理上一定连续逻辑上连续,但物理上不一定连续
随机访问支持O(1)不支持:O(N)
任意位置插入或者删除元素可能需要搬移元素,效率低O(N)只需修改指针指向
插入动态顺序表,空间不够时需要扩容没有容量的概念
应用场景元素高效存储+频繁访问任意位置插入和删除频繁

好了,双向链表就到这里结束了,有用的话点个赞吧~~

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

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

相关文章

CentOS指令学习

目录 一、常用命令 1、ls 2、cd_pwd 3、touch_mkdir_rmdir_rm 4、cp_mv 5、whereis_which_PATH 6、find 7、grep 8、man_help 9、关机与重启 二、压缩解压 1、zip_unzip 2、gzip_gunzip 3、tar 三、其他指令 1、查看用户登录信息 2、磁盘使用情况 3、查看文件…

Java15新增特性

前言 前面的文章&#xff0c;我们对Java9、Java10、Java11、Java12 、Java13、Java14 的特性进行了介绍&#xff0c;对应的文章如下 Java9新增特性 Java10新增特性 Java11新增特性 Java12新增特性 Java13新增特性 Java14新增特性 今天我们来一起看一下Java15这个版本的一些重要…

74HC165 并入串出

/******************************************************** 程序名&#xff1a;main.C 版 本&#xff1a;Ver1.0 芯 片&#xff1a;AT89C51或STC89C51 晶 体&#xff1a;片外12MHz 编 程: Joey 日 期&#xff1a;2023-11-13 描 述&#xff1a;通过 74HC165 对 16 按键…

android 10车载桌面ActivityView触摸事件源码详解分析

hi&#xff0c;粉丝朋友们&#xff1a; 背景 大家好&#xff01;近来居然有好几个粉丝朋友居然问到了一个虚拟屏幕触摸相关的问题&#xff0c;还有老版本android 10上面有个车载桌面使用的ActivityView可以正常触摸的问题。 其实这个ActivityView在最新的版本已经没有了&…

视觉大模型DINOv2:自我监督学习的新领域

1 DINOv2 1.1 DINOv2特点 前段时间&#xff0c;Meta AI 高调发布了 Segment Anything&#xff08;SAM&#xff09;&#xff0c;SAM 以交互式方式快速生成 Mask&#xff0c;并可以对从未训练过的图片进行精准分割&#xff0c;可以根据文字提示或使用者点击进而圈出图像中的特定…

基于springboot实现结合疫情情况的婚恋系统【项目源码】

基于springboot实现结合疫情情况的婚恋系统演示 SpringBoot框架 SpringBoot是一个全新开源的轻量级框架。基于Spring4.0设计&#xff0c;其不仅继承了Spring框架原来有的优秀特性&#xff0c;而且还通过简化配置文件来进一步简化了Spring应用的整个搭建以及开发过程。另外在原…

Resources接口和实现类

Spring Resources概述 Java的标准iava.net.URL类和各种URL前缀的标准处理程序无法满足所有对low-evel资源的访问&#xff0c;比如: 没有标准化的URL实现可用于访问需要从类路径或相对于 ServletContext 获取的资源。并且缺少某些Spring所需要的功能&#xff0c;例如检测某资源…

RK3399平台开发系列讲解(应用篇)文件属性 stat 函数

🚀返回专栏总目录 文章目录 一、struct stat 结构体二、st_mode 变量三、struct timespec 结构体沉淀、分享、成长,让自己和他人都能有所收获!😄 📢Linux 下可以使用 stat 命令查看文件的属性,其实这个命令内部就是通过调用 stat()函数来获取文件属性的,stat 函数是 …

基于XML的声明式事务

场景模拟 参考基于注解的声明式事务 修改Spring的配置文件 将Spring配置文件中去掉tx:annotation-driven标签&#xff0c;并添加配置&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org…

基于springboot实现沁园健身房预约管理系统【项目源码】计算机毕业设计

基于springboot实现沁园健身房预约管理系统演示 B/S架构 B/S结构是目前使用最多的结构模式&#xff0c;它可以使得系统的开发更加的简单&#xff0c;好操作&#xff0c;而且还可以对其进行维护。使用该结构时只需要在计算机中安装数据库&#xff0c;和一些很常用的浏览器就可以…

CSS特效007:绘制3D文字,类似PS效果

css实战中&#xff0c;怎么绘制3D文字呢&#xff1f; 实际上理论很简单&#xff0c;使用text-shadow&#xff0c;根据需要调整阴影的颜色、大小、偏移量等参数&#xff0c;以达到你想要的立体效果。下面是一个简单的示例。关键点就是知道如何设置text-shadow。 效果图 源代码 …

【debug】解决Kali虚拟机开机黑屏,左上角光标一直闪动无法开机问题

做网络攻防实验时&#xff0c;突然Kali无法打开&#xff0c;遇到这个问题。。。。。。 遇到的问题 突然kali虚拟机变成如下黑屏&#xff0c;无法开机&#xff0c;左上角光标闪动&#xff0c;重启无效。 解决办法 在上图界面&#xff0c;按Ctrl F3&#xff08;不同电脑快捷键…

C++进阶篇4---番外-红黑树

一、红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或 Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制&#xff0c;红黑树确保没有一条路 径会比其他路径长出俩倍&#xff0…

[笔记]深入解析Windows操作系统《番外》windows关键进程解释

文章目录 前言一、Linux起源与发展二、什么是shell1.什么是Shell 总结 前言 一、Linux起源与发展 二、什么是shell 1.什么是Shell 总结 以上就是今天要讲的内容&#xff0c;本文仅仅简单介绍了linux命令行的使用。 参考&#xff1a; shells 概念 centOS7中的几个Ctrl组合…

Spring Cloud学习(七)【Docker 容器】

文章目录 初识 DockerDocker 介绍Docker与虚拟机Docker架构安装 Docker Docker 基本操作镜像相关命令容器相关命令数据卷 Dockerfile 自定义镜像镜像结构Dockerfile DockerComposeDockerCompose介绍安装DockerCompose Docker镜像仓库常见镜像仓库服务私有镜像仓库 初识 Docker …

【机器学习】八、规则学习

知识图谱与基本概念 基本概念 规则学习定义&#xff1a;从训练数据中学习出一组能用于对未见示例进行判别的规则。 规则定义&#xff1a;规则一般是&#xff1a;语义明确、能描述数据分布所隐含的客观规律或领域概念。 逻辑规则定义&#xff1a;⊕←?1⋀?2⋀?3…⋀??⊕…

Redis 5大数据类型命令解读

目录 Redis key的命令 1、redis字符串&#xff08;String&#xff09; 2、redis列表(List) 3、redis哈希表(Hash) 4、redis集合(Set) 5、redis有序集合(ZSet) Redis 命令网站&#xff1a;redis中文文档 Redis key的命令 命令说明示例keys *查看当前库所有的keykeys *…

Please No More Sigma(构造矩阵)

Please No More Sigma 给f(n)定义如下&#xff1a; f(n)1 n1,2; f(n)f(n-1)f(n-2) n>2; 给定n&#xff0c;求下式模1e97后的值 Input 第一行一个数字T&#xff0c;表示样例数 以下有T行&#xff0c;每行一个数&#xff0c;表示n。 保证T<100&#xff0c;n<100000…

linux安装并配置git连接github

git安装 sudo apt-get install git git信息配置 git config --global uer.name "yourname" git config --global user.email "youremail" 其中&#xff0c;yourname是你在github上配置的用户名&#xff0c;youremail是你在github上设置的邮箱 查看git…

计算机指令考前小记

RTL寄存器传送语言&#xff1a;简化对指令功能的说明 R[r]&#xff1a;存储器r的内容M[addr]&#xff1a;存储单元addr的内容M[R[r]]&#xff1a;寄存器r的内容所指的存储单元的内容 汇编指令movw 4(%ebp),%ax的RTL语言为&#xff1a;R[ax] <- M[R[ebp]4] 将寄存器EBP的内…
最新文章