【算法】Java-使用数组模拟单向链表,双向链表
目录
试题1:实现一个单链表,并实现以下功能:
试题2:实现一个双链表,并实现以下功能
思路总结:
什么情况下可能涉及到用数组实现链表呢?
在学习时了解到了可以用数组模拟链表,使其兼顾数据查找快,链表新增和删除快的缺点,找来一些试题实现了下,如下:
试题1:实现一个单链表,并实现以下功能:
Java代码实现:
import org.apache.commons.lang3.StringUtils;import java.util.Scanner;public class ArrayLinkedList {public static final int N = 100000;private int head; // headprivate int idx; // 存储新元素的索引下标private int[] e; // 存放数据的数组;private int[] ne; // 当前节点的下一个节点的地址(数组下标)。比如使用头插法,单向链表,e[5] = 5,e[5]的下一个节点的坐标是ne[5],下一个节点是e[ne[5]]public ArrayLinkedList() {e = new int[N];ne = new int[N];head = -1;idx = 0;}public void insertToHead(int val) {e[idx] = val;ne[idx] = head; // head的值是头结点指向的下一个元素的下标值head = idx++;}/*** 将val插入到索引k后面** @param k* @param val*/public void insert(int k, int val) {e[idx] = val;ne[idx] = ne[k];ne[k] = idx++;}/*** 删除k节点后面的节点(只删一个)** @param k*/public void remove(int k) {if (k + 1 == 0) {head = ne[head];} else {ne[k] = ne[ne[k]];}}public static void main(String[] args) {System.out.println("请输入:");Scanner scanner = new Scanner(System.in);ArrayLinkedList arrayLinkedList = new ArrayLinkedList();int head = arrayLinkedList.head;int[] e = arrayLinkedList.e;int[] ne = arrayLinkedList.ne;while (scanner.hasNextLine()) {String inputString = scanner.nextLine();if (StringUtils.isBlank(inputString)) {break;}String[] inputArr = inputString.split(" ");String f = inputArr[0];int s = Integer.valueOf(inputArr[1]);switch (f) {case "H":arrayLinkedList.insertToHead(s);break;case "D":arrayLinkedList.remove(s - 1); // 第k个插入的数,idx是k-1break;case "I":int val = Integer.valueOf(inputArr[2]);arrayLinkedList.insert(s - 1, val);break;}}for (int i = head; i != -1; i = ne[i]) {System.out.print(e[i] + " ");}scanner.close();}
}
试题2:实现一个双链表,并实现以下功能
Java代码实现:
import org.apache.commons.lang3.StringUtils;import java.util.Scanner;/*** 支持的操作:* 1、在最左侧插入一个数;* 2、在最右侧插入一个数;* 3、将第k个插入的数删除;* 4、在第k个插入的数左侧插入一个数;* 5、在第k个插入的数右侧插入一个数*/
public class TwoWayLinkedList2 {public static final int N = 100000;// 存放数组的数据private int[] e;// 存放左指针下标数组private int[] l;// 存放右指针地址数组private int[] r;// 数组待存储下标private int idx;// e[0]表示链表头;e[1]表示链表尾// 向左侧插入,就是插入到上一个节点的右侧。所以插入的逻辑都抽象成插入到具体节点的右侧// 构造方法public TwoWayLinkedList2() {e = new int[N];r = new int[N];l = new int[N];r[0] = 1;l[1] = 0;idx = 2;}/*** 将节点插入到e[k]节点右侧** @param k* @param val*/public void add(int k, int val) {e[idx] = val;l[idx] = k;r[idx] = r[k];l[r[k]] = idx;r[k] = idx;idx++;}/*** 删除e[k]** @param k*/public void remove(int k) {r[l[k]] = r[k];l[r[k]] = l[k];}public static void main(String[] args) {System.out.println("请输入:");Scanner scanner = new Scanner(System.in);TwoWayLinkedList2 linkedList = new TwoWayLinkedList2();int[] e = linkedList.e;int[] l = linkedList.l;int[] r = linkedList.r;while (scanner.hasNextLine()) {String inputString = scanner.nextLine();if (StringUtils.isBlank(inputString)) {break;}String[] inputArr = inputString.split(" ");String f = inputArr[0];Integer s = Integer.valueOf(inputArr[1]);switch (f) {case "L":linkedList.add(0, s);break;case "R":linkedList.add(l[1], s);break;case "D":linkedList.remove(s + 1); // 第k个插入的数,idx是k+1,因为我们用了0和1表示链表头和链表尾break;case "IL":linkedList.add(l[s + 1], Integer.valueOf(inputArr[2]));break;case "IR":linkedList.add(s + 1, Integer.valueOf(inputArr[2]));break;}}// 遍历输出for (int i = r[0]; i != 1; i = r[i]) {System.out.printf("" + e[i]);}scanner.close();}
}
思路总结:
数组实现链表,一个数组用于存放数据,一个数组存放"指针",这里的指针用数组下标代替。如果是双向链表,要用两个数组存放指针。同时要注意首节点和尾结点的记录方法。在实现双链表时,我曾用两个变量表示首尾节点,对比起来,没有用e[0],e[1]表示简洁,而且非常容易搞混。占用第0位和第1位保存链表头和尾时要注意初始的idx=2,第k个插入的元素的索引下标是k+1。大家可以使用更多方法实现,过程虽然曲折,但一顿操作下来,对链表的操作会非常的熟练。
什么情况下可能涉及到用数组实现链表呢?
在没有操作系统和内存管理的情况下。
1. 链表的实现需要动态内存分配和释放,这需要操作系统提供的堆内存管理。没有 OS 的动态内存管理,就无法真正实现链表节点的创建和销毁。
2. 链表通过指针链接节点,需要操作系统提供的指针和地址引用机制。没有 OS,就无法真正用指针建立节点之间的链接关系。
3. 数组可以预先分配一块内存,这个内存块可以视为堆内存,用下标代替指针,通过数组操作就可以模拟出指针操作。
4. 数组是一块连续的内存,空间固定,不需要动态扩展,所以定义数组后直接就可以使用,不依赖动态内存管理。
5. 数组中的每个元素是连续存储的,通过下标可以直接访问,不需要指针来进行寻址。可以模拟指针的移动,改变指针的指向来实现链表的操作。
这里我们从算法分析和学习的角度来看这个问题,但不适合实际项目,只能处理规模较小的数据。要实现一个真正的可扩展链表,还需在操作系统上进行动态内存管理。
相关文章:

