java的LinkedList

news2024/11/24 3:17:11

java的LinkedList

  • 什么是LinkedList
  • LinkedList的模拟实现
  • LinkedList的使用
  • ArrayList和LinkedList的区别

什么是LinkedList

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

  1. LinkedList实现了List接口
  2. LinkedList的底层使用了双向链表
  3. LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问
  4. LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)
  5. LinkedList比较适合任意位置插入的场景

LinkedList的模拟实现

在这里插入图片描述

public interface IList {
    //头插法
    public void addFirst(int data);
    //尾插法
    public void addLast(int data);
    //任意位置插入,第一个数据节点为0号下标
    public void 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 clear();
    public void display();
}
public class MyLinkedList implements IList{
        static class ListNode{
        public int val;
        public ListNode prev;
        public ListNode next;

        public ListNode(int val) {
            this.val = val;
        }
    }


    public ListNode head;
    public ListNode last;
    
    @Override
    public void addFirst(int data) {
        
    }

    @Override
    public void addLast(int data) {

    }

    @Override
    public void addIndex(int index, int data) {

    }

    @Override
    public boolean contains(int key) {
        return false;
    }

    @Override
    public void remove(int key) {

    }

    @Override
    public void removeAllKey(int key) {

    }

    @Override
    public int size() {
        return 0;
    }

    @Override
    public void clear() {

    }

    @Override
    public void display() {

    }
    
}

我们先来实现打印链表和得到链表长度

@Override
public int size() {
    ListNode cur = this.head;
    int count = 0;
    while(cur != null){
        cur = cur.next;
        count++;
    }
    return count;
}
@Override
public void display() {
    ListNode cur = this.head;
    while(cur != null){
        System.out.print(cur.val + " ");
        cur = cur.next;
    }
    System.out.println();
}

接下来实现头插法

在这里插入图片描述

@Override
public void addFirst(int data) {
    ListNode newNode = new ListNode(data);
    if(this.head == null){
        head = last = newNode;
        return;
    }
    head.prev = newNode;
    newNode.next = head;
    head = newNode;
}
public class Test {
    public static void main(String[] args) {
        MyLinkedList list = new MyLinkedList();
        list.addFirst(56);
        list.addFirst(45);
        list.addFirst(34);
        list.addFirst(23);
        list.addFirst(12);
        list.display();
        list.addFirst(33);
        list.display();
        System.out.println(list.size());
    }
    //结果为:
    //12 23 34 45 56 
    //33 12 23 34 45 56 
    //6
}

实现尾插法
在这里插入图片描述

@Override
public void addLast(int data) {
    ListNode newNode = new ListNode(data);
    if(head == null){
        head = last = newNode;
        return;
    }
    last.next = newNode;
    newNode.prev = last;;
    last = newNode;
}
public class Test {
    public static void main(String[] args) {
        MyLinkedList list = new MyLinkedList();
        list.addLast(12);
        list.addLast(23);
        list.addLast(34);
        list.addLast(45);
        list.addLast(56);
        list.display();
    }
    //结果为:
    //12 23 34 45 56
}

实现任意位置插入,第一个数据节点为0号下标
在这里插入图片描述

private ListNode findIndex(int index){
    ListNode cur = this.head;
    while(index != 0){
        cur = cur.next;
        index--;
    }
    return cur;
}
@Override
public void addIndex(int index, int data) {
    int len = size();
    if(index < 0 || index > len - 1){
        return;
    }
    if(index == 0){
        addFirst(data);
        return;
    }
    if(index == len - 1){
        addLast(data);
        return;
    }
    ListNode cur = findIndex(index);
    ListNode newNode = new ListNode(data);
    newNode.next = cur;
    cur.prev.next = newNode;
    newNode.prev = cur.prev;
    cur.prev = newNode;
}
public class Test {
    public static void main(String[] args) {
        MyLinkedList list = new MyLinkedList();
        list.addLast(12);
        list.addLast(23);
        list.addLast(34);
        list.addLast(45);
        list.addLast(56);
        list.display();
        list.addIndex(2,33);
        list.display();
        list.addIndex(0,33);
        list.display();
        list.addIndex(6,33);
        list.display();
        list.addIndex(8,33);
        list.display();
    }
    //结果为:
    //12 23 34 45 56
    //12 23 33 34 45 56
    //33 12 23 33 34 45 56
    //33 12 23 33 34 45 56 33
    //33 12 23 33 34 45 56 33
}

