链表和 list

一、单链表的模拟实现

1.实现方式

链表的实现方式分为动态实现和静态实现两种。
动态实现是通过 new 申请结点,然后通过 delete 释放结点的形式构造链表。这种实现方式最能体
现链表的特性;
静态实现是利用两个数组配合来模拟链表。一个表示数据域,另一个表示指针域,它的运行速度很快。下面演示的也都是单链表的静态实现。
2.定义 - 创建 - 初始化
两个足够大的数组,elem数组(e)用来存数据,next数组(ne)用来存下一个结点的位置;变量 h ,充当头指针,表示头结点的位置;变量 id ,为新来的结点分位置。
const int N = 1e5 + 10;
int h; // 头指针
int id; // 下一个元素分配的位置
int e[N], ne[N]; // 数据域和指针域

3.头插

//头插
void push_front(int x)
{
	id++;
	e[id]=x;
	mp[x]=id;
	ne[id]=ne[h];
	ne[h]=id;	
} 

4.遍历链表

//遍历链表
void print()
{
	for(int i=ne[h];i;i=ne[i])
	{
		cout << e[i] << " ";	
	}	
	cout << endl << endl;
} 

5.按值查找

int mp[N]; // mp[i] 表示 i 在这个元素存放的位置
//push_front的时候,mp[x] = id; // x 这个元素存放的位置是 id
//按值查找
int find(int x)
{
	//策略一
	int i;
	for(i=ne[h];i;i=ne[i])
	{
		if(e[i]==x)
			return i;	
	}
	return 0;
	//策略二
	return mp[x];
}

第一种方式就是遍历链表,如果存储的值数据范围不大,就可以用哈希表优化,就是第二种方式。当然第二种方式是有局限性的,一是存的数据过大会导致崩溃,二是不能存在相同的数据,否则这个数组中的部分数据会进行刷新。

6.在任意位置之后插入元素

//在任意位置之后插入元素
void insert(int p,int x)
{
	id++;
	e[id]=x;
	mp[x]=id;
	ne[id]=ne[p];
	ne[p]=id;
} 

7.删除任意位置之后的元素

//删除任意位置之后的元素
void erase(int p)
{
	if(ne[p])
	{
		mp[e[ne[p]]]=0;
		ne[p]=ne[ne[p]];
	}
}
在单链表的模拟实现中,我们可以发现虽然一个节点是由其数据域和指针域组成的,但真正代表该节点信息的是数据域和下标,指针域只是为了连接下一个节点的工具(其实就是下一个节点的下标,本质上是属于下一个节点的)。有了这个工具我们就能通过elem数组找到下一个节点的数据域,也能通过next数组找到下一个节点的指针域。以上就是单链表的内容了。那我们为什么不像顺序表一样,实现一个尾插、尾删、删除任意位置的元素等操作呢? 其实是能实现,但是没必要。因为时间复杂度是 O ( N ) 级别的。

二、双向链表的模拟实现

1.实现方式

依旧采用静态实现的方式。双向链表无非就是在单链表的基础上加上一个指向前驱的指针,那就再来一个数组,充当指向前驱的指针域即可。
2.定义
const int N = 1e5 + 10;
int h; // 头结点
int id; // 下一个元素分配的位置
int e[N]; // 数据域
int pre[N], ne[N]; // 前后指针域
int mp[N];

3.头插

//头插
void push_front(int x)
{	
	id++;
	e[id]=x;
	mp[x]=id;
	pre[id]=h;
	ne[id]=ne[h];
	pre[ne[h]]=id;
	ne[h]=id;
} 

4.遍历链表

可以直接无视 prev 数组,与单链表的遍历方式一致。
//遍历链表
void print()
{
	for(i=ne[h];i;i=ne[i])
	{
		cout << e[i] << " ";
	}
	cout << endl << endl;	
} 

5.按值查找

不考虑特殊情况,直接使用 mp 数组优化了。
//按值查找
int find(int x)
{
	return mp[x];	
} 

6.在任意位置之后插入元素

//在任意位置之后插入元素
void insert_back(int p,int x)
{
	id++;
	e[id]=x;
	mp[x]=id;
	pre[id]=p;
	ne[id]=ne[p];
	pre[ne[p]]=id;
	ne[p]=id;
}

7.在任意位置之前插入元素

//在任意位置之前插入元素
void insert_front(int p,int x)
{
	id++;
	e[id]=x;
	mp[x]=id;
	pre[id]=pre[p];
	ne[id]=p;
	ne[pre[p]]=id;
	pre[p]=id;
}

8.删除任意位置的元素

//删除任意位置的元素
void erase(int p)
{
	mp[e[p]]=0;
	ne[pre[p]]=ne[p];
	pre[ne[p]]=pre[p];
}

