Java实现链表

链表

  • 前言
  • 一、链表的概念及结构
  • 二、链表的分类
  • 三、链表的实现
    • 无头单向非循环链表实现
    • 无头双向链表实现
    • 具体代码
  • 四、链表习题
  • 五、顺序表和链表的区别


前言

推荐一个网站给想要了解或者学习人工智能知识的读者,这个网站里内容讲解通俗易懂且风趣幽默,对我帮助很大。我想与大家分享这个宝藏网站,请点击下方链接查看。
https://www.captainbed.cn/f1

链表是一种常见的数据结构,由一系列节点组成,每个节点包含数据和指向下一个节点的指针。链表的一个显著特点是,它不需要在内存中连续存储,因此可以高效地插入和删除节点。这种灵活性使得链表在许多应用中成为理想的选择,尤其是在需要动态调整数据结构大小的场景中。

在链表的实现中,通常会有头节点和尾节点之分。头节点是链表的第一个节点,而尾节点是链表的最后一个节点。通过遍历链表,我们可以访问链表中存储的所有数据。链表还支持在链表头部或尾部快速添加新节点,这些操作的时间复杂度通常为O(1)。

然而,链表也有一些缺点。比如,访问链表中的某个特定节点需要从头节点开始遍历,这导致访问链表中间节点的平均时间复杂度为O(n)。此外,链表需要额外的空间来存储指针,这增加了内存的使用。

链表有多种类型,如单向链表、双向链表和循环链表等。单向链表是最简单的链表类型,每个节点只有一个指向下一个节点的指针。双向链表则允许节点同时指向前一个和下一个节点,这使得双向链表在某些操作上比单向链表更高效。循环链表则是将尾节点的指针指向头节点,形成一个闭环。

在实际应用中,链表常用于实现栈、队列和哈希表等数据结构。例如,链表可以作为栈的底层数据结构,实现元素的先进后出。此外,链表还可以用于实现动态数组,支持元素的动态插入和删除。

总之,链表作为一种重要的数据结构,在编程和数据处理中发挥着重要作用。尽管链表在某些方面存在不足,但其灵活性和高效性使得它在许多场景中仍然是理想的选择。通过深入了解链表的特性和应用,我们可以更好地利用这种数据结构来解决实际问题。


一、链表的概念及结构

链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。

概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
现实中 数据结构中
在这里插入图片描述

二、链表的分类

实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:

  1. 单向或者双向
    在这里插入图片描述
  2. 带头或者不带头
    在这里插入图片描述
  3. 循环或者非循环
    在这里插入图片描述

虽然有这么多的链表的结构,但是我们实际中最常用还是两种结构:
在这里插入图片描述

  1. 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
  2. 带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了,后面我们代码实现了就知道了。

三、链表的实现

无头单向非循环链表实现

// 1、无头单向非循环链表实现
public class SingleLinkedList {
 //头插法
public void addFirst(int data);
 //尾插法
public void addLast(int data);
 //任意位置插入,第一个数据节点为0号下标
public boolean addIndex(int index,int data);
 //查找是否包含关键字key是否在单链表当中
public boolean contains(int key);
 //删除第一次出现关键字为key的节点
public void remove(int key);
 //删除所有值为key的节点
public void removeAllKey(int key);
 //得到单链表的长度
public int size();
 public void display();
 public void clear();
 }

无头双向链表实现

// 2、无头双向链表实现
public class DoubleLinkedList {
 //头插法
public void addFirst(int data);
 //尾插法
public void addLast(int data);
 //任意位置插入,第一个数据节点为0号下标
public boolean addIndex(int index,int data);
 //查找是否包含关键字key是否在单链表当中
public boolean contains(int key);
 //删除第一次出现关键字为key的节点
public void remove(int key);
 //删除所有值为key的节点
public void removeAllKey(int key);
 //得到单链表的长度
public int size();
 public void display();
 public void clear();
 }

具体代码

// 2、使用无头单向非循环链表实现
public class SingleLinkedList {
    private Node head; // 头节点

    // 节点类
    private class Node {
        private int data; // 数据
        private Node next; // 下一个节点

        public Node(int data) {
            this.data = data;
        }
    }

