【数据结构】双向带头循环链表实现及总结
简单不先于复杂,而是在复杂之后。
文章目录
- 1. 双向带头循环链表的实现
- 2. 顺序表和链表的区别
1. 双向带头循环链表的实现
List.h
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>typedef int LTDataType;typedef struct ListNode
{struct ListNode* next;struct ListNode* prev;LTDataType data;
}LTNode;//初始化
LTNode* ListInit();//打印
void ListPrint(LTNode* phead);//尾插
void ListPushBack(LTNode* phead, LTDataType x);//头插
void ListPushFront(LTNode* phead, LTDataType x);//尾删
void ListPopBack(LTNode* phead);//头删
void ListPopFront(LTNode* phead);//链表判空
bool ListEmpty(LTNode* phead);//链表长度
size_t ListSize(LTNode* phead);//遍历查找(也可以充当修改的功能,所以链表不需要单独实现修改的功能)
LTNode* ListFind(LTNode* phead, LTDataType x);//pos之前插入
void ListInsert(LTNode* pos, LTDataType x);//删除pos位置
void ListErase(LTNode* pos);//链表销毁
void ListDestory(LTNode* phead);
List.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"List.h"LTNode* ListInit()
{LTNode* guard = (LTNode*)malloc(sizeof(LTNode));if (guard == NULL){perror("malloc fail");exit(-1);}guard->next = guard;guard->prev = guard;return guard;
}LTNode* BuyListNode(LTDataType x)
{LTNode* Node = (LTNode*)malloc(sizeof(LTNode));if (Node == NULL){perror("malloc fail");exit(-1);}Node->next = NULL;Node->prev = NULL;Node->data = x;return Node;}void ListPrint(LTNode* phead)
{assert(phead);printf("phead<=>");LTNode* cur = phead->next;while (cur != phead){printf("%d<=>", cur->data);cur = cur->next;}printf("\n");
}void ListPushBack(LTNode* phead, LTDataType x)
{assert(phead);/*LTNode* newnode = BuyListNode(x);LTNode* tail = phead->prev;tail->next = newnode;newnode->prev = tail;phead->prev = newnode;newnode->next = phead;*/ListInsert(phead, x);//双向带头循环链表不需要专门写头插尾插//只需要复用ListInsert的代码即可
}void ListPushFront(LTNode* phead, LTDataType x)
{assert(phead);//LTNode* newnode = BuyListNode(x);//先链接newnode和phead->next节点之间的关系//newnode->next = phead->next;//phead->next->prev = newnode;//phead->next = newnode;//newnode->prev = phead;//如果不想关心顺序LTNode* first = phead->next;phead->next = newnode;newnode->prev = phead;newnode->next = first;first->prev = newnode;ListInsert(phead->next, x);
}void ListPopBack(LTNode* phead)
{assert(phead);assert(!ListEmpty(phead));/*LTNode* tail = phead->prev;LTNode* prev = tail->prev;prev->next = phead;phead->prev = prev;free(tail);tail = NULL;*/ListErase(phead->prev);
}void ListPopFront(LTNode* phead)
{assert(phead);assert(!ListEmpty(phead));/*LTNode* first = phead->next;LTNode* second = first->next;phead->next = second;second->prev = phead;free(first);first = NULL;*/ListErase(phead->next);
}bool ListEmpty(LTNode* phead)
{assert(phead);return phead->next == phead;
}size_t ListSize(LTNode* phead)
{assert(phead);size_t n = 0;LTNode* cur = phead->next;while (cur != phead){++n;cur = cur->next;}return n;
}LTNode* ListFind(LTNode* phead, LTDataType x)
{assert(phead);size_t n = 0;LTNode* cur = phead->next;while (cur != phead){if (cur->data == x){return cur;}}
}void ListInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* prev = pos->prev;LTNode* newnode = BuyListNode(x);//prev newnode pos 链接prev->next = newnode;newnode->prev = prev;newnode->next = pos;pos->prev = newnode;
}void ListErase(LTNode* pos)
{assert(pos);LTNode* prev = pos->prev;LTNode* next = pos->next;prev->next = next;next->prev = prev;free(pos);//pos = NULL;
}//可以传二级指针,内部置空头结点
//建议:也可以考虑一级指针,让调用 ListDestory 的人置空(可以保持接口一致性)
void ListDestory(LTNode* phead)
{assert(phead);LTNode* cur = phead->next;while (cur != phead){LTNode* next = cur->next;free(cur);cur = next;}free(phead);//phead = NULL;
}
Test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"List.h"void TestList1()
{LTNode* plist = ListInit();ListPushBack(plist, 1);ListPushBack(plist, 2);ListPushBack(plist, 3);ListPushBack(plist, 4);ListPrint(plist);ListPushFront(plist, 10);ListPushFront(plist, 20);ListPushFront(plist, 30);ListPushFront(plist, 40);ListPrint(plist);ListPopBack(plist);ListPopBack(plist);ListPopBack(plist);ListPopBack(plist);ListPrint(plist);}void TestList2()
{LTNode* plist = ListInit();ListPushBack(plist, 1);ListPushBack(plist, 2);ListPushBack(plist, 3);ListPushBack(plist, 4);ListPrint(plist);ListPopFront(plist);ListPopFront(plist);ListPrint(plist);ListPopFront(plist);ListPopFront(plist);ListPrint(plist);}int main()
{TestList2();return 0;
}
2. 顺序表和链表的区别
不同点 | 顺序表 | 链表 |
---|---|---|
存储空间 | 物理上一定连续 | 逻辑上连续,但物理上不一定连续 |
随机访问 | 支持 O(1) | 不支持 O(N) |
任意位置插入或删除元素 | 可能需要搬移元素,效率低 O(N) | 只需修改指针指向 |
插入 | 动态顺序表,空间不够时需要扩容 | 没有容量的概念 |
应用场景 | 元素高效存储+频繁访问 | 任意位置插入和删除频繁 |
缓存利用率 | 高 | 低 |
备注:缓存利用率参考存储体系结构以及局部原理性。
顺序表优点:
- 尾插尾删效率很高。
- 随机访问。(用下标访问)’
- 相比链表结构:cpu高速缓存命中率更高。
顺序表缺点:
- 头部和中部插入删除效率低。 —O(N)
- 扩容。 性能消耗+空间浪费
链表优点:
- 任意位置插入删除效率很高。 O(1)
- 按需申请释放。
链表缺点:
- 不支持随机访问
cpu执行指令,不会直接访问内存。
- 先看数据在不在三级缓存,在(命中)。直接访问
- 不在(不命中),先加载到缓存,再访问。当要访问一个数据时,不会只访问这个数据的几个字节,而是从这个位置开始的一段都加载进去缓存。(加载多少取决于硬件)
与程序员相关CPU缓存知识
相关文章:

