数据结构-双向带头循环链表

news2024/11/27 16:29:22

  • 链表的分类
  • 实现带有哨兵位的双向的循环链表
    • **定义节点的结构**
    • 初始化单个节点
    • 初始化带有哨兵位的双向循环链表
    • 打印链表
    • 销毁链表
    • 尾插
    • 尾删
    • 头插
    • 头删
    • find函数
    • 在任意位置之前插入
    • 任意位置的删除
    • 全部代码
      • list.h
      • list.c
      • test.c
    • 链表和顺序表的区别

链表的分类

如下
在这里插入图片描述
根据上述的三种组合,一共分为8类

实现带有哨兵位的双向的循环链表

定义节点的结构

typedef int LTDataType;

typedef struct ListNode
{
	struct ListNode* next;
	struct ListNode* prev;

	LTDataType data;
}LTNode;

初始化单个节点

LTNode* BuyListNode(LTDataType x)
{
	LTNode* newnode=(LTNode*)malloc(sizeof(LTNode));
	if (newnode==NULL)
	{
		perror("malloc fail");
	}

	newnode->next = NULL;
	newnode->prev = NULL;
	newnode->data = x;

	return newnode;
}

初始化带有哨兵位的双向循环链表

作用:使链表在无数据的情况下就具有循环的特点

LTNode* LTInit()
{
	LTNode* phead = BuyListNode(-1);

	phead->next = phead;
	phead->prev = phead;

	return phead;
}

打印链表

哨兵位phead一定不能为空,否则无法连接下面的节点

void LTPrint(LTNode* phead)
{
	assert(phead);

	printf("<=head=>");
	LTNode* cur = phead->next;
	while (cur!=phead)
	{
		printf("%d<=>",cur->data);
		cur = cur->next;
	}

	printf("\n");
}

销毁链表

void LPDestroy(LTNode* phead)
{
	assert(phead);

	LTNode* cur = phead->next;
	while (cur!=phead)
	{
		LTNode* next = cur->next;
		free(cur);
		cur = next;
	}

	free(phead);

}

尾插

需要三个节点即可布置好顺序
顺序为:tail newnode phead
在这里插入图片描述

void LTPushBack(LTNode* phead, LTDataType x)
{
	assert(phead);

	LTNode* newnode = BuyListNode(x);
	LTNode* tail = phead->prev;

	tail->next = newnode;
	newnode->prev = tail;
	newnode->next = phead;
	phead->prev = newnode;

}

尾删

增加一个函数用于判断除哨兵位以外是否有其它的节点
bool类型只有两个取值:true和false
需要三个节点,顺序为:tailprev,tail,phead
在这里插入图片描述

bool LTEmpty(LTNode* phead)
{
	assert(phead);
	return phead->next == phead;
}

void LTPopBack(LTNode* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));

	LTNode* tail = phead->prev;
	LTNode* tailprev = tail->prev;

	tailprev->next = phead;
	phead->prev = tailprev;

	free(tail);
}

头插

需要三个节点即可布置好顺序
顺序为:phead newnode first

在这里插入图片描述

void LTPushFront(LTNode* phead, LTDataType x)
{
	assert(phead);

	LTNode* newnode = BuyListNode(x);
	LTNode* first = phead->next;

	newnode->next = first;
	first->prev = newnode;
	phead->next = newnode;
	newnode->prev = phead;
}

头删

增加一个函数用于判断除哨兵位以外是否有其它的节点
bool类型只有两个取值:true和false
需要三个节点,顺序为:phead,tail,tailnex
在这里插入图片描述

void LTPopFront(LTNode* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));

	LTNode* tail = phead->next;
	LTNode* tailnex = tail->next;

	phead->next = tailnex;
	tailnex->prev = phead;

	free(tail);
}

find函数

从哨兵位的下一个节点开始遍历,直至找到该元素或者遍历到哨兵位结束

LTNode* LTFind(LTNode* phead, LTDataType x)
{
	assert(phead);

	LTNode* cur = phead->next;
	while (cur!=phead)
	{
		if (cur->data==x)
		{
			return cur;
		}
		cur = cur->next;
	}

	return NULL;
}

在任意位置之前插入

任意位置之前的插入需要搭配find函数来使用,需要三个节点,顺序为:posprev,newnode,pos
可以使用它来进行头插和尾插,分别可以表示为LTInsert(phead->next, x) LTInsert(phead, x)
在这里插入图片描述

void LTInsert(LTNode* pos, LTDataType x)
{
	assert(pos);

	LTNode* newnode= BuyListNode(x);
	LTNode* posprev = pos->prev;

	newnode->next = pos;
	pos->prev = newnode;
	posprev->next = newnode;
	newnode->prev = posprev;
}

