Java玩转《啊哈算法》之模拟链表

人应该支配习惯,而绝不是让习惯支配人。一个人要是不能改掉坏习惯,那么他就一文不值。

目录

  • 代码地址
  • 模拟链表
    • 创建
    • 遍历打印
    • 插入
    • 插入优化
  • 完整代码

各位小伙伴们好呀!本人最近看了下《啊哈算法》,写的确实不错。

但稍显遗憾的是,书籍示例代码是c语言,而不是本人常用的Java。

那就弥补遗憾,说干就干,把这本书的示例语言用java写一遍, 顺带附上一些自己的理解!

今天这篇博客讲的是如何用数组来模拟链表。
在这里插入图片描述

来不及买纸质书但又想尽快感受算法魅力的童鞋也甭担心,电子版的下载链接已经放到下方了,可尽情下载。

链接:https://pan.baidu.com/s/1imxiElcCorw2F-HJEnB-PA?pwd=jmgs
提取码:jmgs

代码地址

本文代码已开源:

git clone https://gitee.com/guqueyue/my-blog-demo.git

请切换到gitee分支,

然后查看aHaAlgorithm模块下的src/main/java/com/guqueyue/aHaAlgorithm/chapter_2_StackAndChainTable即可!

模拟链表

在往期的博客中,我们用数组模拟了队列、栈,并且说了用链表也可以模拟队列、栈。

于是乎,我们还介绍了链表,但是链表指来指去的难免让人奇奇怪怪、晕头转向。

  1. Java玩转《啊哈算法》解密QQ号之队列
  2. Java玩转《啊哈算法》解密回文之栈
  3. Java玩转《啊哈算法》之链表

那么,这期博客,我们来讲一下如何用数组来模拟链表。

数组可以模拟队列、栈,链表也可以模拟队列、栈,数组也能模拟链表?没想到吧。

创建

那么,要怎么用数组来模拟链表呢?我们需要准备两个数组,一个数组存元素,一个数组用来存元素对应的下一个元素的位置
在这里插入图片描述
如上图所示,我们data数组用于存放元素内容,right数组用以存放相同索引处对应data数组的下一个元素的索引。

如图我们头节点的元素为data[1]也就是2,下一个元素为data[right[1]]也就是3。

当然,我们这里可以做一些小小的改动:

  1. 为了不浪费空间,我们的存放数组的索引从0开始而不是从1开始。
  2. 链表尾节点的下一个位置的索引,我们用-1表示,而不是0。

首先,我们声明一下需要使用的两个数组、链表的长度以便于录入数据以及控制台输入的对象:

   // 用于控制台输入private static Scanner scanner = new Scanner(System.in);private static int[] data = new int[101]; // 元素数组private static int[] right = new int[101]; // 索引数组private static int n = 0; // 链表长度