实现删除第一次出现关键字为key的节点
在这里插入图片描述

@Override
public void remove(int key) {
    ListNode cur = this.head;
    while(cur != null){
        if(cur.val == key){
            if(cur == this.head){
                head = head.next;
                if(head != null){
                    head.prev = null;
                }
            }else{
                cur.prev.next = cur.next;
                if(cur.next == null){
                    last = last.prev;
                }else{
                    cur.next.prev = cur.prev;
                }
            }
            return;
        }
        cur = cur.next;
    }
}
public class Test {
    public static void main(String[] args) {
        MyLinkedList list = new MyLinkedList();
        list.addLast(12);
        list.addLast(23);
        list.addLast(34);
        list.addLast(45);
        list.addLast(56);
        list.display();
        list.remove(12);
        list.display();
        list.remove(56);
        list.display();
        list.remove(34);
        list.display();
    }
    //结果为:
    //12 23 34 45 56
    //23 34 45 56
    //23 34 45
    //23 45
}

删除所有值为key的节点,我们只需要在删除第一次出现关键字为key的节点的代码上将return删除掉,让其循环到链表结尾

@Override
public void removeAllKey(int key) {
    ListNode cur = this.head;
    while(cur != null){
        if(cur.val == key){
            if(cur == this.head){
                head = head.next;
                if(head != null){
                    head.prev = null;
                }
            }else{
                cur.prev.next = cur.next;
                if(cur.next == null){
                    last = last.prev;
                }else{
                    cur.next.prev = cur.prev;
                }
            }
        }
        cur = cur.next;
    }
}
public class Test {
    public static void main(String[] args) {
        MyLinkedList list = new MyLinkedList();
        list.addLast(23);
        list.addLast(33);
        list.addLast(34);
        list.addLast(23);
        list.addLast(23);
        list.display();
        list.removeAllKey(23);
        list.display();
    }
    //结果为:
    //23 33 34 23 23
    //33 34
}

实现查找是否包含关键字key是否在双向链表当中,我们只需要遍历链表,找到返回true,没找到返回false

@Override
public boolean contains(int key) {
    ListNode cur = this.head;
    while(cur != null){
        if(cur.val == key){
            return true;
        }
        cur = cur.next;
    }
    return false;
}
public class Test {
    public static void main(String[] args) {
        MyLinkedList list = new MyLinkedList();
        list.addLast(12);
        list.addLast(23);
        list.addLast(34);
        list.addLast(45);
        list.addLast(56);
        list.display();
        System.out.println(list.contains(34));
        System.out.println(list.contains(100));
    }
    //结果为:
    //12 23 34 45 56
    //true
    //false
}

接下来实现clear,我们可以直接暴力的将head和last置为null
但是最后是将每个结点的prev和last都置为null,我们需要一个curN保留下一个结点,最后还需要将head和last置为null

@Override
public void clear() {
    ListNode cur = this.head;
    while(cur != null){
        ListNode curN = cur.next;
        cur.prev = null;
        cur.next = null;
        cur = curN;
    }
    this.head = this.last = null;
}
public class Test {
    public static void main(String[] args) {
        MyLinkedList list = new MyLinkedList();
        list.addLast(12);
        list.addLast(23);
        list.addLast(34);
        list.addLast(45);
        list.addLast(56);
        list.display();
        list.clear();
        list.display();
    }
    //结果为:
    //12 23 34 45 56
    //
}

LinkedList的使用

  1. LinkedList的构造
方法解释
LinkedList ()无参构造
LinkedList (Collection<? extends E> c)利用其他集合容器中元素构造List
import java.util.ArrayList;
import java.util.LinkedList;
public class Test {
    public static void main(String[] args) {
        //构造一个空的LinkedList
        LinkedList<Integer> list1 = new LinkedList<>();
        list1.add(1);
        list1.add(2);
        list1.add(3);
        list1.add(4);
        list1.add(5);
        System.out.println(list1);

        ArrayList<Integer> list2 = new ArrayList<>();
        list2.add(11);
        list2.add(22);
        list2.add(33);
        list2.add(44);
        list2.add(55);
        //使用ArrayList构造LinkedList
        LinkedList<Integer> list3 = new LinkedList<>(list2);
        System.out.println(list3);

    }
    //结果为:
    //[1, 2, 3, 4, 5]
    //[11, 22, 33, 44, 55]
}
  1. LinkedList的其他常用方法介绍