【算法】Java-使用数组模拟单向链表,双向链表
目录 试题1:实现一个单链表,并实现以下功能: 试题2:实现一个双链表,并实现以下功能 思路总结: 什么情况下可能涉及到用数组实现链表呢? 在学习时了解到了可以用数组模拟链表,使其…...

Nessus简单介绍与安装
Nessus简单介绍与安装 1.Nessus简介 Nessus号称是世界上最流行的漏洞扫描程序,全世界有超过75000个组织在使用它。该工具提供完整的电脑漏洞扫描服务,并随时更新其漏洞数据库。Nessus不同于传统的漏洞扫描软件,Nessus可同时在本机或远端上遥…...

【每天一道算法题】day2-认识时间复杂度
认识时间复杂度: O:读作big O,在数学上指的是上限的意思 常数时间的操作 一个操作如果和样本的数据量没有关系,每次都是固定时间内完成的操作,叫做常数操作。时间复杂度为一个算法流程中,常数操作数量的一…...
前端报错合集
error Component name “index“ should always be multi-word vue/multi-word-component-names 的解决办法 原因组件命名是 没有采用驼峰 error Component name “index“ should always be multi-word vue/multi-word-component-names 的解决办法_error component name &qu…...

Milvus以及Web UI 安装
向量数据库懂的都懂 版本数据 [rootiZ7xv7q4im4c48qen2do2bZ project]# cat /etc/redhat-release CentOS Stream release 9 [rootiZ7xv7q4im4c48qen2do2bZ project]# docker version Client: Docker Engine - CommunityVersion: 24.0.5API version: 1.43Go v…...

