手撕【双向链表】带头双向循环(2)

news2024/11/23 21:19:44

目录

Test.c

DList.h

DList.c

SLInsert

 SLErase

DList.c总代码

顺序表和链表的对比


今天继续再双向循环链表的基础上做修改。

❓提问:请你在10分钟内写一个带头双向循环链表。

其实我们只要把SLInsert 和 SLErase 写好就大功告成了!🆗

Test.c

#include"Dlist.h"
int main()
{
	SL* phead = SLInit();
	//头插
	SLPushFront(phead, 7);
	SLPushFront(phead, 77);
	SLPushFront(phead, 9);
	SLPushFront(phead, 99);
	SLPrint(phead);
	//头删
	SLPopFront(phead);
	SLPopFront(phead);
	SLPrint(phead);
	//尾插
	SLPushBack(phead,8);
	SLPushBack(phead, 88);
	SLPrint(phead);
	//尾删
	SLPopBack(phead);
	SLPopBack(phead);
	SLPrint(phead);
	//
	SLDestory(phead);
	phead = NULL;
	return 0;
}

DList.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLDataType;
typedef struct SListNode
{
	SLDataType val;
	struct SListNode* prev;
	struct SListNode* next;
}SL;
//初始化
SL* SLInit();
//打印数据
SL* SLPrint(SL* phead);
//查询
SL* SLFind(SL* phead, SLDataType x);
//头插
void SLPushFront(SL* phead, SLDataType x);
//头删
void SLPopFront(SL* phead);
//尾插
void SLPushBack(SL* phead, SLDataType x);
//尾删
void SLPopBack(SL* phead);
//在pos的前面插入
void SLInsert(SL* pos, SLDataType x);
//删除pos位置
void SLErase(SL* pos);
//销毁
void SLDestory(SL* phead);

DList.c

SLInsert

//在pos的前面插入
void SLInsert(SL* pos, SLDataType x)
{
	assert(pos);
	SL* cur = pos->prev;
	SL* newnode = Createnewnode(x);
	newnode->next = pos;
	pos->prev = newnode;
	cur->next = newnode;
	newnode->prev = cur;
}

 SLErase

//删除pos位置
void SLErase(SL* pos)
{
	assert(pos);
	SL* cur = pos->prev;
	SL* tail = pos->next;
	cur->next = tail;
	tail->prev = cur;
	free(pos);
	pos = NULL;
}

DList.c总代码

#include"Dlist.h"
//创建新的节点
SL* Createnewnode(SLDataType x)
{
	SL* newnode = (SL*)malloc(sizeof(SL));
	newnode->val = x;
	newnode->prev = NULL;
	newnode->next = NULL;
	return newnode;
}
//初始化
SL* SLInit()
{
	SL* phead = Createnewnode(-1);
	phead->prev = phead;
	phead->next = phead;
	return phead;
}
//打印
SL* SLPrint(SL* phead)
{
	assert(phead);
	assert(phead->next != phead);//不打印头节点
	SL* cur = phead->next;
	while (cur != phead)
	{
		printf("<=%d=>", cur->val);
		cur = cur->next;
	}
	printf("\n");
}
//查询
SL* SLFind(SL* phead, SLDataType x)
{
	assert(phead);
	SL* cur = phead->next;
	while (cur != phead)
	{
		if (cur->val == x)
		{
			return cur;
		}
	}
	return NULL;
}
//在pos的前面插入
void SLInsert(SL* pos, SLDataType x)
{
	assert(pos);
	SL* cur = pos->prev;
	SL* newnode = Createnewnode(x);
	newnode->next = pos;
	pos->prev = newnode;
	cur->next = newnode;
	newnode->prev = cur;
}
//删除pos位置
void SLErase(SL* pos)
{
	assert(pos);
	SL* cur = pos->prev;
	SL* tail = pos->next;
	cur->next = tail;
	tail->prev = cur;
	free(pos);
	pos = NULL;
}
//头插
void SLPushFront(SL* phead, SLDataType x)
{
	SLInsert(phead->next, x);
}
//头删
void SLPopFront(SL* phead)
{
	assert(phead->next != phead);//不删除头节点
	SLErase(phead->next);
}
//尾插
void SLPushBack(SL* phead, SLDataType x)
{
	SLInsert(phead, x);
}
//尾删
void SLPopBack(SL* phead)
{
	assert(phead->next != phead);//不删除头节点
	SLErase(phead->prev);
}
//销毁
void SLDestory(SL* phead)
{
	assert(phead);
	SL* cur = phead->next;
	while (cur != phead)
	{
		SL* tmp = cur->next;
		free(cur);
		cur = tmp;
	}
	free(phead);
	cur = NULL;
}

 

 🙂🙂是不是很简单,动手快速写一写吧!!

顺序表和链表的对比

链表(双向)的优势:

  • 任意位置插入删除都是O(1)
  • 知道pos位置并且插入和删除,都是O(N)  //后期学习哈希可以达到O(1)
  • 按需求申请释放,合理利用空间,不存在浪费