【数据结构】双向带头循环链表实现及总结
简单不先于复杂,而是在复杂之后。 文章目录 1. 双向带头循环链表的实现2. 顺序表和链表的区别 1. 双向带头循环链表的实现 List.h #pragma once #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <stdbool.h>typede…...

创建自己的Hexo博客
目录 一、Github新建仓库二、支持环境安装Git安装Node.js安装Hexo安装 三、博客本地运行本地hexo文件初始化本地启动Hexo服务 四、博客与Github绑定建立SSH密钥,并将公钥配置到github配置Hexo与Github的联系检查github链接访问hexo生成的博客 一、Github新建仓库 登…...

音箱、功放播放HDMI音频解决方案之HDMI音频分离器HHA
HDMI音频分离器HHA简介 HDMI音频分离器HHA具有一路HDMI信号输入,转换成一路HDMI信号、一路5.1光纤音频信号、一路5.1 SPDIF/同轴音频信号和一路模拟左右声道立体声信号输出,同时还支持EDID存储及兼容HDCP功能;分辨率最高支持1920*1080p&#…...

天猫数据分析:2023年坚果炒货市场年销额超71亿,混合坚果成多数消费者首选
近年来,随着人们生活水平和健康意识的提升,在休闲零食市场中,消费者们也越来越关注食品的营养价值,消费者这一消费偏好的转变也为坚果炒货食品行业带来了发展契机。 整体来看,坚果炒货市场的体量较大。根据鲸参谋电商…...

YouTrack 用户登录提示 JIRA 错误
就算输入正确的用户名和密码,我们也得到了下面的错误信息: youtrack Cannot retrieve JIRA user profile details. 解决办法 出现这个问题是因为 YouTrack 在当前的系统重有 JIRA 的导入关联。 需要把这个导入关联取消掉。 找到后台配置的导入关联&a…...
题目 1163: 排队买票
题目描述: 有M个小孩到公园玩,门票是1元。其中N个小孩带的钱为1元,K个小孩带的钱为2元。售票员没有零钱,问这些小孩共有多少种排队方法,使得售票员总能找得开零钱。注意:两个拿一元零钱的小孩,他们的位置互…...