在这里插入图片描述

任意位置的删除

道理同任意位置的插入
在这里插入图片描述

void LTErase(LTNode* pos)
{
	assert(pos);

	LTNode* posprev = pos->prev;
	LTNode* posnex = pos->next;

	posprev->next = posnex;
	posnex->prev = posprev;

	free(pos);
}

结果如下:
在这里插入图片描述

全部代码

list.h

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

typedef int LTDataType;

typedef struct ListNode
{
	struct ListNode* next;
	struct ListNode* prev;

	LTDataType data;
}LTNode;

//创建单个的节点
LTNode* BuyListNode(LTDataType x);
//初始化
LTNode* LTInit();
//
void LTPrint(LTNode* phead);
void LPDestroy(LTNode* phead);

//尾插
void LTPushBack(LTNode* phead, LTDataType x);
//尾删
void LTPopBack(LTNode* phead);

//头插
void LTPushFront(LTNode* phead, LTDataType x);
//头删
void LTPopFront(LTNode* phead);

LTNode* LTFind(LTNode* phead, LTDataType x);

//任意位置之前的插入
void LTInsert(LTNode* pos, LTDataType x);
//任意位置的删除
void LTErase(LTNode* pos);

list.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "list.h"

LTNode* BuyListNode(LTDataType x)
{
	LTNode* newnode=(LTNode*)malloc(sizeof(LTNode));
	if (newnode==NULL)
	{
		perror("malloc fail");
	}

	newnode->next = NULL;
	newnode->prev = NULL;
	newnode->data = x;

	return newnode;
}

LTNode* LTInit()
{
	LTNode* phead = BuyListNode(-1);

	phead->next = phead;
	phead->prev = phead;

	return phead;
}

void LTPrint(LTNode* phead)
{
	assert(phead);

	printf("<=head=>");
	LTNode* cur = phead->next;
	while (cur!=phead)
	{
		printf("%d<=>",cur->data);
		cur = cur->next;
	}

	printf("\n");
}

void LPDestroy(LTNode* phead)
{
	assert(phead);

	LTNode* cur = phead->next;
	while (cur!=phead)
	{
		LTNode* next = cur->next;
		free(cur);
		cur = next;
	}

	free(phead);

}
void LTPushBack(LTNode* phead, LTDataType x)
{
	assert(phead);

	LTNode* newnode = BuyListNode(x);
	LTNode* tail = phead->prev;

	tail->next = newnode;
	newnode->prev = tail;
	newnode->next = phead;
	phead->prev = newnode;

}

bool LTEmpty(LTNode* phead)
{
	assert(phead);
	return phead->next == phead;
}

void LTPopBack(LTNode* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));

	LTNode* tail = phead->prev;
	LTNode* tailprev = tail->prev;

	tailprev->next = phead;
	phead->prev = tailprev;

	free(tail);
}

void LTPushFront(LTNode* phead, LTDataType x)
{
	assert(phead);

	LTNode* newnode = BuyListNode(x);
	LTNode* first = phead->next;

	newnode->next = first;
	first->prev = newnode;
	phead->next = newnode;
	newnode->prev = phead;
}

void LTPopFront(LTNode* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));

	LTNode* tail = phead->next;
	LTNode* tailnex = tail->next;

	phead->next = tailnex;
	tailnex->prev = phead;

	free(tail);
}

LTNode* LTFind(LTNode* phead, LTDataType x)
{
	assert(phead);

	LTNode* cur = phead->next;
	while (cur!=phead)
	{
		if (cur->data==x)
		{
			return cur;
		}
		cur = cur->next;
	}

	return NULL;
}

void LTInsert(LTNode* pos, LTDataType x)
{
	assert(pos);

	LTNode* newnode= BuyListNode(x);
	LTNode* posprev = pos->prev;

	newnode->next = pos;
	pos->prev = newnode;
	posprev->next = newnode;
	newnode->prev = posprev;
}

