链表和 list

news2025/2/8 20:36:39

一、单链表的模拟实现

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();

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

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

相关文章

【AI大模型】Ubuntu18.04安装deepseek-r1模型+服务器部署+内网访问

以下内容主要参考博文&#xff1a;DeepSeek火爆全网&#xff0c;官网宕机&#xff1f;本地部署一个随便玩「LLM探索」 - 程序设计实验室 - 博客园 安装 ollama Download Ollama on Linux curl -fsSL https://ollama.com/install.sh | sh 配置 ollama 监听地址 ollama 安装后…

cmd执行mysql命令

安装mysql之后如果想使用cmd执行mysql命令&#xff0c;需要怎么操作呢&#xff0c;下面一起看一下。 安装mysql之后&#xff0c;如果直接去cmd窗口执行MySQL命令&#xff0c;窗口可能会提示mysql不是可执行命令。 需要配置系统的环境变量&#xff0c;将mysql的安装路径配置系…

网络安全威胁框架与入侵分析模型概述

引言 “网络安全攻防的本质是人与人之间的对抗&#xff0c;每一次入侵背后都有一个实体&#xff08;个人或组织&#xff09;”。这一经典观点概括了网络攻防的深层本质。无论是APT&#xff08;高级持续性威胁&#xff09;攻击、零日漏洞利用&#xff0c;还是简单的钓鱼攻击&am…

详细教程 | 如何使用DolphinScheduler调度Flink实时任务

Apache DolphinScheduler 非常适用于实时数据处理场景&#xff0c;尤其是与 Apache Flink 的集成。DolphinScheduler 提供了丰富的功能&#xff0c;包括任务依赖管理、动态调度、实时监控和日志管理&#xff0c;能够有效简化 Flink 实时任务的管理和部署。通过 DolphinSchedule…

【通俗易懂说模型】线性回归(附深度学习、机器学习发展史)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;深度学习_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前言 2. …

【R语言】apply函数族

在R语言中使用循环操作时是使用自身来实现的&#xff0c;效率较低。所以R语言有一个符合其统计语言出身的特点&#xff1a;向量化。R语言中的向量化运用了底层的C语言&#xff0c;而C语言的效率比高层的R语言的效率高。 apply函数族主要是为了解决数据向量化运算的问题&#x…

传统营销架构在当下如何进行优化转型?

随着市场环境的变化和数字技术的发展&#xff0c;传统营销架构越来越难以适应当下的营销市场。为了适应新时代的要求&#xff0c;企业也需要对营销架构进行优化转型。企业主可以着手从哪些方面进行调整呢&#xff1f;下面就来一同探讨下。 一、强调扁平化原则 扁平化与去中心化…

QMK启用摇杆和鼠标按键功能

虽然选择了触摸屏&#xff0c;我仍选择为机械键盘嵌入摇杆模块&#xff0c;这本质上是对"操作连续性"的执着。   值得深思的是&#xff0c;本次开发过程中借助DeepSeek的代码生成与逻辑推理&#xff0c;其展现的能力已然颠覆传统编程范式&#xff0c;需求描述可自动…

计算机网络-SSH基本原理

最近年底都在忙&#xff0c;然后这两天好点抽空更新一下。前面基本把常见的VPN都学习了一遍&#xff0c;后面的内容应该又继续深入一点。 一、SSH简介 SSH&#xff08;Secure Shell&#xff0c;安全外壳协议&#xff09;是一种用于在不安全网络上进行安全远程登录和实现其他安…

yolov11模型在Android设备上运行【踩坑记录】

0) 参考资料: https://github.com/Tencent/ncnn?tabreadme-ov-file https://github.com/pnnx/pnnx https://github.com/nihui/ncnn-android-yolov5 https://github.com/Tencent/ncnn?tabreadme-ov-file 1) &#xff1a;将xxx.pt模型转化成 xxx.onnx ONNX&#xff08;Ope…

win编译openssl

