《Java初阶数据结构》----3.<线性表---LinkedList与链表>

news2024/11/24 20:27:27

目录

前言

一、链表的简介

1.1链表的概念

1.2链表的八种结构 

重点掌握两种

1.3单链表的常见方法

三、单链表的模拟实现

四、LinkedList的模拟实现(双链表)

4.1 什么是LinkedList

4.2LinkedList的使用

五、ArrayList和LinkedList的区别 


前言

      大家好,我目前在学习java。之前也学了一段时间,但是没有发布博客。时间过的真的很快。我会利用好这个暑假,来复习之前学过的内容,并整理好之前写过的博客进行发布。如果博客中有错误或者没有读懂的地方。热烈欢迎大家在评论区进行讨论!!!

      喜欢我文章的兄弟姐妹们可以点赞,收藏和评论我的文章。喜欢我的兄弟姐妹们以及也想复习一遍java知识的兄弟姐妹们可以关注我呦,我会持续更新滴,
     望支持!!!!!!一起加油呀!!!!

语言只是工具,不能决定你好不好找工作,决定你好不好找工作的是你的能力!!!!!

学历本科及以上就够用了!!!!!!!!!!!!!!!!!!


本篇博客主要讲解Java基础语法中的

一、链表的简介

1.1链表的概念

1.2链表的八种结构

重点掌握两种结构:

1.3单链表的常见方法

三、单链表的模拟实现

四、LinkedList的模拟实现(双链表)

4.1 什么是LinkedList

4.2LinkedList的使用(及实现)

五、ArrayList和LinkedList的区别

一、链表的简介

1.1链表的概念

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

1.2链表的八种结构 

下面三种情况组合起来就有八种2^3。

1. 单向或者双向 

2.带头或者不带头

3. 循环或者非循环

重点掌握两种

1.无头单向非循环链表(单链表):结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。

2.无头双向链表(双链表):在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。

1.3单链表的常见方法

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

三、单链表的模拟实现

用内部类的方式定义链表节点。

    //链表是由每一个节点组成的,每一个节点都是一个对象,
//  如果我们去抽象他,它有两个域,节点是链表的一部分,所以我们把节点定义成内部类
    static class ListNode{
        public int val;//节点的值域,整型
        public ListNode next;//下一个节点的地址,要表示节点的地址,因此是ListNode类型

        //由于new新的节点对象时,值可以知道,但是下一个节点的地址是未知的
        //因此我们创建构造方法时,只初始化val的值,next的值默认为null。
        public ListNode(int val) {
            this.val = val;
        }
    }

 再定义一个头结点

    //对于链表本身,还应该有个head,来表示当前链表的头结点,这是我们链表的头结点
    //而不是节点的头结点。因此是链表的属性,切勿放到节点类之中。节点类只有两个属性,值域和下一个节点的地址域
    //要表示节点的地址,因此是ListNode类型
    public ListNode head;

简单的初始化链表 

    public void easyCreateList(){
        ListNode node1 = new ListNode(12);
        ListNode node2 = new ListNode(23);
        ListNode node3 = new ListNode(34);
        ListNode node4 = new ListNode(45);
        ListNode node5 = new ListNode(56);

        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        node4.next = node5;
        this.head = node1;
    }

遍历打印链表 

    //注意:head必须一直指向第一个节点的位置,从而来找到这个链表
    //因此我们定义一个ListNode类型的cur。
    public void display(){
        ListNode cur = head;
        if (cur == null){
            System.out.print("当前链表为空,无法打印");
        }
        while (cur != null){
            System.out.printf(cur.val+" ");
            cur = cur.next;
        }
        System.out.println();
    }