方法解释
boolean add(E e)尾插 e
void add(int index, E element)将 e 插入到 index 位置
boolean addAll(Collection<? extends E> c)尾插 c 中的元素
E remove(int index)删除 index 位置元素
boolean remove(Object o)删除遇到的第一个 o
E get(int index)获取下标 index 位置元素
E set(int index, E element)将下标 index 位置元素设置为 element
void clear()清空
boolean contains(Object o)判断 o 是否在线性表中
int indexOf(Object o)返回第一个 o 所在下标
int lastIndexOf(Object o)返回最后一个 o 的下标
List< E > subList(int fromIndex, int toIndex)截取部分 list
import java.util.LinkedList;
import java.util.List;
public class Test {
    public static void main(String[] args) {
        LinkedList<Integer> list1 = new LinkedList<>();
        list1.add(1);   //add(elem)表示尾插
        list1.add(2);
        list1.add(3);
        list1.add(4);
        list1.add(5);
        System.out.println(list1.size());   //5
        System.out.println(list1);      //[1, 2, 3, 4, 5]

        //在起始位置插入0
        list1.add(0,0);    //add(index,elem);在index位置插入元素elem
        System.out.println(list1);      //[0, 1, 2, 3, 4, 5]

        list1.remove();     //remove();删除第一个元素,内部调用的是removeFirst()
        System.out.println(list1);  //[1, 2, 3, 4, 5]
        list1.removeFirst();    //removeFirst();删除第一个元素
        System.out.println(list1);  //[2, 3, 4, 5]
        list1.removeLast();     //removeLast();删除最后一个元素
        System.out.println(list1);  //[2, 3, 4]
        list1.remove(1);    //remove(index);删除index位置的元素
        System.out.println(list1);  //[2, 4]

        //contains(elem):检测elem元素是否存在,如果存在返回true,否则返回false
        if(!list1.contains(1)){
            list1.add(0,1);
        }
        System.out.println(list1);  //[1, 2, 4]
        list1.addLast(1);
        System.out.println(list1);  //[1, 2, 4, 1]
        System.out.println(list1.indexOf(1));   //indexOf(elem);从前往后找第一个elem的位置 0
        System.out.println(list1.lastIndexOf(1));   //lastIndexOf(elem);从后往前找第一个elem的位置 3
        int elem = list1.get(0);    //get(index);获取指定位置元素
        System.out.println(elem);   // 1
        list1.set(0,100);   //set(index,elem);将index位置的元素设置为elem
        System.out.println(list1);  //[100, 2, 4, 1]

        //subList(from,to):用list1中[from,to)之间的元素构造一个新的LinkedList返回
        List<Integer> copy = list1.subList(0,3);
        System.out.println(list1);  //[100, 2, 4, 1]
        System.out.println(copy);   //[100, 2, 4]
        list1.clear();  //将list1中元素清空
        System.out.println(list1.size());   //0
    }
}
  1. LinkedList的遍历
public class Test {
    public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        System.out.println(list);

        System.out.println("======for=====");
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i) + " ");
        }
        System.out.println();

        System.out.println("======for each=====");
        for(int x : list){
            System.out.print(x + " ");
        }
        System.out.println();

        System.out.println("======Iterator=====");
        Iterator<Integer> it = list.iterator();
        while(it.hasNext()){
            System.out.print(it.next() + " ");
        }
        System.out.println();

        System.out.println("======ListIterator=====");
        ListIterator<Integer> lit = list.listIterator();
        while(lit.hasNext()){
            System.out.print(lit.next() + " ");
        }
        System.out.println();

        System.out.println("======ListIterator拓展=====");
        ListIterator<Integer> lit2 = list.listIterator(list.size());
        while(lit.hasPrevious()){
            System.out.print(lit.previous() + " ");
        }
    }
    //结果为:
    //[1, 2, 3, 4, 5]
    //======for=====
    //1 2 3 4 5
    //======for each=====
    //1 2 3 4 5
    //======Iterator=====
    //1 2 3 4 5 
    //======ListIterator=====
    //1 2 3 4 5
    //======ListIterator拓展=====
    //5 4 3 2 1
}