链表(双向)劣势:

  • 下标随机访问不方便O(N) //不支持高效排序

顺序表优势:

  • 支持下标随机访问O(1)
  • CPU高速缓存命中率比较高 

 顺序表劣势:

  • 头部或者中间插入删除效率低,要挪动数据。O(N)
  • 空间不够需要扩容,扩容有一定的消耗,且可能存在一定的空间浪费
  • 只适合尾插尾删

有人可能问CPU高速缓存命中率比较高是什么?

 电脑中负责运算就是 CPUGPU(显卡等)。负责存储就是内存硬盘(磁盘/固态)。内存是带电暂时存储,速度相对较快硬盘是不带电,永久存储,读写速度相对慢。

当然除了内存和硬盘这两个存储介质,还有其他的存储介质。就是缓存  虽然内存速度相较于硬盘快,但是对于CPU来说还是慢了,于是就有围绕在CPU附近的缓存。

缓存中,缓存的存储数据越少,速度越快。所以,小的数据会放到寄存器大的数据会放到高速缓存中去。像顺序表/链表/数组这样的数据存储,当然是放到高速缓存中。

那么数据是怎样放入缓存,CPU怎样去访问高速缓存中的数据呢?

  • 首先CPU会到高速缓存中去查看需要访问的数据是否在缓存中
  • 如果在就访问成功(命中)
  • 如果不在(没命中)就把数据 加载 高速缓存中(不是一个一个加载,而是一段一段的加载)
  • 加载之后再去访问

对于顺序表来说,物理结构上的连续,加载和访问时的命中率更高

对于链表来说,只是逻辑上的连续,物理空间可能相隔很远,所以命中率相对没有那么高,而且很容易造成缓存污染(空间存储都是一些无用的数据)

这个也叫:局部性原理

 想要更加深入的了解【戳一戳】:与程序员相关的CPU缓存知识 | 酷 壳 - CoolShell

✔✔✔✔✔最后感谢大家的阅读,若有错误和不足,欢迎指正!乖乖敲代码哦! 

代码---------→【唐棣棣 (TSQXG) - Gitee.com】

联系---------→【邮箱:2784139418@qq.com】

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

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

相关文章

TensorFlow: 框架的自动微分机制

自动微分&#xff08;Automatic differentiation&#xff09;是深度学习框架中的一个关键功能&#xff0c;它为我们提供了一种便捷且高效的方式来求解函数的导数。在TensorFlow中&#xff0c;作为一款流行且强大的机器学习框架&#xff0c;自动微分机制为用户提供了一个方便的方…

004 OpenCV akaze特征点检测匹配

目录 一、环境 二、akaze特征点算法 2.1、基本原理 2.2、实现过程 2.3、实际应用 2.4、优点与不足 三、代码 3.1、数据准备 3.2、完整代码 一、环境 本文使用环境为&#xff1a; Windows10Python 3.9.17opencv-python 4.8.0.74 二、akaze特征点算法 特征点检测算法…

ctyunos 与 openeuler

ctyunos-2.0.1-220311-aarch64-dvd ctyunos-2.0.1-220329-everything-aarch64-dvd glibc python3 对应openEuler 20.03 LTS SP1

Selenium操作已经打开的Chrome浏览器窗口

Selenium操作已经打开的Chrome浏览器窗口 0. 背景 在使用之前的代码通过selenium操作Chrome浏览器时&#xff0c;每次都要新打开一个窗口&#xff0c;觉得麻烦&#xff0c;所以尝试使用 Selenium 获取已经打开的浏览器窗口&#xff0c;在此记录下过程 本文使用 chrome浏览器来…

Word中NoteExpress不显示的问题

首先确认我们以及安装了word插件 我们打开word却没有。此时我们打开&#xff1a;文件->选项->加载项 我们发现被禁用了 选择【禁用项目】&#xff08;如果没有&#xff0c;试一试【缓慢且禁用的加载项】&#xff09;&#xff0c;点击转到 选择启用 如果没有禁用且没有出…

基于SSM的校园家教兼职信息交流平台设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

μC/OS-II---消息邮箱管理1(os_mbox.c)