我们可以看出,双向链表只是在单链表的基础上加了pre这个前驱指针数组,本质和单链表无异,就是清楚指针域之间的关系。

三、循环链表的模拟实现

回看之前实现的带头单向链表。我们定义0表示空指针,但其实哨兵位就在0位置,所有的结构正好成环。因此循环链表就是在原有的基础上,让最后一个元素指向表头即可。在这里就用一道算法题来说明循环链表。
因为报数一直绕着圈进行,所以我们可以使用循环链表。操作的次数比较明显,因为要使所有人出圈,所有要操作总人数的次数,也就是n。在进行每一步操作时,要数m个人,但是如果数到第m个的话,我们改变其前面元素的指针域就会很困难了,所以我们可以数m-1次,再使用指针域找到第m个人的信息。
#include <iostream>
using namespace std;
const int N=110;
int ne[N]; 
int main() 
{
	int n,m;
	cin >> n >> m;
	for(int i=1;i<n;i++)
	{
		ne[i]=i+1;
	}
	ne[n]=1;
	int t=n;
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<m-1;j++)
		{
			t=ne[t];
		}
		cout << ne[t] << " ";
		ne[t]=ne[ne[t]];
	}
	return 0;
}

四、动态链表 - list

STL 里面的 list 的底层就是动态实现的双向循环链表,增删会涉及 new 和 delete,因为new 和 delete 是非常耗时的操作,效率不高,在竞赛中一般不会使用。因为和vector都是STL的容器,使用操作也差不多,只要正常使用接口就能实现。
1. 创建 list
list<int> lt;

2.push_front / push_back

push_front :头插;push_back :尾插。
 // 尾插
 lt.push_back(i);
 // 头插
 lt.push_front(i);
3. pop_front / pop_back
pop_front :头删;pop_back :尾删
 // 头删
 lt.pop_front();
 // 尾删
 lt.pop_back();

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

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

相关文章

C语言switch case语句详解(非常详细)

在C语言中&#xff0c;switch case 语句是一种多分支选择结构&#xff0c;用于根据变量的值执行不同的代码块。 相比于if else语句&#xff0c;switch case在处理多个固定值的条件判断时更加简洁和高效。本文将详细讲解switch case语句的用法、语法格式、实例代码、注意事项&a…

DeepSeek本地部署

前言 蛇年过年前&#xff0c;国产大模型 DeepSeek以更高的效率、更低的计算成本火爆国内外&#xff0c;成为现象级AI&#xff0c;但由于访问人数过多经常频繁出现反应迟缓甚至是宕机的情况。 但万幸的是&#xff0c;DeepSeek 是一个开源模型&#xff0c;我们可以通过本地部署…

springboot简单应用

快速开发Springboot项目实现简单的增删改查&#xff0c;前期需要准备&#xff1a;idea与postman安装 Maven&#xff0c;MySQL&#xff08;8&#xff09;&#xff0c;JDK(21) 目录 前言 springboot 使用3.0版本&#xff0c;JDK使用21,MySQL使用8版本 开发环境IDEA使用2024版本 …

tomcat核心组件及原理概述

目录 1. tomcat概述 1.1 概念 1.2 官网地址 2. 基本使用 2.1下载 3. 整体架构 3.1 核心组件 3.2 从web.xml配置和模块对应角度 3.3 如何处理请求 4. 配置JVM参数 5. 附录 1. tomcat概述 1.1 概念 什么是tomcat Tomcat是一个开源、免费、轻量级的Web服务器。 Tomca…

【Linux】24.进程间通信(3)

文章目录 3.6 systemv共享内存3.6.1 共享内存函数3.6.3 一个简单的共享内存代码实现3.6.4 一个复杂的共享内存代码实现3.6.4 key和shmid的主要区别: 3.7 systemv消息队列&#xff08;了解&#xff09;3.8 systemv信号量&#xff08;了解&#xff09;进程互斥四个问题理解信号量…

115,【7】 攻防世界 web fileinclude

进入靶场 试着访问了几个文件&#xff0c;都没得到信息&#xff0c;f12看看源码 还真有 <?php // 检查是否开启了错误显示功能 // ini_get 函数用于获取 PHP 配置选项的值&#xff0c;这里检查 display_errors 选项是否开启 if( !ini_get(display_errors) ) {// 如果错误…

深入理解Java引用传递

先看一段代码&#xff1a; public static void add(String a) {a "new";System.out.println("add: " a); // 输出内容&#xff1a;add: new}public static void main(String[] args) {String a null;add(a);System.out.println("main: " a);…

langchain教程-7.Embedding/文本向量化

前言 该系列教程的代码: https://github.com/shar-pen/Langchain-MiniTutorial 我主要参考 langchain 官方教程, 有选择性的记录了一下学习内容 这是教程清单 1.初试langchain2.prompt3.OutputParser/输出解析4.model/vllm模型部署和langchain调用5.DocumentLoader/多种文档…