ArrayList和LinkedList的区别

不同点ArrayListLinkedList
存储空间上物理上一定连续逻辑上连续,但物理上不一定连续
随机访问支持:O(1)不支持:O(N)
头插需要搬移元素,效率低O(N)只需修改引用的指向,时间复杂度为O(1)
插入空间不够时需要扩容没有容量的概念
应用场景元素高效存储+频繁访问任意位置插入和删除元素频繁

本篇文章到此,谢谢阅读,希望对您有帮助。

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

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

相关文章

一维数组的引用

#define SIZE 5 int main(void) { int i 0; int arr[SIZE] { 86,85,85,896,45 };//同理五个数据只是偶然&#xff0c;可能会更多 //输入 for (i 0;i < SIZE;i) { printf("请输入你的第%d个值&#xff1a;",i1); scanf_s(&…

【机器学习】逻辑回归|分类问题评估|混淆矩阵|ROC曲线|AUC指标 介绍及案例代码实现

文章目录 逻辑回归逻辑回归简介逻辑回归的数学基础逻辑回归原理概念损失函数 逻辑回归API函数和案例案例癌症分类预测 分类问题评估混淆矩阵分类评估方法 - 精确率 召回率 F1ROC曲线 AUC指标案例AUC 计算的API分类评估报告api 电信客户流失预测案例 逻辑回归 逻辑回归简介 ​…

python爬虫 - 进阶正则表达式

&#x1f308;个人主页&#xff1a;https://blog.csdn.net/2401_86688088?typeblog &#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/2401_86688088/category_12797772.html 目录 前言 一、匹配中文 &#xff08;一&#xff09;匹配单个中文字符 &#xff08;二…

【网易云音乐】--源代码分享

最近写了一个网易云音乐的音乐实现部分&#xff0c;是通过JavaScript和jQuery实现的&#xff0c;具体效果大家可以参照下面的视频 源代码分享 - git地址: 网易云音乐源代码 下面将着重讲解一下音乐实现部分 视频有点模糊&#xff0c;不好意思&#xff0c;在b站上添加视频的时候…

【Oracle DB故障分享】分享一次由于SGA设置太小导致的DP备份失败

List item 今天给客户做Oracle例行数据库健康巡检&#xff0c;过程中检出一些备份异常&#xff0c;分享如下。 排查问题&#xff1a; 打开DP备份软件&#xff0c;随即弹出如下提示&#xff1a; 登录DP&#xff0c;查看备份情况&#xff1a;发现从10/6开始&#xff0c;DP备份…

ESP32—C3实现DS18B20(温度传感器)检测温度(Arduino IED )

1源代码&#xff08;DS18B20&#xff09; #include <OneWire.h> // 引入OneWire库&#xff0c;用于与单总线设备通信 #include <DallasTemperature.h> // 引入DallasTemperature库&#xff0c;用于读取DS18B20温度传感器数据// 定义连接到DS18B20数据引脚的GPIO编…

Vue入门-指令修饰符-@keyup.enter

指令修饰符&#xff1a; 通过"."指明一些指令后缀&#xff0c;不同后缀封装了不同的处理操作 ->简化代码 ①按键修饰符 keyup.enter ->键盘回车监听 ".enter"if(e.keyenter){} //".enter"用来简化代码 demo&#xff1a; <!DOCTYPE…

Ubuntu系统可以使用WIFI上网,而插网线有线网不能上网,网卡驱动未安装问题解决

文章目录 问题分析解决结果 问题 linux ubuntn系统下可以正常连WiFi上网&#xff0c;但是不能插网线上网。 分析 首先要排除是否为硬件问题&#xff0c;我在windows下是可以正常使用网线的&#xff0c;所以排除硬件的问题。 查看网卡是否被检测(wifi有说明网卡是有检测的) …

有了WPF后Winform还有活路吗?

近年来&#xff0c;随着技术的不断发展&#xff0c;Windows Presentation Foundation&#xff08;WPF&#xff09;和Windows Forms&#xff08;WinForms&#xff09;这两种技术在开发桌面应用程序方面一直备受关注。虽然WPF以其强大的功能和灵活性吸引了众多开发者&#xff0c;…

【iOS】YYModel的初步学习