从某节点开始打印链表 

    public void display(ListNode listNode){
        ListNode cur = listNode;
        if (cur == null){
            System.out.print("当前链表为空,无法打印");
        }
        while (cur != null){
            System.out.printf(cur.val+" ");
            cur = cur.next;
        }
        System.out.println();
    }

 求链表的长度

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

 是否链表是否包含关键字key

    //是否链表是否包含关键字key
    public boolean contains(int key){
        ListNode cur = head;
        while (cur != null){
            if(key == cur.val){
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

头插法 

    //头插法,就算链表里一个节点都没有,此方法也可以插入新的节点
    //因此创建链表可以用此方法创建
    public void addFirst(int data){
        ListNode node = new ListNode(data);
        node.next = head;
        head = node;
    }

尾插法

    //尾插法,在链表最后面插入元素
    public void addLast(int data){
        ListNode node = new ListNode(data);
        ListNode cur = head;
        if (cur == null){
            head = node;
            return;
        }
        //找到链表的尾节点
        while (cur.next != null){
            cur = cur.next;
        }
        cur.next = node;
    }

在指定位置插入元素

    //在指定位置插入元素
    public void addIndex(int index, int data){
        if(index < 0|| index > size()){
            System.out.println("index不合法");
            return;
        }
        if(index == 0){
            addFirst(data);
            return;
        }
        if(index == size()){
            addLast(data);
            return;
        }
//        ListNode node = new ListNode(data);
//        ListNode pre = head;
//        int count = 0;
//        while (true){
//            pre = pre.next;
//            count++;
//            if (index == count+1){
//                node.next = pre.next;
//                pre.next = node;
//                break;
//            }
//        }
        ListNode cur = findIndexSubOne(index);
        ListNode node = new ListNode(data);
        node.next = cur.next;
        cur.next = node;
    }

 找到要删除节点的位置的前一个节点

    //找到要删除节点的位置的前一个节点
    private ListNode findIndexSubOne(int index){
        ListNode cur = head;
        for (int i = 0; i<index-1; i++){
            cur = cur.next;
        }
        return cur;

//        while (index-1 != 0){
//            cur = cur.next;
//            index--;
//        }
//        return cur;
    }

 删除第一次出现关键字为key的节点

    //删除第一次出现关键字为key的节点
    public void remove(int key){
        if(head == null){
            System.out.println("当前链表为空,您要删除的数据不存在");
            return;
        }
        if (head.val == key){
            head = head.next;
            return;
        }
        ListNode cur = searchPrev(key);
        if (cur == null){
            System.out.println("没有找到你要删除的数字");
            return;
        }
        cur.next = cur.next.next;
    }

找到key的前驱

    //找到key的前驱
    private ListNode searchPrev(int key){
        ListNode cur = head;
        while (cur.next!=null){
            if (cur.next.val == key){
                return cur;
            }
            cur = cur.next;
        }
        return null;
    }

 删除链表中元素

    public void removeAllKey(int key){
        if(head == null){
            System.out.println("当前链表为空,无法删除!");
            return;
        }
        ListNode cur = head.next;
        ListNode prev = head;
        while (cur != null){
            if(cur.val == key){
                prev.next = cur.next;
                cur = cur.next;
            }else {
                cur = cur.next;
                prev = prev.next;
            }
        }
        if (head.val == key){
            head = head.next;
        }
    }

逆置链表 

    public ListNode reverseList(ListNode head){
        if(head == null){
            return null;
        }
        if(head.next == null){
            return head;
        }

        ListNode cur = head.next;
        head.next = null;
        while (cur != null){
            ListNode curNext = cur.next;
            cur.next = head;
            head = cur;
            cur = curNext;
        }
        return head;
    }

    public void reverseList(){
        if(head == null){
            return;
        }
        if(head.next == null){
            return;
        }

        ListNode cur = head.next;
        head.next = null;
        while (cur != null){
            ListNode curNext = cur.next;
            cur.next = head;
            head = cur;
            cur = curNext;
        }
    }

 用栈的方式逆序打印链表

    //用栈的方式逆序打印链表
    public void reverseStackList(){
        Stack<ListNode> stack = new Stack<>();
        ListNode cur = head;
        while (cur != null){
            stack.push(cur);
            cur=cur.next;
        }
        while (!stack.isEmpty()){
            ListNode top = stack.pop();
            System.out.print(top.val+" ");
        }
        System.out.println();
    }

暴力清空链表 

    public void clear(){
        this.head = null;
    }

四、LinkedList的模拟实现(双链表)

4.1 什么是LinkedList

LinkedList:的底层是双向链表结构,由于链表没有将元素存储在连续的空间中,元素存储在单独的节 点中,然后通过引用将节点连接起来了,因此在在任意位置插入或者删除元素时,不需要搬移元素,效率比较高。

在集合框架中,LinkedList也实现了List接口,具体如下:

说明

1. LinkedList实现了List接口

2. LinkedList的底层使用了双向链表

3. LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问

4. LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)

5. LinkedList比较适合任意位置插入的场景

4.2LinkedList的使用(及实现)

 1. LinkedList的构造

2. LinkedList的其他常用方法介绍 

3.方法的具体实现 

使用内部类构造双链表的节点,头节点,尾结点 

    static class ListNode{
        private int val;//链表值域
        private ListNode prev;//前节点地址
        private ListNode next;//后节点地址

        //构造方法,初始化链表节点值域
        public ListNode(int val) {
            this.val = val;
        }
    }
    public ListNode head; //双向链表的头结点
    public ListNode last;//双向链表的尾巴

头插法

    //头插法
    public void addFirst(int data){
        ListNode node = new ListNode(data);
        if (head == null){
            head = node;
            last = node;
            return;
        }
        head.prev =node;
        node.next = head;
        head = node;
    }

尾插法

    //尾插法
    public void addLast(int data){
        ListNode node =new ListNode(data);
        if (head == null){
            head = node;
            last = node;
            return;
        }
        last.next =node;
        node.prev = last;
        last = node;
    }

链表长度

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

 打印链表

    //打印链表
    public void display(){
        ListNode cur = head;
        if (cur == null){
            System.out.println("该链表为空,无法打印!");
            return;
        }
        while (cur != null){
            System.out.print(cur.val+" ");
            cur = cur.next;
        }
        System.out.println();//方便测试看数据
    }

链表是否包含某元素

    //链表是否包含某元素
    public boolean contains(int key){
        ListNode cur = head;
        if (cur == null){
            System.out.println("该链表为空!");
            return false;
        }
        while (cur != null){
            if(cur.val == key){
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

检查下标是否异常

    //检查下标是否异常
    public void checkIndex(int index){
        if (index<0 || index >size()){//等于size用尾插法
            throw new indexOutOfException("index 不合法!"+index);
        }
    }

 在某位置添加元素

    public void addIndex(int index, int data) {
        checkIndex(index);
        if (index == 0) {
            addFirst(data);
            return;
        }
        if(index == size()) {
            addLast(data);
            return;
        }
        ListNode node = new ListNode(data);
//            while (index !=0){
//                cur = cur.next;
//                index--;
//            }
        ListNode cur = searchIndexNode(index);
        node.prev=cur.prev;
        node.next=cur;
        cur.prev.next = node;
        cur.prev = node;
    }

 找到第n个节点的位置

    //双链表,由于知道了前一个节点的位置
    //因此插进第n个元素时直接找到第n个节点的位置就可以
    private ListNode searchIndexNode(int index){
        ListNode cur =head;
        while (index !=0){
            cur = cur.next;
            index--;
        }
        return cur;
    }

 删除第一个出现的某元素

删除链表中所有这个元素

 后续会添加完整的代码

五、ArrayList和LinkedList的区别 

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

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

相关文章

无法连接到internet怎么办?已连接但无internet访问,其实并不难

有时我们会遇到无法连接到Internet的问题&#xff0c;由多种原因引起&#xff0c;包括硬件故障、软件设置问题、网络供应商故障等。本文将介绍无法连接到Internet时可以采取的步骤。 简述 当你无法连接到Internet时&#xff0c;可以按照以下步骤进行检查和解决&#xff1a; 1…

数据结构C++——优先队列

文章目录 一、定义二、ADT三、优先队列的描述3.1 线性表3.2 堆3.2.1 最大堆的ADT3.2.2 最大堆的插入3.2.3 最大堆的删除3.2.4 最大堆的初始化3.3 左高树 LT3.3.1 高度优先左高树HBLT3.3.2 重量优先左高树WBLT3.3.3 最大HBLT的插入3.3.4 最大HBLT的删除3.3.5 合并两棵最大HBLT3.…

自用:磁传感器数据解算

协议格式&#xff1a; 详细计算磁场如下&#xff1a; 3字节数据的格式为有符号整型数&#xff0c;数据为补码格式&#xff0c;最高位为符号位。需要先将补码格式的数据转化为10进制的实际值&#xff0c;方法如下&#xff1a; 当数据小于时为正数&#xff0c;实际值为本身&…

Mac中maven配置安装路径

Mac中maven配置安装路径 没有下载maven的可以先下载&#xff1a;&#xff08;这里建议maven版本不要下高了&#xff09; 如果你的bash_profile中没有配置JAVA_HOME路径&#xff0c;可以按照下面的命令配置一下 获取JAVA的安装路径&#xff1a; /usr/libexec/java_home -V …

Nest.js 实战 (三):使用 Swagger 优雅地生成 API 文档

什么是 Swagger ? Swagger 是一组围绕 OpenAPI 规范构建的开源工具&#xff0c;可以帮助您设计、构建、记录和使用 REST API。主要的 Swagger 工具 包括&#xff1a; Swagger Editor&#xff1a;基于浏览器的编辑器&#xff0c;您可以在其中编写 OpenAPI 定义Swagger UI&…

NSSCTF[堆][tcache]

1. [CISCN 2021 初赛]lonelywolf 题目地址&#xff1a;[CISCN 2021 初赛]lonelywolf | NSSCTF 思路&#xff1a; 修开tcache结构&#xff0c;伪造一个0x91的chunk&#xff0c;伪造0x91chunk的数量&#xff08;填满tcache&#xff09;&#xff0c;再将其释放free进入unsortedb…

Linux中,MySQL数据库基础

21 世纪&#xff0c;人类迈入了“信息爆炸时代”&#xff0c;大量的数据、信息在不断产生&#xff0c;伴随而来的就是如何安全、有效地存储、检索和管理它们。对数据的有效存储、高效访问、方便共享和安全控制已经成为信息时代亟待解决的问题。 数据库简介 使用数据库的必要性…

MATLAB--文件操作相关指令

文章目录 文件操作相关指令前言 M文件创建MATLAB文件操作指令MATLAB文件流控制 文件操作相关指令 前言 记录一下M文件创建、操作、获取信息等相关资料。   MATLAB的M文件是用来代替MATLAB命令行窗口输入指令的文件。因此所有的MATLAB指令都可以再MATLAB的M文件中调用. M文件…

算法力扣刷题记录 五十七【236. 二叉树的最近公共祖先】和【235. 二叉搜索树的最近公共祖先】

前言 公共祖先解决。二叉树和二叉搜索树条件下的最近公共祖先。 二叉树篇继续。 一、【236. 二叉树的最近公共祖先】题目阅读 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff…

Spring Bean介绍

目录 1.什么是bean 2.获取bean 3.bean的作用域 4.第三方bean 5.Bean的生命周期 6.Bean的种类 7.为什么使用Bean&#xff1f; 1.什么是bean Bean是Java世界中的一种组件&#xff0c;用于封装数据和逻辑&#xff0c;以便在应用程序中重用和维护。它不仅可以装在数据&#x…

Redis哨兵模式实践

本次环境为Centos7.6&#xff0c;redis-7.0.4 1&#xff1a;主备模式&#xff1a;即主节点的数据自动同步到从节点&#xff0c;但当主节点挂了&#xff0c;从节点需要手动设置为主节点&#xff0c;比较麻烦。 2&#xff1a;哨兵模式&#xff1a;当主节点挂了&#xff0c;自动投…

PCL-基于SAC_IA和NDT结合的点云配准算法

一、原理概述1.点云配准流程图2.快速点特征直方图FPFH3.采样一致性SAC_IA粗配准4.正态分布变换NDT精配准 二、实验代码三、实验结果四、总结五、参考 一、原理概述 1.点云配准流程图 2.快速点特征直方图FPFH 快速点特征直方图&#xff08;Fast Point Feature Histogram&#…

Oracle SQL:了解执行计划和性能调优

查询优化类似于制作完美食谱的艺术——它需要对成分&#xff08;数据&#xff09;、厨房&#xff08;数据库系统&#xff09;和使用的技术&#xff08;查询优化器&#xff09;有深入的了解。每个数据库系统都有自己的处理和运行 SQL 查询的方式&#xff0c;“解释”计划向我们展…

Mysql注意事项(一)

Mysql注意事项&#xff08;一&#xff09; 最近回顾了一下MySQL&#xff0c;发现了一些MySQL需要注意的事项&#xff0c;同时也作为学习笔记&#xff0c;记录下来。–2020年05月13日 1、通配符* 检索所有的列。 不建议使用 通常&#xff0c;除非你确定需要表中的每个列&am…

每日刷题记录(codetop版)

7.21 7.22 7.23 复习7.21和7.22

每日OJ_牛客DD1 连续最大和

目录 牛客DD1 连续最大和 解析代码 牛客DD1 连续最大和 连续最大和_牛客题霸_牛客网 解析代码 本题是一个经典的动规问题&#xff0c;简称dp问题&#xff0c;但这个问题是非常简单的dp问题&#xff0c;而且经常会考察&#xff0c;所以一定要把这个题做会。本题题意很简单&am…

探寻安全新时代:叉车AI智能影像防撞系统,守护生命之光

在繁忙的工业现场&#xff0c;叉车司机常常面临着视线受阻的困境&#xff0c;那些被货物遮挡的盲区&#xff0c;仿佛隐藏着无法预知的危险。然而&#xff0c;这样的隐患在一次惨痛的事故中暴露无遗&#xff0c;一名无辜的行人因叉车司机的视线受阻而不幸被撞身亡。这起悲剧让我…

机械设计基础B(学习笔记)

绪论 机构&#xff1a;是一些具备各自特点的和具有确定的相对运动的基本组合的统称。 组成机构的各个相对运动部分称为构件。构件作为运动单元&#xff0c;它可以是单一的整体&#xff0c;也可以是由几个最基本的事物&#xff08;通常称为零件&#xff09;组成的刚性结构。 构件…

python·数据分析基础知识

numpy 一个数值计算包 python列表与numpy矩阵区别 python中修改列表元素和列表相加 for循环 &#xff1a;[x1 for x in a] 多个元素需要用zip捆绑&#xff1a;[xy for(x,y) in zip(a,b)] numpy矩阵自动进行相应元素计算 np.array()1各元素1 ab各元素相加 a*b矩阵相乘或者是…

爬虫学习4:爬取王者荣耀技能信息

爬虫&#xff1a;爬取王者荣耀技能信息&#xff08;代码和代码流程&#xff09; 代码 # 王者荣耀英雄信息获取 import time from selenium import webdriver from selenium.webdriver.common.by import By if __name__ __main__:fp open("./honorKing.txt", "…