Mac下使用brew安装go 以及遇到的问题

首先按照网上找到的命令进行安装 brew install go 打开终端输入go version&#xff0c;查看安装的go版本 go version 配置环境变量 查看go的环境变量配置&#xff1a; go env 事实上安装好后的go已经可以使用了。 在home/go下新建src/hello目录&#xff0c;在该目录中新建…

Ubuntu部署Deepseek-R1模型(8b)

安装ubuntu系统 本机电脑系统ubuntu-20.04 #升级软件 sudo apt-get update#安装curl sudo apt-get install curl通过以上两条指令&#xff0c;完成了curl命令的安装。 安装ollama 打开Ollama官网 选择Linux&#xff0c; 给出如上图方框所示的一条指令 curl -fsSL https:…

【ROS视频推流】使用web_video_server完成视频推流

&#x1f680; 本文简要介绍一下使用web_video_server功能包完成实时视频推流的方法。 假设有A,B两个设备&#xff0c;它们之间可以ping通。我们需要将A设备上的实时摄像头图像推流并在B设备的浏览器上显示。 &#x1f314;01准备工作 # A设备 # 下载视频推流功能包 #&#xff…

[LVGL] 在VC_MFC中移植LVGL

前言&#xff1a; 0. 在MFC中开发LVGL的优点是可以用多个Window界面做辅助扩展 1.本文基于VC2022-MFC单文档框架移植lvgl8 2. gitee上下载lvgl8.3 源码&#xff0c;并将其文件夹改名为lvgl lvgl: LVGL 是一个开源图形库&#xff0c;提供您创建具有易于使用的图形元素、漂亮…

Java----线程池

什么是线程池呢&#xff0c;先举一个情景&#xff1a; 一个火锅店开业了&#xff0c;早上人比较少&#xff0c;大家进店后不需要预约&#xff0c;直接付款在店里的桌子上吃饭&#xff0c;慢慢的人多了&#xff0c;店里的桌子不够用了&#xff0c;没座位的人可以先预约&#xf…

安卓开发,底部导航栏

1、创建导航栏图标 使用系统自带的矢量图库文件&#xff0c;鼠标右键点击res->New->Vector Asset 修改 Name , Clip art 和 Color 再创建一个 同样的方法再创建四个按钮 2、添加百分比布局依赖 app\build.gradle.kts 中添加百分比布局依赖&#xff0c;并点击Sync Now …

每日Attention学习22——Inverted Residual RWKV

模块出处 [arXiv 25] [link] [code] RWKV-UNet: Improving UNet with Long-Range Cooperation for Effective Medical Image Segmentation 模块名称 Inverted Residual RWKV (IR-RWKV) 模块作用 用于vision的RWKV结构 模块结构 模块代码 注&#xff1a;cpp扩展请参考作者原…

Git--使用教程

Git的框架讲解 Git 是一个分布式版本控制系统&#xff0c;其架构设计旨在高效地管理代码版本&#xff0c;支持分布式协作&#xff0c;并确保数据的完整性和安全性。 Git 的核心组件&#xff1a; 工作区&#xff08;Working Directory&#xff09;&#xff1a; 工作区是你在本…

智慧停车系统:不同规模停车场的应用差异与YunCitys解决方案

在智慧停车领域&#xff0c;不同规模停车场因自身特点&#xff0c;对智慧停车系统的需求和应用效果存在显著差异。云创智城凭借丰富的经验和先进的技术&#xff0c;为各类规模停车场打造了贴合需求的智慧停车系统&#xff0c;下面为您详细剖析。 小型停车场&#xff1a;精准高…

snort的学习记录

一、what is snort&#xff1f;什么是snort? Snort 是一款开源的 网络入侵检测系统&#xff08;NIDS&#xff09; 和 网络入侵防御系统&#xff08;NIPS&#xff09;&#xff0c;能够实时监控网络流量&#xff0c;检测恶意行为&#xff08;如端口扫描、SQL注入、DDoS攻击等&a…

PHP-trim

[题目信息]&#xff1a; 题目名称题目难度PHP-trim1 [题目考点]&#xff1a; trim() 函数移除字符串两侧的空白字符或其他预定义字符。[Flag格式]: SangFor{dl9hFiITmhQNAJysCgigAskyCZ6kQaDc}[环境部署]&#xff1a; docker-compose.yml文件或者docker tar原始文件。 ht…

maven如何不把依赖的jar打包到同一个jar?

spring boot项目打jar包部署&#xff1a; 经过以下步骤&#xff0c; 最终会形成maven依赖的多个jar&#xff08;包括lib下添加的&#xff09;、 我们编写的程序代码打成一个jar&#xff0c;将程序jar与 依赖jar分开&#xff0c;便于管理&#xff1a; success&#xff1a; 最终…