目录 消息邮箱创建消息邮箱删除等待邮箱中的消息向邮箱发送一则消息 消息邮箱创建 OS_EVENT *OSMboxCreate (void *pmsg) {OS_EVENT *pevent; #if OS_CRITICAL_METHOD 3u /* Allocate storage for CPU status register */OS_CPU_SR cpu_sr …

比特币上的人工智能

以感知机为例 人工智能&#xff0c;尤其是机器学习形式的人工智能&#xff0c;最近取得了巨大的进步&#xff0c;应用范围从人脸识别到自动驾驶汽车。我们建议将 AI 与比特币区块链结合起来&#xff0c;以获得许多其他方式无法实现的显着优势&#xff1a; 公开透明&#xff1a…

面试资料快速复习 Git常用命令(简单实用)

Git-command Git常用命令、面试复习、简单实用命令 ​ 一、概念理解 &#xff08;一&#xff09;工作区、暂存区、本地仓库、远程仓库 workspace&#xff1a;工作区staging area&#xff1a;暂存区/缓存区local repository&#xff1a;本地仓库remote repository&#xff…

前端实现页面内容的截图与下载(html2canvas)

今天是一个发文的好日子&#x1f600;~ &#x1f447;&#x1f447;&#x1f447; 一个需求&#xff0c;要截取页面中的内容并截图保存&#xff0c;来看一看我是怎么实现的吧&#xff1a; 这里需要使用到插件--html2canvas 1.安装并引入html2canvas npm install html2canv…

Es 拼音搜索无法高亮

目录 背景&#xff1a; Es 版本&#xff1a; 第一步 第二步 &#xff08;错误步骤 - 只是记录过程&#xff09; 第三步 第四步 第五步 第六步 第七步 背景&#xff1a; app 原有的搜索功能无法进行拼音搜索&#xff0c;产品希望可以支持&#xff0c;例如内容中含有&a…

upload-labs关卡10(点和空格绕过)通关思路

文章目录 前言一、回顾前几关知识点二、靶场第十关通关思路1、看源代码2、bp抓包绕过3、检查文件是否成功上传 总结 前言 此文章只用于学习和反思巩固文件上传漏洞知识&#xff0c;禁止用于做非法攻击。注意靶场是可以练习的平台&#xff0c;不能随意去尚未授权的网站做渗透测…

软件质量保护与测试(第2版)学习总结第十一章 白盒测试

错误隐藏在角落里、集聚在边界处 ----Boris Beizer 白盒测试是看源代码的&#xff0c;静态分析和动态分析 11.2 控制流测试 程序结构主要有3种 顺序结构、分支结构、循环结构 #include "stdafx.h" …

C++实现KNN和K-Means

学校机器学习课程的实验课要求实现KNN和K-Means&#xff1a; &#xff08;平时没听课&#xff09;临时去查了一下KNN和K-Means是啥&#xff0c;然后自己用C写了小例子&#xff0c;想着写都写了那就把代码贴出来吧。 顺便再聊聊自己对于这俩算法的理解。 下面是文心一言的回答…

洛谷 P3131 [USACO16JAN] Subsequences Summing to Sevens S

被普及-卡的没思路真是蒟蒻啊233 优化思路 每次都在枚举(a[r]-a[l-1])%70&#xff0c;所以可以认为数组大小对最终答案没有影响&#xff0c;考虑对前缀和数组取模&#xff0c;那么如果有a[r]的值等于a[l-1]的值相等&#xff08;即余数相等&#xff09;&#xff0c;那么两者相减…

米尔AM62x核心板,高配价低,AM335x升级首选

AM335x是TI经典的工业MPU&#xff0c;它引领了一个时代&#xff0c;即工业市场从MCU向MPU演进&#xff0c;帮助产业界从Arm9迅速迁移至高性能Cortex-A8处理器。随着工业4.0的发展&#xff0c;HMI人机交互、工业工控、医疗等领域的应用面临迫切的升级需求&#xff0c;AM62x处理器…

Python 双门双向门禁控制板实时监控源码

本示例使用设备&#xff1a;实时网络双门双向门禁控制板可二次编程控制网络继电器远程开关-淘宝网 (taobao.com) #python通过缩进来表示代码块&#xff0c;不可以随意更改每行前面的空白&#xff0c;否则程序会运行错误&#xff01;&#xff01;&#xff01;如果缩进不一致&a…

这款IDEA插件真的爱了

IDEA是一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;它可以帮助开发人员更加高效地编写、调试和部署软件应用程序。我们在编写完接口代码后需要进行接口调试等操作&#xff0c;一般需要打开额外的调试工具。 今天给大家介绍一款IDEA插件&#xff1a;Api…

Taro编译警告解决方案:Error: chunk common [mini-css-extract-plugin]

文章目录 1. 背景2. 问题分析3. 解决方案3.1 更新 Taro 版本3.2 更新相关依赖3.3 调整 webpack 配置3.4 检查依赖版本 4. 拓展与分析4.1 拓展4.2 避免不必要的依赖4.3 查阅 Taro GitHub 仓库 5. 总结 &#x1f389;欢迎来到Java学习路线专栏~Taro编译警告解决方案&#xff1a;E…

golang学习笔记——斐波纳契数列

斐波纳契数列 编写一个程序来计算某个数字的斐波纳契数列。 斐波那契数列是一个数字列表&#xff0c;其中每个数字是前两个斐波那契数字之和。 例如&#xff0c;数字 6 的序列是 1,1,2,3,5,8&#xff0c;数字 7 的序列是 1,1,2,3,5,8,13&#xff0c;数字 8 的序列是 1,1,2,3,5…