YYModel的初步学习 文章目录 YYModel的初步学习前言与JSONModel对比YYModel的优势如何使用YYModel最简单的Model形式容器类属性白名单和黑名单Model的嵌套 小结 前言 随着时代的发展&#xff0c;iOS解析JSON数据的第三方库越来越多&#xff0c;原先的JSONModel的性能上的问题逐…

【动手学深度学习】6.4 多输入多输出通道

彩色图像具有标准的RBG通道来代表红绿蓝&#xff0c;但是到目前位置我们仅展示了单个输入和单个通道的简化例子。这使得我们可以将输入&#xff0c;卷积核和输出看作二维张量而当我们添加通道时&#xff0c;输入和隐藏表示都变成了三维张量。例如每个RGB输入图像都具有 3 h …

工具篇-完整的 Git 项目管理工具教程(在命令框中使用 Git、在 IDEA 中使用 Git)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 Git 概述 2.0 Git 的安装和配置 3.0 获取本地仓库 3.1 基础操作指令 3.2 分支 4.0 Git 远程仓库 4.1 创建远程仓库 4.2 配置 SSH 公钥 4.3 操作远程仓库 5.0 使用…

活动预告|博睿数据将受邀出席GOPS全球运维大会上海站!

第二十四届 GOPS 全球运维大会暨研运数智化技术峰会上海站将于2024年10月18日-19日在上海中庚聚龙酒店召开。大会将为期2天&#xff0c;侧重大模型、DevOps、SRE、AIOps、BizDevOps、云原生及安全等热门技术领域。特设了如大模型 运维/研发测试、银行/证券数字化转型、平台工程…

Qt-系统处理窗口移动和大小改变相关事件(60)

目录 描述 使用 补充&#xff1a;事件分发 / 事件过滤 描述 移动和改变窗口大小事件 使用 重写事件 移动窗口位置 改变窗口大小 补充&#xff1a;事件分发 / 事件过滤 这个属于事件背后的逻辑&#xff0c;可以让程序员有更多的操作&#xff0c;不过要小心使用&#xff0c…

凸函数 (Convex Function)

文章目录 1.凸函数定义2. 凸函数和非凸函数的图示3.闭凸函数 1.凸函数定义 凸函数是指在其图像上的任意两个点之间画一条线&#xff0c;这条线始终不会低于函数图像。其数学定义为对于任何两个点 x x x 和 y y y&#xff0c;以及 λ ∈ [ 0 , 1 ] \lambda \in [0,1] λ∈[0,…

51单片机的智能温控风扇【proteus仿真+程序+报告+原理图+演示视频】

1、主要功能 该系统由AT89C51/STC89C52单片机LCD1602显示模块温度传感器步进电机按键、蜂鸣器、LED等模块构成。适用于智能风扇调速等相似项目。 可实现功能: 1、LCD1602实时显示温度、自动/手动和风扇风力等级 2、温度传感器DS18B20采集温度信息 3、手动模式&#xff1a;可…

【软件测试】基本知识3

一、能够说出软件缺陷判定标准 说明&#xff1a;执行结果与用例的期望结果不一致&#xff08;含义&#xff09;&#xff0c;为缺陷。 缺陷的定义&#xff1a;软件在使用过程中存在的任何问题都叫软件的缺陷&#xff0c;简称bug 缺陷判定标准 软件未实现需求&#xff08;规格&…

[单master节点k8s部署]37.微服务(一)springCloud 微服务

微服务架构的一个重要特点是&#xff0c;它与开发中使用的具体编程语言或技术栈无关。每个微服务都可以使用最适合其功能需求的语言或技术来实现。例如&#xff0c;一个微服务可以用Java编写&#xff0c;另一个微服务可以用Python、Go、Node.js等编写。微服务架构允许这种灵活性…

OpenCV高级图形用户界面(5)获取指定滑动条(trackbar)的当前位置函数getTrackbarPos()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 返回滑动条的位置。 该函数返回指定滑动条的当前位置。 cv::getTrackbarPos() 函数用于获取指定滑动条&#xff08;trackbar&#xff09;的当前…

【C++差分数组】P1672何时运输的饲料

本文涉及知识点 C差分数组 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 P1672何时运输的饲料 原文比较啰嗦&#xff0c;我简述一下&#xff1a; 第x天运来F1(1<F1<1e6)千克的饲料&#xff0c;第D&#xff08;1<2e3)天还剩F2&…