手搓带头双向循环链表(C语言)

news2024/11/15 22:53:34

目录

List.h

List.c

ListTest.c

测试示例

带头双向循环链表优劣分析


List.h

#pragma once

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

typedef int LTDataType;

typedef struct ListNode
{
	struct ListNode* prev;
	struct ListNode* next;
	LTDataType data;
}ListNode;

//创建节点
ListNode* BuyListNode(LTDataType x);
//初始化
ListNode* ListInit();
//打印链表
void ListPrint(ListNode* phead);
//尾插
void ListPushBack(ListNode* phead, LTDataType x);
//尾删
void ListPopBack(ListNode* phead);
//销毁
void ListDistroy(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);

List.c

#include "List.h"

//创建节点
ListNode* BuyListNode(LTDataType x)
{
	ListNode* node = (ListNode*)malloc(sizeof(ListNode));
	//申请空间失败
	if (node == NULL)
	{
		perror("BuyListNode");
		exit(-1);
	}
	node->data = x;
	node->prev = NULL;
	node->next = NULL;
	
	return node;
}

//初始化
ListNode* ListInit()
{
	ListNode* phead = BuyListNode(-1);
	phead->prev = phead;
	phead->next = phead;

	return phead;
}

//打印链表
void ListPrint(ListNode* phead)
{
	assert(phead);

	ListNode* cur = phead->next;

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

//尾插
void ListPushBack(ListNode* phead, LTDataType x)
{
	assert(phead);

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

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

//尾删
void ListPopBack(ListNode* phead)
{
	assert(phead);
	assert(phead->prev != phead);

	ListNode* tailPrev = phead->prev->prev;
	free(phead->prev);
	tailPrev->next = phead;
	phead->prev = tailPrev;
}

//销毁
void ListDistroy(ListNode* phead)
{
	assert(phead);

	ListNode* cur = phead->next;
	ListNode* tmp = cur;

	while (cur != phead)
	{
		cur = cur->next;
		free(tmp);
		tmp = cur;
	}
	
	phead->prev = phead;
	phead->next = phead;
}

//头插
void ListPushFront(ListNode* phead, LTDataType x)
{
	assert(phead);

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

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

//头删
void ListPopFront(ListNode* phead)
{
	assert(phead);
	assert(phead->next != phead);

	ListNode* first = phead->next;
	ListNode* second = first->next;
	free(first);
	second->prev = phead;
	phead->next = second;
}

//查找
ListNode* ListFind(ListNode* phead, LTDataType x)
{
	assert(phead);

	ListNode* cur = phead->next;

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

	return NULL;
}

//在pos位置之前插入
void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);

	ListNode* posPrev = pos->prev;
	ListNode* newnode = BuyListNode(x);

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

//删除pos位置的值
void ListErase(ListNode* pos)
{
	assert(pos);

	ListNode* posPrev = pos->prev;
	ListNode* posNext = pos->next;
	free(pos);
	posPrev->next = posNext;
	posNext->prev = posPrev;
}

头插尾插复用:

//在pos位置之前插入
void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);

	ListNode* posPrev = pos->prev;
	ListNode* newnode = BuyListNode(x);

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

//头插
void ListPushFront(ListNode* phead, LTDataType x)
{
	ListInsert(phead->next, x);
}

//尾插
void ListPushBack(ListNode* phead, LTDataType x)
{
	ListInsert(phead, x);
}

 头删尾删复用:

//删除pos位置的值
void ListErase(ListNode* pos)
{
	assert(pos);

	ListNode* posPrev = pos->prev;
	ListNode* posNext = pos->next;
	free(pos);
	posPrev->next = posNext;
	posNext->prev = posPrev;
}

//头删
void ListPopFront(ListNode* phead)
{
    assert(phead->next != phead);

	ListErase(phead->next);
}

//尾删
void ListPopBack(ListNode* phead)
{
	assert(phead->prev != phead);
    
    ListErase(phead->prev);
	
}

ListTest.c

#include "List.h"

void test1()
{
	ListNode* phead = NULL;
	//初始化
	phead = ListInit();
	ListPrint(phead);
	//测试尾插
	ListPushBack(phead, 1);
	ListPushBack(phead, 2);
	ListPushBack(phead, 3);
	ListPushBack(phead, 4);
	ListPushBack(phead, 5);
	ListPrint(phead);

	//测试尾删
	ListPopBack(phead);
	ListPrint(phead);
	ListPopBack(phead);
	ListPrint(phead);
	ListPopBack(phead);
	ListPrint(phead);
	ListPopBack(phead);
	ListPrint(phead);
	ListPopBack(phead);
	ListPrint(phead);
	/*ListPopBack(phead);
	ListPrint(phead);*/

	ListDistroy(phead);
}

void test2()
{
	ListNode* phead = NULL;
	//初始化
	phead = ListInit();
	ListPrint(phead);
	//测试头插
	ListPushFront(phead, 1);
	ListPushFront(phead, 2);
	ListPushFront(phead, 3);
	ListPushFront(phead, 4);
	ListPushFront(phead, 5);
	ListPrint(phead);

	//测试头删
	ListPopFront(phead);
	ListPrint(phead);
	ListPopFront(phead);
	ListPrint(phead);
	ListPopFront(phead);
	ListPrint(phead);
	ListPopFront(phead);
	ListPrint(phead);
	ListPopFront(phead);
	ListPrint(phead);
	/*ListPopFront(phead);
	ListPrint(phead);*/

	ListDistroy(phead);
}
void test3()
{
	ListNode* phead = NULL;
	//初始化
	phead = ListInit();
	ListPrint(phead);
	//测试在pos位置之前插入
	ListInsert(phead, 1);
	ListInsert(phead, 2);
	ListInsert(phead, 3);
	ListInsert(phead, 4);
	ListInsert(phead, 5);
	ListPrint(phead);
	ListInsert(phead->next, 6);
	ListInsert(phead->next, 7);
	ListInsert(phead->next, 8);
	ListInsert(phead->next, 9);
	ListInsert(phead->next, 10);
	ListPrint(phead);

	//测试删除pos位置的值
	ListNode* pos = ListFind(phead, 1);
	ListErase(pos);
	ListPrint(phead);

	pos = ListFind(phead, 5);
	ListErase(pos);
	ListPrint(phead);

	pos = ListFind(phead, 10);
	ListErase(pos);
	ListPrint(phead);
	ListDistroy(phead);
}
int main()
{
	//测试尾插尾删
	//test1();
	//测试头插头删
	//test2();
	//测试在pos位置插入删除
	test3();
	return 0;
}

测试示例

尾插尾删:

头插头删:

在pos位置插入删除:

带头双向循环链表优劣分析

不同点顺序表链表
存储空间上物理上一定连续逻辑上连续,但物理上不一定连续
随机访问支持O(1)不支持:O(N)
任意位置插入或者删除元素可能需要搬移元素,效率低O(N)只需修改指针指向
插入动态顺序表,空间不够时需要扩容没有容量的概念
应用场景元素高效存储+频繁访问任意位置插入和删除频繁
缓存利用率

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

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

相关文章

上位机图像处理和嵌入式模块部署(树莓派4b读写json数据)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们说过&#xff0c;ini文件是用来进行配置的&#xff0c;数据库是用来进行数据存储的。那json是用来做什么的呢&#xff0c;json一般是用来做…

[HNOI2003]激光炸弹

原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 二维前缀和板题。 注意从&#xff08;1,1&#xff09;开始存即可&#xff0c;所以每次输入x,y之后&#xff0c;要x,y。 因为m的范围最大为…

使用Neo4j和Langchain创建知识图谱

使用Neo4j和Langchain创建知识图谱 知识图谱是组织和整合信息的强大工具。通过使用实体作为节点和关系作为边缘&#xff0c;它们提供了一种系统的知识表示方法。这种有条理的表示有利于简化查询、分析和推理&#xff0c;使知识图在搜索引擎、推荐系统、自然语言处理和人工智能…

32.基础乐理-相对音感与绝对音感

相对音感的概念&#xff1a; 就是先给你一个音&#xff0c;告诉你这个音是X&#xff0c;然后再给一个Y音&#xff0c;你就能根据 X 音判断出这个 Y 音是什么&#xff0c;原理是在于你掌握的是 X 与 Y 之间相对距离的感觉&#xff0c;比如图1&#xff0c;弹两个键 先弹 小字一组…

Ubuntu GUI使用Root用户登录指南

Ubuntu GUI使用Root用户登录指南 一、前言 默认情况下&#xff0c;Ubuntu 禁用了 root 账户&#xff0c;我们必须使用 sudo 命令来执行任何需要 root 权限的任务&#xff0c;比如像这样删除一个系统配置文件&#xff08;操作危险&#xff0c;请勿尝试&#xff09;&#xff1a;…

python可视化学习笔记折线图问题-起始点问题

问题描述&#xff1a; 起始点的位置不对 from pyecharts.charts import Line import pyecharts.options as opts # 示例数据 x_data [1,2,3,4,5] y_data [1, 2, 3, 4, 5] # 创建 Line 图表 line Line() line.add_xaxis(x_data) line.add_yaxis("test", y_data) li…

安装“STM32F4 Discovery Board Programming with Embedded Coder”MATLAB获取硬件支持包失败

安装“STM32F4 Discovery Board Programming with Embedded Coder”MATLAB获取硬件支持包失败 -完美解决方法 显示请续订您的软件维护服务&#xff0c;解决办法 根据知乎的文章 MATLAB获取硬件支持包失败&#xff0c;显示请续订您的软件维护服务&#xff0c;解决办法&#xff…

《QT实用小工具·五十》动态增删数据与平滑缩放移动的折线图

1、概述 源码放在文章末尾 该项目实现了带动画、带交互的折线图&#xff0c;包含如下特点&#xff1a; 动态增删数值 自适应显示坐标轴数值 鼠标悬浮显示十字对准线 鼠标靠近点自动贴附 支持直线与平滑曲线效果 自定义点的显示类型与大小 自适应点的数值显示位置 根据指定锚点…

程序包的创建

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 前面很多范例中都用到的 dbms output.put_line 实际上就是一个典型的程序包应用&#xff0c; 其中 dbms output是程序包的名称&#xff0c;put_line 是该程序包中定义的一个…

Python-快速搭建一个管理平台

目录 &#x1f4dc; 准备工作 一、项目介绍 ✨ 二、制作数据库表 添加信息 ⚒️ 三、运行client.exe &#x1f680; 1、连接数据库&#xff0c;选择对应表&#xff0c;生成代码 2、把后端代码依次复制到项目中 3、把前端代码依次复制到前端项目中 4、添加路由 四、运行后端项目…

异地组网,让“远程运维”更简单

您是否在联网场景中有过这些需求&#xff1f; 摄像头需要联网统一监控、PLC需要联网告别本地升级、工控机需要联网告别本地配置、广告屏需要联网告别本地下载视频、远程打开终端设备WEB进行配置......这些问题有人新升级的“异地组网”功能统统可以解决&#xff01; 告别繁琐…

【Unity】修改模型透明度

在 Unity 中修改模型透明度主要有两种方法&#xff1a;通过材质和通过着色器。以下是两种方法的步骤和解释&#xff1a; 方法 1&#xff1a;通过材质 在 Unity 编辑器中&#xff0c;选择你想要修改透明度的模型。在 Inspector 窗口中&#xff0c;找到模型的 Renderer 组件&am…

Java | Leetcode Java题解之第62题不同路径

题目&#xff1a; 题解&#xff1a; class Solution {public int uniquePaths(int m, int n) {long ans 1;for (int x n, y 1; y < m; x, y) {ans ans * x / y;}return (int) ans;} }

Linux 进程间通信之匿名管道

&#x1f493;博主CSDN主页:麻辣韭菜&#x1f493;   ⏩专栏分类&#xff1a;Linux知识分享⏪   &#x1f69a;代码仓库:Linux代码练习&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Linux知识   &#x1f51d; 目录 前言 一. 进程间通信介绍 1.进程间通…

MySQL8密码复杂度设置

在MySQL中&#xff0c;密码复杂度设置可以通过调整密码验证插件的配置参数来实现。MySQL 8.0 引入了 validate_password 插件&#xff0c;用于强制实施密码策略。 查询是否已安装的插件&#xff1a;show plugins;确认是否已安装插件validate_password 查询mysql插件目录位置&…

RTMP 直播推流 Demo(二)—— 音频推流与视频推流

音视频编解码系列目录&#xff1a; Android 音视频基础知识 Android 音视频播放器 Demo&#xff08;一&#xff09;—— 视频解码与渲染 Android 音视频播放器 Demo&#xff08;二&#xff09;—— 音频解码与音视频同步 RTMP 直播推流 Demo&#xff08;一&#xff09;—— 项目…

【最大公约数 调和级数】2183.统计可以被 K 整除的下标对数目

本文涉及知识点 最大公约数 调和级数 LeetCode2183. 统计可以被 K 整除的下标对数目 给你一个下标从 0 开始、长度为 n 的整数数组 nums 和一个整数 k &#xff0c;返回满足下述条件的下标对 (i, j) 的数目&#xff1a; 0 < i < j < n - 1 且 nums[i] * nums[j] 能…

读天才与算法:人脑与AI的数学思维笔记15_声响的数学之旅

1. 音乐 1.1. 巴赫的作品以严格的对位著称&#xff0c;他十分中意对称的结构 1.2. 巴托克的作品很多都以黄金比例为结构基础&#xff0c;他非常喜欢并善于使用斐波纳契数列 1.3. 有时&#xff0c;作曲家是本能地或者不自知地被数学的模式和结构所吸引&#xff0c;而他们并没…

MySQL-分页查询

MySQL分页查询 MySQL 分页查询原则&#xff1a; 在 MySQL 数据库中使用 LIMIT 子句进行分页查询。MySQL 分页中开始位置为 0。分页子句在查询语句的最后侧。 LIMIT子句 SELECT 投影列 FROM 表名 WHERE 条件 ORDER BY LIMIT 开始位置&#xff0c;查询数量;示例&#xff1a; …

【ARMv8/v9 系统寄存 3 -- system counter CNTPCT_EL0】

文章目录 ARMv8/v9 system countersystem counter读取函数实现 ARMv8/v9 system counter 所有使用Arm处理器的系统中都会包含一个标准化的通用定时器&#xff08;Generic Timer&#xff09;框架。这个通用定时器系统提供了一个系统计数器&#xff08;System Counter&#xff0…