一、perl执行脚本 1、安装perl脚本 perl安装 2、配置perl脚本 perl Configure VC-WIN32 no-asm no-shared --prefixE:\openssl-x.x.x\install二、编译openssl 1、使用vs工具编译nmake 如果使用命令行nmake编译会提示“无法打开包括文件: “limits.h”“ 等错误信息 所以…

【B站保姆级视频教程:Jetson配置YOLOv11环境(七)Ultralytics YOLOv11配置】

Jetson配置YOLOv11环境&#xff08;7&#xff09;Ultralytics YOLOv11环境配置 文章目录 1. 下载YOLOv11 github项目2. 安装ultralytics包3. 验证ultralytics安装3.1 下载yolo11n.pt权重文件3.2 推理 1. 下载YOLOv11 github项目 创建一个目录&#xff0c;用于存放YOLOv11的项目…

硬核技术:小程序能够调用手机的哪些传感器

一、加速度传感器 小程序可以调用手机的加速度传感器来检测设备的运动状态。加速度传感器能够测量设备在三个轴&#xff08;X、Y、Z&#xff09;上的加速度变化。通过分析这些数据&#xff0c;小程序可以实现一些功能&#xff0c;如运动检测、步数统计、游戏中的动作感应等。 健…

Day 31 卡玛笔记

这是基于代码随想录的每日打卡 491. 非递减子序列 给你一个整数数组 nums &#xff0c;找出并返回所有该数组中不同的递增子序列&#xff0c;递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。 数组中可能含有重复元素&#xff0c;如出现两个整数相等&#xff0…

【蓝桥杯嵌入式】4_key:单击+长按+双击

全部代码网盘自取 链接&#xff1a;https://pan.baidu.com/s/1PX2NCQxnADxYBQx5CsOgPA?pwd3ii2 提取码&#xff1a;3ii2 1、电路图 将4个按键的引脚设置为input&#xff0c;并将初始状态设置为Pull-up&#xff08;上拉输入&#xff09; 为解决按键抖动的问题&#xff0c;我们…

Nginx进阶篇 - nginx多进程架构详解

文章目录 1. nginx的应用特点2. nginx多进程架构2.1 nginx多进程模型2.2 master进程的作用2.3 进程控制2.4 worker进程的作用2.5 worker进程处理请求的过程2.6 nginx处理网络事件 1. nginx的应用特点 Nginx是互联网企业使用最为广泛的轻量级高性能Web服务器&#xff0c;其特点是…

【算法专场】分治(下)

目录 前言 归并排序 思想 912. 排序数组 算法思路 算法代码 LCR 170. 交易逆序对的总数 算法思路 算法代码 315. 计算右侧小于当前元素的个数 - 力扣&#xff08;LeetCode&#xff09; 算法思路 算法代码 493. 翻转对 算法思路 算法代码 好久不见~时隔多日&…

OSPF基础(2):数据包详解

OSPF数据包(可抓包) OSPF报文直接封装在IP报文中&#xff0c;协议号89 头部数据包内容&#xff1a; 版本(Version):对于OSPFv2&#xff0c;该字段值恒为2(使用在IPV4中)&#xff1b;对于OSPFv3&#xff0c;该字段值恒为3(使用在IPV6中)。类型(Message Type):该OSPF报文的类型。…

Docker Desktop安装kubernetes时一直在Starting:Kubernetes failed to start

原因&#xff1a;由于墙的问题&#xff0c;导致拉取国外的K8s镜像失败 解决&#xff1a; 下载 k8s-for-docker-desktop 选中自己的kubernetes 版本 下载zip包 PowerShell运行load_images.ps1文件 重启docker kubernetes运行成功

StarSpider 星蛛 爬虫 Java框架 可以实现 lazy爬取 实现 HTML 文件的编译,子标签缓存等操作

StarSpider 星蛛 爬虫 Java框架 开源技术栏 StarSpider 能够实现 针对 HTML XSS SQL 数学表达式等杂乱数据的 爬取 解析 提取 需求&#xff01; 目录 文章目录 StarSpider 星蛛 爬虫 Java框架目录介绍如何获取&#xff1f;maven配置 架构是什么样的&#xff1f;结果对象的类…