Go for循环中的defer
背景 写个后台程序,定时抓取服务器指标,代码逻辑如下,使用一段时间后内存不断增加 func CollectInfo() {for {// 获取服务器信息代码// ...............resp, err : http.Post("http://server", "application/json", str…...

创建开机自启的脚本
在启动许多ros节点时有多种方式,我推荐使用launch来启动所有的节点,这也是一种规范的方式。以后会慢慢向这个方向靠。 除此之外还可以通过创建的脚本来启动: 脚本位置不限,只需要: sudo gedit xxx.sh在里面添加相应的…...

学生信息系统(python实现)
#codingutf-8 import os.path filenamestudent.txtdef menm():#菜单界面print(学生管理系统)print(-----------------------------功能菜单-----------------------------)print(\t\t\t\t\t\t1.录入学生信息)print(\t\t\t\t\t\t2.查找学生信息)print(\t\t\t\t\t\t3.删除学生信息…...
管理类联考——数学——汇总篇——知识点突破——数据分析——1. 计数原理——排列组合——公式
排列组合 排列与组合的推导: 从n个不同的元素中取出m(m≤n)个元素做排列为 A n m A_n^m An...

C#,《小白学程序》第十六课:随机数(Random)第三,正态分布的随机数的计算方法与代码
1 随机数的问题 用 C# Random 类生成的随机数是平均分布的。也就是各数据段的出现的次数差不多。彩票号码属于这种随机数。 而很多很多常见的随机数,比如:成绩,却是符合正态分布的。 因而很多时候需要生成符合正态分布规律的随机数。 2 文…...

一文读懂java变量类型
前言 在学习和使用Java编程语言时,理解变量类型是至关重要的基础知识。Java是一种静态类型语言,强调变量必须先声明其类型,才能进行后续操作。因此,对于初学者来说,了解Java中不同的变量类型及其特性是迈向编程成功的…...

解决windows下git操作提示用户名密码错误的问题
当代码从一个平台切换到另一个平台的时候,需要做两步操作,第一步就是更新git的仓库地址,在项目的.git/config文件里面修改,这一步做完之后,就可以推送代码到新的仓库了,这里就是重点来了。 一般第一次推动代…...

ESP32开发:Clion配置IDF
IDF环境搭建 使用安装包安装IDF 可以通过安装包进行安装,如下图: 下载链接如下:https://dl.espressif.cn/dl/esp-idf/?idf4.4 安装好后,IDF会添加环境变量IDF_TOOLS_PATH,如果要安装多个IDF,为了防止冲…...

伦敦金的走势高低的规律
伦敦金市场是一个流动性很强的市场,其价格走势会在诸多因素的影响下,出现反复的上下波动,如果投资者能够在这些高低走势中找到一定的规律,在相对有利的时机入场和离场,就能够通过不断的交易,累积大量的财富…...

【C#-1】C#调用matlab生成的dll库
matlab打包dll 1、matlab示例程序: function untitled4(x)z peaks(x);figuresurf(z) end 2、输入deploytool打包matlab程序,具体如下: 3、拷贝 打包成功后,将生成for_redistribution_files_only文件夹中的dll文件拷贝到C#程序…...
MATLAB中pdist和pdist2的区别
一、pdist 和 pdist2 是MATLAB中用于计算距离矩阵的两个不同函数,它们的区别在于输入和输出以及一些计算选项。 pdist: pdist函数用于计算一组点之间的距离。 输入:通常接受一个矩阵,矩阵的每一行代表一个数据点,矩阵的列代表数据…...

直播平台源码开发搭建APP的DASH协议:流媒体技术其中一环
在直播平台源码APP中,有着许许多多、多种多样的功能,比如短视频功能,帮助我们去获取信息,看到全世界用户身边发生的事情或是他们的生活;又比如直播功能,为用户提供了实时的娱乐享受,还让一些用户…...
【前端】js解码base64
【前端】js解码base64 //不会乱码 function strTob(base64) {// 对base64转编码var decode atob(base64)decode escape(decode)// 编码转字符串var str decodeURIComponent(decode)return str } atob 中文乱码的解决方案 decode escape(decode) // 编码转字符串 v…...

Apipost:API开发者的协同工作神器
在当今快速发展的数字化时代,API已成为企业与开发者实现数据互通、应用集成的重要桥梁。然而,随着API数量的不断增加,API开发、调试、测试、文档等工作也变得越来越复杂。为了解决这一痛点,一款名为Apipost的API协同研发工具应运而…...

照片动起来软件有哪些?试试这几个
照片动起来软件有哪些?将照片动起来可以让照片更加生动有趣,让人们更容易吸引到你的照片。在社交媒体和短视频的时代,人们需要更多的方式来吸引别人的注意力。让照片动起来可以让你的照片变得更加生动、更加有趣,让人们更容易停留…...

地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...

stm32wle5 lpuart DMA数据不接收
配置波特率9600时,需要使用外部低速晶振...