    // 头插法
    public void addFirst(int data) {
        Node newNode = new Node(data);
        if (head == null) {
            head = newNode;
        } else {
            newNode.next = head;
            head = newNode;
        }
    }

    // 尾插法
    public void addLast(int data) {
        Node newNode = new Node(data);
        if (head == null) {
            head = newNode;
        } else {
            Node cur = head;
            while (cur.next != null) {
                cur = cur.next;
            }
            cur.next = newNode;
        }
    }

    // 任意位置插入
    public boolean addIndex(int index, int data) {
        if (index < 0 || index > size()) {
            return false;
        }
        if (index == 0) {
            addFirst(data);
            return true;
        }
        if (index == size()) {
            addLast(data);
            return true;
        }
        Node newNode = new Node(data);
        Node cur = findNode(index - 1);
        newNode.next = cur.next;
        cur.next = newNode;
        return true;
    }

    // 查找是否包含关键字
    public boolean contains(int key) {
        Node cur = head;
        while (cur != null) {
            if (cur.data == key) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

    // 删除第一个出现的关键字节点
    public void remove(int key) {
        if (head == null) {
            return;
        }
        if (head.data == key) {
            head = head.next;
            return;
        }
        Node cur = head;
        while (cur.next != null && cur.next.data != key) {
            cur = cur.next;
        }
        if (cur.next != null) {
            cur.next = cur.next.next;
        }
    }

    // 删除所有值为关键字的节点
    public void removeAllKey(int key) {
        if (head == null) {
            return;
        }
        // 处理头节点的情况
        while (head != null && head.data == key) {
            head = head.next;
        }
        // 处理其他节点的情况
        Node cur = head;
        while (cur != null && cur.next != null) {
            if (cur.next.data == key) {
                cur.next = cur.next.next;
            } else {
                cur = cur.next;
            }
        }
    }

    // 获取链表长度
    public int size() {
        int count = 0;
        Node cur = head;
        while (cur != null) {
            count++;
            cur = cur.next;
        }
        return count;
    }

    // 查找指定位置的节点
    private Node findNode(int index) {
        Node cur = head;
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }
        return cur;
    }

    // 打印链表
    public void display() {
        Node cur = head;
        while (cur != null) {
            System.out.print(cur.data + " ");
            cur = cur.next;
        }
        System.out.println();
    }

    // 清空链表
    public void clear() {
        head = null;
    }
}

四、链表习题

  1. 删除链表中等于给定值 val 的所有结点
  2. 反转一个单链表
  3. 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点
  4. 输入一个链表,输出该链表中倒数第k个结点
  5. 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有结点组成的
  6. 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前
  7. 链表的回文结构
  8. 输入两个链表,找出它们的第一个公共结点
    在这里插入图片描述
  9. 给定一个链表,判断链表中是否有环
    【思路】
    快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表其实位置开始运行,如果链表带环则一定会在环中相遇,否则快指针率先走到链表的末尾。比如:陪女朋友到操作跑步减肥。

【扩展问题】

  • 为什么快指针每次走两步,慢指针走一步可以?
    假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。当慢指针刚进环时,可能就和快指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。
    此时,两个指针每移动一次,之间的距离就缩小一步,不会出现每次刚好是套圈的情况,因此:在满指针走到一圈之前,快指针肯定是可以追上慢指针的,即相遇。

  • 快指针一次走3步,走4步,…n步行吗?
    在这里插入图片描述

  1. 给定一个链表,返回链表开始入环的第一个结点。 如果链表无环,则返回 NULL

解决像这样的题目,我们可以找等式,通过等式来找出相应的关系