void LTErase(LTNode* pos)
{
	assert(pos);

	LTNode* posprev = pos->prev;
	LTNode* posnex = pos->next;

	posprev->next = posnex;
	posnex->prev = posprev;

	free(pos);
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "list.h"
void Test1()
{
	LTNode* plist = LTInit();
	LTPushBack(plist, 1);
	LTPushBack(plist, 2);
	LTPushBack(plist, 3);
	LTPushBack(plist, 4);
	LTPrint(plist);
	LTPopBack(plist);
	LTPopBack(plist);
	LTPrint(plist);
}

void Test2()
{
	LTNode* plist = LTInit();
	LTPushBack(plist, 1);
	LTPushBack(plist, 2);
	LTPushBack(plist, 3);
	LTPushBack(plist, 4);
	LTPushFront(plist, 100);
	LTPushFront(plist, 200);
	LTPushFront(plist,300);
	LTPrint(plist);
	LTPopFront(plist);
	LTPrint(plist);

}
void Test3()
{
	LTNode* plist = LTInit();
	LTPushBack(plist, 1);
	LTPushBack(plist, 2);
	LTPushBack(plist, 3);
	LTNode* pos=LTFind(plist, 3);
	if (pos==NULL)
	{
		perror("pos NULL");
	}
	LTInsert(pos, 100);
	LTPrint(plist);
	LTErase(pos);
	LTPrint(plist);
}
int main()
{
	//Test1();
	//Test2();
	Test3();
	return 0;
}

链表和顺序表的区别

在这里插入图片描述

局部性原理:加载指定的数据,可能会把与其物理内存之后的数据加载上去。
根据局部性原理,顺序表在载入缓存中时,可能会把与之相邻的数据一同载入,但是,链表的地址并不是相邻的,在载入相应的链表的时候不会把相邻的链表载入缓存。
因此顺序表的缓存利用率比较高。

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

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

相关文章

线性调频信号公式推导及matlab仿真

线性调频信号的数学表达式&#xff1a; 其中&#xff0c;t是时间变量&#xff0c;单位为秒&#xff08;s&#xff09;&#xff1b;T为脉冲持续时间&#xff08;周期&#xff09;&#xff1b;K是线性调频率&#xff0c;单位是Hz/s&#xff1b; 角度&#xff08;单位为弧度&…

【通过粒子滤波进行地形辅助导航】用于地形辅助导航的粒子滤波器和 PCRB研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【MySQL异常解决】MySQL执行SQL文件出现【Unknown collation ‘utf8mb4_0900_ai_ci‘】的解决方案

MySQL执行SQL文件出现【Unknown collation ‘utf8mb4_0900_ai_ci‘】的解决方案 一、背景描述二、报错原因三、解决方案3.1 升级 MySQL 数据库版本3.2 修改字符集为 一、背景描述 从服务器MySQL中导出数据为SQL执行脚本后&#xff0c;在本地电脑执行导出的SQL脚本&#xff0c;…

【数据结构---排序】庖丁解牛式剖析常见的排序算法

排序算法 一、常见的排序算法二、常见排序算法的实现1. 直接插入排序2. 希尔排序3. 直接选择排序4. 堆排序5. 冒泡排序6. 快速排序6.1 递归实现快速排序思路一、hoare 版本思路二、挖坑法思路三、前后指针法 6.2 非递归实现快速排序 7. 归并排序7.1 归并排序的递归实现7.2 归并…

Word2Vec实现文本识别分类

深度学习训练营之使用Word2Vec实现文本识别分类 原文链接环境介绍前言前置工作设置GPU数据查看构建数据迭代器 Word2Vec的调用生成数据批次和迭代器模型训练初始化拆分数据集并进行训练 预测 原文链接 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&…

Apache Phoenix(2):安装Phoenix

1 下载 大家可以从官网上下载与HBase版本对应的Phoenix版本。 http://phoenix.apache.org/download.html 2 安装 &#xff08;1&#xff09;上传安装包到Linux系统&#xff0c;并解压 cd /opt/ tar -xvzf phoenix-hbase-2.5-5.1.3-bin.tar.gz &#xff08;2&#xff09;将p…

软件测试真实企业测试流程

最近收到不少准备转行软件测试的小伙伴私信问真实企业里面软件测试流程是什么样子的&#xff1f; 对于这个问题&#xff0c;在面试的时候也是经常会被问到。 关于测试流程&#xff0c;100家公司可能有100套测试流程&#xff0c;但是基本上都是大同小异&#xff0c;完全可以将测…

行业追踪,2023-07-14,汽车零部件在反弹时已清仓,耐心等待第二波买点重现

自动复盘 2023-07-14 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

ELK-日志服务【kafka-配置使用】

kafka-01 10.0.0.21 kafka-02 10.0.0.22 kafka-03 10.0.0.23 【1】安装zk集群、配置 [rootes-01 ~]# yum -y install java maven [rootes-01 ~]# tar xf apache-zookeeper-3.5.9-bin.tar.gz -C /opt/[rootes-01 ~]# cd /opt/apache-zookeeper-3.5.9-bin/conf/ [rootes-…

MySQL结构以及数据管理(增删改查)

目录 1.数据库的简介 2.数据库分类 2.1关系型数据库 2.2 非关系型数据库 3.mysql的数据类型 3.1 常用的数据库类型 4.mysql的数据库结构 4.1 查看库信息 4.2 查看表信息 5.SQL 语句 5.1 SQL语言分类&#xff1a; 1.数据库的简介 数据库&#xff08;database&#…

基于LoRa技术的网络终端无线程序升级系统研究(学习)

摘要 设计了一种基于LoRa技术的STM32F4无线程序升级系统。此系统由PC及相关STM32软件开发环境、LoRa通信模块及控制器和STM32F4终端三部分组成。 本系统采用LoRa技术将程序数据无线发送到终端&#xff0c;终端通过IAP技术实现远程无线程序自动升级。测试结果表明&#xff0c;…

基于Springboot+Vue的宠物店猫咖管理系统(源代码+数据库)088

基于SpringbootVue的宠物店猫咖管理系统(源代码数据库)088 一、系统介绍 本系统分为管理员、店长、用户三种角色 用户角色包含以下功能&#xff1a; 登录、注册、我的宠物、我的信息、文件管理、我的预约、门店详情、打工喵、本地喵、外来喵、宠物领养、个人中心、密码修改…

0基础学习VR全景平台篇 第61篇:基本功能-如何发布VR视频

戳我先了解“全景视频上传规范” 1、点击【上传】按钮&#xff0c;打开本地文件夹&#xff0c;上传符合要求的全景视频素材&#xff0c;可以选择单个或多个视频同时上传。 2、视频上传成功以后&#xff0c;需要处理一段时间&#xff0c;请耐心等待。 视频处理好以后&#xff0…

2023年7月最新ESI 中国 国内高校排名(附上下载链接),

东南大学的排名 多年来 一直是22, 21 &#xff0c;还需要进一步提高&#xff0c;进入前10. 下载连接 (375条消息) 2023年7月最新ESI数据国内高校排名表格-行业报告文档类资源-CSDN文库

Vue3 组件之间跨级通信

文章目录 Vue3 组件之间跨级通信概述选项式API简单使用支持响应式调用顶层方法 组合式API简单使用支持响应式底层调顶层方法 Vue3 组件之间跨级通信 概述 通常情况下&#xff0c;当我们需要从父组件向子组件传递数据时&#xff0c;会使用props。 但是一些多层级嵌套的组件&a…

【Vue】给 elementUI 中的 this.$confirm、this.$alert、 this.$prompt添加按钮的加载效果

文章目录 主要使用 beforeClose 方法实现 loading 的效果beforeClose MessageBox 关闭前的回调&#xff0c;会暂停实例的关闭 function(action, instance, done)1. action 的值为confirm, cancel或close。 2. instance 为 MessageBox 实例&#xff0c;可以通过它访问实例上的属…

不外传秘诀| docker 快速搭建常用的服务环境

本文主要给大家介绍如何使用 docker 搭建常用的服务环境&#xff0c; 包括mysql,reedis,nginx,jenkins 等常用的环境&#xff0c;下面直接进入主题。 1、MySQL 部署 ①搜索 MySQL 镜像 docker search mysql ②拉取 MySQL 镜像 docker pull mysql:5.7 ③创建容器&#xf…

嵌入式LinuxLED驱动开发实验

目录&#xff1a; 1. Linux下LED灯的驱动原理1.1. 地址映射1.1.1. 实际物理地址映射到虚拟地址的函数1.1.2. 内存访问函数 2.硬件原理图分析3. 实验程序编写3.1. 驱动程序编写3.2. 应用程序编写 4. 运行测试 1. Linux下LED灯的驱动原理 我们在裸机实验的时候&#xff0c;都是通…

2023年最具威胁的25种安全漏洞(CWE TOP 25)

1. CWE 4.12发布 最近几年&#xff0c;每年6月CWE发布的版本都成为一年中最重要的版本&#xff0c;因为里面包含了新的CWE TOP 25 视图&#xff0c;也就是我们常说的&#xff1a;CWE最具威胁的25种缺陷。 CWE 4.12 在6月29号发布&#xff0c;里面包含了重要的2023年TOP25视图…

Promise分享

手写promise之前需要知道 宏任务 & 微任务 我们都知道 Js 是单线程的&#xff0c;但是一些高耗时操作就带来了进程阻塞问题。为了解决这个问题&#xff0c;Js 有两种任务的执行模式&#xff1a;同步模式&#xff08;Synchronous&#xff09;和异步模式&#xff08;Asynchr…