然后,我们就可以愉快的编写创建链表的方法了:

   /*** @Description 创建链表* @return void**/private static void createChainTable() {System.out.print("请输入数字个数: ");n = scanner.nextInt();System.out.printf("请输入%d个数,中间用空格隔开,输入完回车: ", n);for (int i = 0; i < n; i++) {data[i] = scanner.nextInt();}// 初始化right数组for (int i = 0; i < n; i++) {right[i] = i == n-1 ? -1 : i+1;}}

遍历打印

有了创建链表的方法,当然要有一个打印的方法,不然怎么验证:

  /*** @Description 打印链表* @return void**/private static void printChainTable() {// 输出int t = 0;System.out.print("链表为:" + data[t]);while(right[t] != -1) {t = right[t]; // 获取下一个元素的索引System.out.print("->" + data[t]);}System.out.println();}

ok了,下面让我们来验证一下:

package com.guqueyue.aHaAlgorithm.chapter_2_StackAndChainTable;import java.util.Scanner;/*** @Author: guqueyue* @Description: 用数组模拟链表* @Date: 2024/1/15**/
public class ChainTableTest2 {// 用于控制台输入private static Scanner scanner = new Scanner(System.in);private static int[] data = new int[101]; // 元素数组private static int[] right = new int[101]; // 索引数组private static int n = 0; // 链表长度public static void main(String[] args) {// 创建链表createChainTable();// 打印链表printChainTable();}/*** @Description 打印链表* @return void**/private static void printChainTable() {// 输出int t = 0;System.out.print("链表为:" + data[t]);while(right[t] != -1) {t = right[t]; // 获取下一个元素的索引System.out.print("->" + data[t]);}System.out.println();}/*** @Description 创建链表* @return void**/private static void createChainTable() {System.out.print("请输入数字个数: ");n = scanner.nextInt();System.out.printf("请输入%d个数,中间用空格隔开,输入完回车: ", n);for (int i = 0; i < n; i++) {data[i] = scanner.nextInt();}// 初始化right数组for (int i = 0; i < n; i++) {right[i] = i == n-1 ? -1 : i+1;}}
}

运行代码,控制台输入,可得:
在这里插入图片描述

插入

在这里插入图片描述

同样的,按照书上的逻辑,我们来写一个往链表中插入元素的方法:

   /*** @Description 插入链表* @return void**/private static void insertChainTable() {// 插入一个数int len = n;System.out.print("请输入插入的数:");data[len] = scanner.nextInt();// 按照链表顺序遍历 data 数组,找到比 num 大的数int t = 0;while (t != -1) {if (data[right[t]] > data[len]) { // 如果当前节点的下一个节点大于插入数,则插入right[len] = right[t]; // 插入的节点 指向当前节点的下一个节点right[t] = len; // 当前节点 指向插入的节点break;}t = right[t];}}

我们来验证一下(完整代码已开源,在本博客最后也可查看):

   public static void main(String[] args) {// 创建链表createChainTable();// 打印链表printChainTable();// 往链表中插入数据insertChainTable();// 打印链表printChainTable();}

运行,得:

在这里插入图片描述
看起来好像没啥问题,但是同上期博客一样,存在着两个问题:

  1. 如果插入的节点值大小小于头节点,该节点会被插入到头节点后面,违背了从小到大的顺序。
  2. 如果插入的节点值大于等于尾结点,则该节点不会被插入,甚至于直接报错!

如:
在这里插入图片描述
又比如:

在这里插入图片描述

插入优化

因此,我们来把插入方法优化一下,增加插入头节点和尾节点的逻辑:

	/*** @Description 按照从小到大的顺序插入链表* @return void**/private static void insertChainTable2() {// 插入一个数int len = n;System.out.print("请输入插入的数:");data[len] = scanner.nextInt();// 如果新插入的节点比 头节点 小,则插入到链表头部if (data[len] < data[0]) {// 头节点和尾节点互换int temp = data[0]; data[0] = data[len]; data[len] = temp;right[len] = right[0]; // 保持旧头节点原有的连接关系不变right[0] = len; // 将新的头节点指向旧的节点}else {// 按照链表顺序遍历 data 数组,找到比 num 大的数int t = 0;while (right[t] != -1) {if (data[right[t]] > data[len]) { // 如果当前节点的下一个节点大于插入数,则插入right[len] = right[t]; // 插入的节点 指向当前节点的下一个节点right[t] = len; // 当前节点 指向插入的节点break;}t = right[t];}// 插入的数如果比链表的最后一个节点大,则插入到链表尾部if (right[t] == -1) {right[n-1] = len;right[len] = -1;}}}

改动代码,来验证一下吧:

public static void main(String[] args) {// 创建链表createChainTable();// 打印链表printChainTable();// 往链表中插入数据
//        insertChainTable();insertChainTable2();// 打印链表printChainTable();
}

运行代码,分别验证,插入中间节点:

在这里插入图片描述
头节点:
在这里插入图片描述
尾节点:
在这里插入图片描述
很是完美!!!

完整代码

package com.guqueyue.aHaAlgorithm.chapter_2_StackAndChainTable;import java.util.Scanner;/*** @Author: guqueyue* @Description: 用数组模拟链表* @Date: 2024/1/15**/
public class ChainTableTest2 {// 用于控制台输入private static Scanner scanner = new Scanner(System.in);private static int[] data = new int[101]; // 元素数组private static int[] right = new int[101]; // 索引数组private static int n = 0; // 链表长度public static void main(String[] args) {// 创建链表createChainTable();// 打印链表printChainTable();// 往链表中插入数据
//        insertChainTable();insertChainTable2();// 打印链表printChainTable();}/*** @Description 打印链表* @return void**/private static void printChainTable() {// 输出int t = 0;System.out.print("链表为:" + data[t]);while(right[t] != -1) {t = right[t]; // 获取下一个元素的索引System.out.print("->" + data[t]);}System.out.println();}/*** @Description 插入链表* @return void**/private static void insertChainTable() {// 插入一个数int len = n;System.out.print("请输入插入的数:");data[len] = scanner.nextInt();// 按照链表顺序遍历 data 数组,找到比 num 大的数int t = 0;while (t != -1) {if (data[right[t]] > data[len]) { // 如果当前节点的下一个节点大于插入数,则插入right[len] = right[t]; // 插入的节点 指向当前节点的下一个节点right[t] = len; // 当前节点 指向插入的节点break;}t = right[t];}}/*** @Description 按照从小到大的顺序插入链表* @return void**/private static void insertChainTable2() {// 插入一个数int len = n;System.out.print("请输入插入的数:");data[len] = scanner.nextInt();// 如果新插入的节点比 头节点 小,则插入到链表头部if (data[len] < data[0]) {// 头节点和尾节点互换int temp = data[0]; data[0] = data[len]; data[len] = temp;right[len] = right[0]; // 保持旧头节点原有的连接关系不变right[0] = len; // 将新的头节点指向旧的节点}else {// 按照链表顺序遍历 data 数组,找到比 num 大的数int t = 0;while (right[t] != -1) {if (data[right[t]] > data[len]) { // 如果当前节点的下一个节点大于插入数,则插入right[len] = right[t]; // 插入的节点 指向当前节点的下一个节点right[t] = len; // 当前节点 指向插入的节点break;}t = right[t];}// 插入的数如果比链表的最后一个节点大,则插入到链表尾部if (right[t] == -1) {right[n-1] = len;right[len] = -1;}}}/*** @Description 创建链表* @return void**/private static void createChainTable() {System.out.print("请输入数字个数: ");n = scanner.nextInt();System.out.printf("请输入%d个数,中间用空格隔开,输入完回车: ", n);for (int i = 0; i < n; i++) {data[i] = scanner.nextInt();}// 初始化right数组for (int i = 0; i < n; i++) {right[i] = i == n-1 ? -1 : i+1;}}
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#,K-均值(K-Means)聚类算法的核心源代码

一、詹姆斯麦昆&#xff08;James MacQueen&#xff09; IMS研究员詹姆斯B麦昆于2014年7月15日病逝&#xff0c;享年85岁。他的妻子安和他们的三个孩子唐纳德、凯特和玛丽以及五个孙子孙女幸存下来。 从1962年到去世&#xff0c;麦昆教授一直在加州大学洛杉矶分校管理研究生院…

软考 系统分析师系列知识点之需求获取(7)

所属章节&#xff1a; 第11章. 软件需求工程 第2节. 需求获取 需求获取是一个确定和理解不同的项目干系人的需求和约束的过程。需求获取是一件看上去很简单、做起来却很难的事情。需求获取是否科学、准备是否充分&#xff0c;对获取出来的结果影响很大&#xff0c;这是因为大部…

图书推荐||Word文稿之美

让你的文档从平凡到出众&#xff01; 本书内容 《Word文稿之美》是一本全面介绍Word排版技巧和应用的实用指南。从初步认识数字排版到高效利用模板、图文配置和表格与图表的排版技巧&#xff0c;再到快速修正错误和保护文件&#xff0c;全面系统地讲解数字排版的技术和能力&…

[剪藏] - 瑞萨收购Altium!

2024年2月15日消息&#xff0c;瑞萨电子公司近日表示计划以每股68.50澳元&#xff0c;总额 91 亿澳元&#xff08;约合 59 亿美元&#xff09;收购 PCB 设计软件公司 Altium的所有流通股&#xff08;企业价值为88亿澳元&#xff09;&#xff0c;此举不禁让人联想到西门子 2017 …

鼠标失灵怎么办?电脑出现鼠标失灵的详细处理方法介绍

无论是笔记本电脑还是台式机电脑&#xff0c;鼠标是必不可少的外设之一&#xff0c;而我们在使用电脑的过程中&#xff0c;经常回遇到鼠标突然失灵了&#xff0c;不听使唤&#xff0c;控制不了&#xff0c;接下小编来与大家一起分享&#xff0c;遇到这种情况我们该怎么办 有时…

YOLO v9训练自己数据集

原以为RT-DETR可以真的干翻YOLO家族&#xff0c;结果&#xff0c;&#xff01;&#xff01;&#xff01;&#xff01; 究竟能否让卷积神经网络重获新生&#xff1f; 1.数据准备 代码地址&#xff1a;https://github.com/WongKinYiu/yolov9 不能科学上网的评论区留言 数据集…

社交APP开发能给用户带来什么

现在的社交软件也非常的多&#xff0c;每款社交软件都有自己的特色&#xff0c;社交软件是日常中必备的软件&#xff0c;不管是生活交流还是感情工作交流都是比较方便的&#xff0c;因为社交软件满足了日常的远程交流问题&#xff0c;所以开发社交软件也会逐渐的流行起来的。 …

Cloud整合Zookeeper代替Eureka

微服务间通信重构与服务治理笔记-CSDN博客 Zookeeper是一个分布式协调工具,可以实现注册中心功能 安装Zookeeper 随便 就用最新版本吧 进入Zookeeper 包目录 cd /usr/local/develop/ 解压 tar -zxvf apache-zookeeper-3.9.1-bin.tar.gz -C /usr/local/develop 进入配置文件…

USB4之ASM2464PD与ASM2464PDX兼容与运用

首先在NVMe上运用: 一&#xff1a;ASM2464PD&#xff08;现在可以做带PD的方案&#xff09; 二&#xff1a;ASM2464PDX 1&#xff1a; Application Guide- CFX card reader NVMe SSD 2&#xff1a;ASM2464PDX Application Guide- NVMe SSD x4 with data clone 三&#xff…

摄像头工程师说 Camera - 颜色空间 YUV 与 YCbCr 的区别与联系(4)

摄像头工程师说 Camera - 数据格式 YUV 与 YCbCr 的区别与联系&#xff08;4&#xff09; 概述 上回书咱们说到 摄像头工程师说 Camera - 数据格式 YUV 格式的存储&#xff08;3&#xff09; 本节咱们说说YUV 与 YCbCr 两种色彩空间定义的联系与区别。 相同点&#xff1a; Y…

嵌入式驱动学习第一周——linux的休眠与唤醒

前言 本文介绍进程的休眠与唤醒。 嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程&#xff0c;未来预计四个月将高强度更新本专栏&#xff0c;喜欢的可以关注本博主并订阅本专栏&#xff0c;一起讨论一起学习。现在关注就是老粉啦&#xff01; 行文目录 前言1. 阻塞和非阻…

PCL中的3D特征

PCL中的3D特征 PCL中的3D特征理论入门如何传递输入法线估计例子 PCL中的3D特征 理论入门 来自[RusuDissertation]&#xff1a; 在他们原生表示中&#xff0c; 点 如 3D 映射系统概念中定义的那样&#xff0c;使用它们的笛卡尔坐标 x、y、z 相对于给定原点简单地表示。假设坐标…