  • 结论
    让一个指针从链表起始位置开始遍历链表,同时让一个指针从判环时相遇点的位置开始绕环运行,两个指针都是每次均走一步,最终肯定会在入口点的位置相遇。
  • 证明
    在这里插入图片描述
  1. 给定一个链表,每个结点包含一个额外增加的随机指针,该指针可以指向链表中的任何结点或空结点。
    要求返回这个链表的深度拷贝
  2. 其他 。ps:链表的题当前因为难度及知识面等等原因还不适合我们当前学习,大家可以先把c++学一下,在逐步开始刷题 Leetcode + 牛客

五、顺序表和链表的区别

不同点顺序表链表
存储空间上物理上一定连续逻辑上连续,但物理上不一定连续
随机访问支持O(1)不支持:O(N)
任意位置插入或者删除元素可能需要搬移元素,效率低O(N)只需修改指针指向
插入动态顺序表,空间不够时需要扩容没有容量的概念
应用场景元素高效存储+频繁访问任意位置插入和删除频繁
缓存利用率

备注:缓存利用率参考存储体系结构 以及 局部原理性。

在这里插入图片描述
在这里插入图片描述

与程序员相关的CPU缓存知识

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

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

相关文章

Autodesk Flame 2025 for Mac:视觉特效制作的终极利器

在数字时代&#xff0c;视觉特效已经成为电影、电视制作中不可或缺的一部分。Autodesk Flame 2025 for Mac&#xff0c;这款专为视觉特效师打造的终极工具&#xff0c;将为您的创作提供无尽的可能。 Autodesk Flame 2025 for Mac拥有强大的三维合成环境&#xff0c;能够支持您…

05.配置tomcat管理功能

认证失败&#xff0c;需要配置tomcat-users.xml文件 配置用户信息 [rootweb01 /application/tomcat/conf\]# tail tomcat-users.xml <role rolename"admin-gui"/> <role rolename"host-gui"/><role rolename"mana…

数学建模--LaTeX的基本使用

目录 1.回顾 2.设置这个页眉和页脚 3.对于字体的相关设置 4.对于这个分级标题的设置 5.列表的使用 6.插入图片 1.回顾 &#xff08;1&#xff09;昨天我们了解到了这个latex的使用基本常识&#xff0c;以及这个宏包的概念&#xff0c;区域的划分&#xff0c;不同的代码代…

PCL 法向量加权的RANSAC拟合分割平面

目录 一、算法原理1、原理概述2、主要函数二、代码实现三、结果展示四、相关链接本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 1、原理概述

树与二叉树的概念介绍

一.树的概念及结构&#xff1a; 1.树的概念&#xff1a; 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的 有…

IDEA 上方添加左右箭头按钮

IDEA 版本&#xff1a;2021.3.3 按钮&#xff1a; 左箭头&#xff08;Back&#xff09;&#xff08;快捷键&#xff1a;Ctrl Alt 左箭头&#xff09; 右箭头&#xff08;Forward&#xff09;&#xff08;快捷键&#xff1a;Ctrl Alt 右箭头&#xff09; 日常写代码中经常…

Java与GO语言对比分析

你是不是总听到go与java种种对比&#xff0c;其中在高并发的服务器端应用场景会有人推荐你使用go而不是 java。 那我们就从两者运行原理和基本并发设计来对比分析&#xff0c;看看到底怎么回事。 运行原理对比 java java 中 jdk 已经帮我们屏蔽操作系统区别。 只要我们下载并…

开源金融AI代理平台FinRobot;支持多翻译引擎和模式的高效浏览器翻译开源插件;使用自然语言控制生成视频的通用世界模型

✨ 1: finrobot FinRobot 是一个基于大语言模型的开源金融AI代理平台&#xff0c;适用于多种金融应用。 FinRobot是一个综合性的AI代理平台&#xff0c;超越了原有的FinGPT&#xff0c;旨在满足金融行业的多元化需求。它集成了各种AI技术&#xff0c;不仅仅局限于语言模型&am…

APM2.8飞控

ArduPilotMega 主控可应用于 固定翼、直升机、多旋翼、地面车辆 APM2.8飞控供电有两种 1.电流计供电&#xff0c; 2.带BEC&#xff08;稳压功能&#xff09;的电调供电 ArduPilotMega 内部的硬件结构图&#xff1a; 调试时&#xff0c;不要使用向导&#xff0c;由于向导功能不…

【JUC编程】-多线程和CompletableFuture的使用

多线程编程 文章目录 多线程编程[toc]引言创建多线程的方式继承Thread类实现Runnable接口实现Callable接口Callable和Runnable的区别 Lambda表达式 线程的实现原理Future&FutureTask具体使用submit方法Future到FutureTask类Future注意事项局限性 CompletionService引言使用…

【蓝桥杯——物联网设计与开发】拓展模块2 - 电位器模块

一、电位器模块 &#xff08;1&#xff09;资源介绍 &#x1f505;原理图 蓝桥杯物联网竞赛实训平台提供了一个拓展接口 CN2&#xff0c;所有拓展模块均可直接安装在 Lora 终端上使用&#xff1b; 图1 拓展接口 电位器模块电路原理图如下所示&#xff1a; 图2 …

通用代码生成器应用场景三,遗留项目反向工程

通用代码生成器应用场景三&#xff0c;遗留项目反向工程 如果您有一个遗留项目&#xff0c;要重新开发&#xff0c;或者源代码遗失&#xff0c;或者需要重新开发&#xff0c;但是希望复用原来的数据&#xff0c;并加快开发。 如果您的项目是通用代码生成器生成的&#xff0c;…

无线蓝牙耳机品牌推荐:倍思M2s Pro,让旅途更添乐趣

随着端午节的临近,许多人开始规划起出游计划。出游除了要做好行程安排,还需准备一些实用的物品来提升旅途的舒适度。特别是在高铁等长途旅行中,一款优质的降噪蓝牙耳机无疑是消磨时光、享受音乐的绝佳选择。那么,在众多的无线蓝牙耳机品牌中,有哪些值得推荐的呢?今天,我们就来…

IT廉连看——UniApp——事件绑定

IT廉连看——UniApp——事件绑定 这是我们上节课最终的样式&#xff1b; 一、现在我有这样一个需求&#xff0c;当我点击“生在国旗下&#xff0c;长在春风里”它的颜色由红色变为蓝色&#xff0c;该怎么操作&#xff1f; 这时候我们需要一个事件的绑定&#xff0c;绑定一个单…

指纹识别经典图书、开源算法库、开源数据库

目录 1. 指纹识别书籍 1.1《精通Visual C指纹模式识别系统算法及实现》 1.2《Handbook of Fingerprint Recognition》 2. 指纹识别开源算法库 2.1 Hands on Fingerprint Recognition with OpenCV and Python 2.2 NIST Biometric Image Software (NBIS) 3. 指纹识别开源数…

react-native 默认停用 flipper 通知

react-native 0.74 默认停用 flipper &#xff0c;但仍然可以手动安装 flipper 官方声明文档 英语好的可以直接阅读。 integration with React Native will no longer be enabled 原因 增加编译时间有时候会有连接问题升级会导致不能使用 之后调试推荐 我们建议团队使用 A…

谷粒商城实战(029 业务-订单支付模块-支付宝支付2)

Java项目《谷粒商城》架构师级Java项目实战&#xff0c;对标阿里P6-P7&#xff0c;全网最强 总时长 104:45:00 共408P 此文章包含第305p-第p310的内容 代码编写 前端代码 这里使用的是jsp 在这里引用之前配置的各种支付信息 在AlipayConfig.java里 这里是调用阿里巴巴写…

单片机的内存映射和重映射

内存映射 在单片机内&#xff0c;不管是RAM还是ROM还是寄存器&#xff0c;他们都是真实存在的物理存储器&#xff0c;为了方便操作&#xff0c;单片机会给每一个存储单元分配地址&#xff0c;这就叫做内存映射。 单片机的内存映射是指将外部设备或外部存储器映射到单片…

​测斜仪数据处理软件-MCU自动测量单元的重要性及应用

随着科技的快速发展&#xff0c;测斜仪数据处理软件在多个领域&#xff0c;如土木工程、地质学、环境科学等&#xff0c;扮演着越来越重要的角色。本文旨在探讨测斜仪数据处理软件-MCU自动测量单元的重要性、应用及其发展趋势。 一、MCU自动测量单元处理测斜仪数据的重要性 测斜…

快速上手 HuggingFace

HuggingFace HuggingFace 是类似于 GitHub 的社区&#xff0c;它主要提供各种的模型的使用&#xff0c;和 github 不同的是&#xff0c;HuggingFace 同时提供了一套框架&#xff0c;进行模型推理&#xff0c;模型训练、和模型库文件的管理等等。本文将介绍&#xff0c;如何快速…