【lesson9】高并发内存池Page Cache层释放内存的实现
文章目录 Page Cache层释放内存的流程Page Cache层释放内存的实现 Page Cache层释放内存的流程 如果central cache释放回一个span,则依次寻找span的前后page id的没有在使用的空闲span,看是否可以合并,如果合并继续向前寻找。这样就可以将切…...
Java基础面试题-6day
I/O流基础知识总结 (1) io即输入输出流, 如何区分输入还是输入流 以内存为中介,当我们是将数据存储到内存即为输入,反之存储到外部存储器,即为输出 在Java中分输入输出流,根据数据处理又可以分…...
【Oracle 集群】RAC知识图文详细教程(三)--RAC工作原理和相关组件
RAC 工作原理和相关组件 OracleRAC 是多个单实例在配置意义上的扩展,实现由两个或者多个节点(实例)使用一个共同的共享数据库(例如,一个数据库同时安装多个实例并打开)。在这种情况下,每一个单独…...
二级C语言笔试2
(总分100,考试时间90分钟) 一、选择题 下列各题A)、B)、C)、D)四个选项中,只有一个选项是正确的。 1. 下列叙述中正确的是( )。 A) 算法的效率只与问题的规模有关,而与数据的存储结构无关 B) 算法的时间复杂度是指执行算法所需要的计算工作量 …...

如何计算两个指定日期相差几年几月几日
一、题目要求 假定给出两个日期,让你计算两个日期之间相差多少年,多少月,多少天,应该如何操作呢? 本文提供网页、ChatGPT法、VBA法和Python法等四种不同的解法。 二、解决办法 1. 网页计算法 这种方法是利用网站给…...

再识C语言 DAY13 【递归函数(超详细)】
文章目录 前言一、函数递归什么是递归递归的两个重要条件练习一练习二 递归与迭代练习三练习四在练习三、四中出现的问题 如果您发现文章有错误请与我留言,感谢 前言 本文总结于此文章 一、函数递归 什么是递归 函数调用自身的编程技巧称为递归 (函数自…...

【Linux】权限管理
🔥博客主页: 小羊失眠啦. 🎥系列专栏:《C语言》 《数据结构》 《C》 《Linux》 《Cpolar》 ❤️感谢大家点赞👍收藏⭐评论✍️ 文章目录 一 、Linux中的用户1.1 Linux用户分类1.2 用户转换1.3 指令提权 二、Linux权限管…...

地理坐标系、空间坐标系、epsg查询网站
坐标系可用范围和详细信息的查询网站 简介 epsg.ruiduobao.com是一个可以查询gdal中所有坐标系信息的网站,可查询到坐标系的基准面、椭球体、中央子午线等相关信息,并对每个坐标系的可用范围在地图中进行了显示。详细信息可以看操作视频: e…...

docker 容器指定主机网段
docker 容器指定主机网段。 使用macvlan网络模式可以让Docker容器直接连接到物理网络,而不需要通过NAT或端口映射的方式来访问它们。可以提高网络性能和稳定性,同时也可以使容器更易于管理。 1、查询网卡的名称:使用ifconfig命令查看网卡名…...

零基础Vue框架上手;git,node,yarn安装
项目搭建环境: git安装:Git - 安装 Git (git-scm.com)(官网) 下载路径:Git - Downloading Package (git-scm.com);根据自己电脑下载相对应的安装包 点next 点next,点到最后安装就行。…...

十分钟学会用springboot制作微信小程序富文本编辑器
1.1 富文本模型设计 在构建富文本编辑器系统时,首先需要设计一个合适的富文本模型。 CREATE TABLE IF NOT EXISTS rich_texts (id INT PRIMARY KEY AUTO_INCREMENT,title VARCHAR(255),content TEXT,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );这个表包括…...
【BBF系列协议】TR181-1 TR069的设备数据模型
TR-069的TR-181设备数据模型 执行摘要 TR-181定义了TR-069 [2]设备数据模型的版本1(设备:1)。设备:1数据模型仅适用于启用TR-069的终端设备,不适用于互联网网关设备或其他网络基础设施设备。启用TR-069的基础设施设备改为使用TR-098 [4]互联网网关设备数据模型或未来设备…...
Elasticsearch(简称ES)性能优化 实践
Elasticsearch(简称ES)性能优化主要包括以下几个方面: 索引优化: 选择合适的分片数:根据业务需求和数据量合理设置分片数,避免过多或过少分片造成性能问题。分片数过多会导致创建分片速度变慢、集群易崩溃…...
《跨越阶层,小白选专业的逻辑:揭秘家庭背景与个人发展的秘密联系》
文章目录 底层最好的专业 小康最好的专业 中产最好的专业 巨富最好的专业 总结 一个人选专业选的好不好,不在于专业本身,而在于你的出身,你的起点,你的家庭;你需要读懂你的原生家庭的文化才能改变自己。换句话说就是&a…...

设计模式(行为型)-中介者模式
目录 定义 类图结构展示 角色职责详解 模式的优缺点分析 优点 缺点 适用场景 应用实例 与其他模式的结合与拓展 总结 定义 中介者模式的核心思想可以概括为:用一个中介对象来封装一系列的对象交互。这个中介者就像一个通信枢纽,使各对象不需要…...

高考加油!UI界面生成器!
这个高考助力标语生成器具有以下特点: 视觉设计:采用了蓝色为主色调,搭配渐变背景和圆形装饰元素,营造出宁静而充满希望的氛围,非常适合高考主题。 标语生成:内置了超过 100 条精心挑选的高考加油标语&a…...
Redis击穿,穿透和雪崩详解以及解决方案
在 Java 开发中,Redis 作为常用的缓存中间件,可能会面临击穿、穿透、雪崩这三类经典问题。以下是对这三个问题的详细解析及对应的 Java 解决方案: 一、Redis 缓存击穿(Cache Breakdown) 问题描述 定义:大…...

因泰立科技:镭眸T51激光雷达,打造智能门控新生态
在高端门控行业,安全与效率是永恒的追求。如今,随着科技的飞速发展,激光雷达与TOF相机技术的融合,为门控系统带来了前所未有的智能感知能力,开启了精准守护的新时代。因泰立科技的镭眸T51激光雷达,作为这一…...
Cloudflare
Cloudflare 是一个网络基础设施和网站安全服务提供商,它的主要作用是让网站 更快、更安全、更可靠。简单来说,它是一个“护盾 加速器”。 🧩 Cloudflare 的主要功能: 1. 🚀 加速网站访问(CDN)…...

软考-系统架构设计师-第十六章 层次式架构设计理论与实践
层次式架构设计理论与实践 16.2 表现层框架设计16.3 中间层框架设计16.4 数据访问层设计16.5 数据架构规划与设计16.6 物联网层次架构设计 软件体系结构为软件系统提供了结构、行为和属性的高级抽象,由构成系统的元素描述这些元素的相互作用、指导元素集成的模式以及…...
爬虫工具链的详细分类解析
以下是针对爬虫工具链的详细分类解析,涵盖静态页面、动态渲染和框架开发三大场景的技术选型与核心特性: 🧩 一、静态页面抓取(HTML结构固定) 工具组合:Requests BeautifulSoup 适用场景:目标数…...

论文阅读笔记——Quo Vadis, Action Recognition? A New Model and the Kinetics Dataset
I3D 论文 UCF-101(13000多个视频)和 HMDB-51(7000多个视频)数据集过小,提出了 Kinetics 数据集,并且在其之上预训练之后能够迁移到其他小的数据集。 2DLSTM:使用2D CNN的好处是可以直接从 Ima…...

AR测量工具:精准测量,多功能集成
在日常生活中,我们常常会遇到需要测量物体长度、距离或角度的情况。无论是装修房屋、制作家具,还是进行户外活动,一个精准的测量工具都能大大提高我们的工作效率。AR测量工具就是这样一款集多种功能于一体的实用测量软件,它利用增…...
【Hive 运维实战】一键管理 Hive 服务:Metastore 与 HiveServer2 控制脚本开发与实践
一、引言 在大数据开发中,Hive 作为重要的数据仓库工具,其核心服务metastore(元数据服务)和hiveserver2(查询服务)的启停管理是日常运维的基础操作。手动执行命令启停服务不仅效率低下,还容易因…...