LinkedList与单向链表(二)(双向链表)

news2024/9/26 5:14:19

1.ListedList的模拟实现

package Demo1;

/**
 * Describe:双向链表的简单模拟实现
 * User:lenovo
 * Date:2023-01-08
 * Time:11:20
 */
class Node {
    int val;
    Node prev;
    Node next;

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

    public Node() {
    }
}
public class MyLinkedList {
    Node first;
    Node last;
    int size = 0;

    public MyLinkedList() {
    }

    //头插法
    public void addFirst(int data){
        Node cur = new Node(data);
        //链表为空
        if(first == null) {
            first = cur;
            last = cur;
            size++;
            return;
        }
        //链表不为空
        cur.next = first;
        first.prev = cur;
        first = cur;
        size++;
    }
    //尾插法
    public void addLast(int data){
        Node cur = new Node(data);
        //链表为空
        if(first == null) {
            first = cur;
            last = cur;
            size++;
            return;
        }
        //链表不为空
        last.next = cur;
        cur.prev = last;
        last = last.next;
        size++;
    }

    //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data){
        if(index < 0 || index > size) {
            return;//这里我们可以直接返回,或者报错
        }
        Node cur = new Node(data);
        Node s1 = first;
        Node s2 = first;
        //头节点的插入
        if(index == 0) {
            addFirst(data);
            return;
        }
        //尾节点的插入
        if(index == size){
            addLast(data);
            return;
        }
        //找这个下表的节点
        //如果它小,我们从头找这个元素
        int count = 0;
        if(index < size / 2) {
            while(count != index) {
                s2 = s2.next;
                count++;
            }
        }else {
            s2 = last;
            while(size - 1 - index != count) {
                s2 = s2.prev;
                count++;
            }
        }

        s1 = s2.prev;
        //开始插入
        s1.next = cur;
        cur.next = s2;
        s2.prev = cur;
        cur.prev = s1;
        size++;
    }

    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key){
        Node cur = first;
        if(first == null ) {
            return false;
        }
        while(cur != null && cur.val != key) {
            cur = cur.next;
        }
        if(cur == null) {
            return false;
        }else {
            return true;
        }
    }

    //删除第一次出现关键字为key的节点
    public void remove(int key){
        Node cur = first;
        if(first == null ) {
            return;
        }
        while(cur != null) {
            if(cur.val == key) {
                //头节点的判断
                if(cur == first) {
                    //如果只有一个节点
                    if(cur.next == null) {
                        first = null;
                        last = null;
                        size--;
                        break;
                    }
                    Node s1 = cur.next;
                    s1.prev = null;
                    first = s1;
                    size--;
                    break;
                }else if(cur == last) {//尾节点的判断
                    Node s1 = cur.prev;
                    s1.next = null;
                    last = s1;
                    size--;
                    break;
                }else {//其他节点的判断
                    Node s1 = cur.prev;
                    Node s2 = cur.next;
                    s1.next = s2;
                    s2.prev = s1;
                    size--;
                    break;
                }

            }
            cur = cur.next;
        }
    }
    //删除所有值为key的节点
    public void removeAllKey(int key){
        if(first == null ) {
            return;
        }

        Node cur = first;
        while(cur != null) {
            if(cur.val == key) {
                //头节点的判断
                if(cur == first) {
                    //如果只有一个节点
                    if(cur.next == null) {
                        first = null;
                        last = null;
                        size--;
                        break;
                    }
                    Node s1 = cur.next;
                    s1.prev = null;
                    first = s1;
                    size--;
                }else if(cur == last) {//尾节点的判断
                    Node s1 = cur.prev;
                    s1.next = null;
                    last = s1;
                    size--;
                }else {//其他节点的判断
                    Node s1 = cur.prev;
                    Node s2 = cur.next;
                    s1.next = s2;
                    s2.prev = s1;
                    size--;
                }
            }
            cur = cur.next;

        }
    }

    //得到单链表的长度
    public int size(){
        return size;
    }

    public void display(){
        //链表为空
        if(this.first ==null) {
            return;
        }
        Node cur = first;
        while(cur != null) {
            System.out.print(cur.val + " ");
            cur = cur.next;
        }
        System.out.println();
    }

    public void clear(){
        //最保险的方式是遍历数组每个节点的上下节点设为空
        Node cur = first;
        while(cur != null) {
            Node tmp = cur.next;
            cur.prev = null;
            cur.next = null;
            cur = tmp;
        }
        first = null;
        last = null;
    }

    //测试
    public static void main(String[] args) {
        MyLinkedList list = new MyLinkedList();
        System.out.println("==================头插法===============");
        list.addFirst(1);
        list.addFirst(2);
        list.addFirst(3);
        list.addFirst(4);
        list.display();
        System.out.println("================尾插法================");
        MyLinkedList list2 = new MyLinkedList();
        list2.addLast(1);
        list2.addLast(2);
        list2.addLast(3);
        list2.addLast(4);
        list2.display();
        System.out.println("===============插入任意位置=============");
        list2.addIndex(-1,0);//这条不会被加上去
        list2.addIndex(4,5);
        list2.addIndex(1,11);
        list2.display();
        System.out.println("===============查找关键字===============");
        System.out.println(list2.contains(1));
        System.out.println(list2.contains(0));
        System.out.println("===============删除第一个关键字===========");
        list2.remove(11);
        list2.remove(22);
        list2.display();
        System.out.println("===============删除所有的5==============");
        list2.addLast(5);
        list2.addLast(5);
        list2.addLast(5);
        list2.addLast(6);
        list2.removeAllKey(5);
        list2.display();
        System.out.println("==============获得长度================");
        System.out.println(list2.size());
        System.out.println("==============清空数组================");
        list2.clear();
        list2.display();


    }
}

(如有错误,请批评指针,评论区会不定时查看)

2.LinkedList的使用

2.1什么是LinkedList

LinkedList的底层是双向链表结构,双向链表的的储存并不需要连续的大块空间,并且链表是通过节点链接起来的,因此在任意位置插入或删除元素并没有很高的复杂度。

  • LinkedList实现了List接口;

  • LinkedList的底层是双向链表;

  • LinkedList没有实现RandomAccess及接口,因此不支持随机访问;

  • LinkedList的任意位置插入和删除元素时效率比较高;

  • LinkedList比较适合任意位置插入和删除的场景。

2.2LinkedList的使用

    • LinkedList的构造方法

两个构造方法:

无参构造:LinkedList()

使用其他容器中元素构造List:public LinkedList(Collection<? extends E> c)

/**
 * Describe:LinkedList构造方法的介绍
 * User:lenovo
 * Date:2023-01-09
 * Time:14:17
 */
public class Test {
    public static void main(String[] args) {
        List<Integer> list1 = new LinkedList<>();

        List<String> list2 = new ArrayList<>();
        list2.add("javeSE");
        list2.add("javaWeb");

        List<String> list3 = new LinkedList<>(list2);
    }
}

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

//常用方法的介绍
public class Test {
    public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();
        System.out.println("===========尾插法================");
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
        System.out.println(list);
        System.out.println("=================在任意位置插入===============");
        list.add(0, 0);
        System.out.println(list);
        System.out.println("=================移除元素===============");
        list.remove();//移除第一个元素,内部调用的是removeFirst
        System.out.println(list);
        list.removeFirst();//移除第一个元素
        System.out.println(list);
        list.removeLast();//移除最后一个元素
        System.out.println(list);
        list.remove((Integer) 3);//移除第一个指定的元素
        System.out.println(list);
        System.out.println("================contains()检测是否包含某一元素=============");
        System.out.println(list.contains(2));
        System.out.println(list.contains(3));
        System.out.println("=================找都某一元素返回下标======================");
        System.out.println(list.indexOf(2));
        System.out.println(list.lastIndexOf(4));
        System.out.println("===================获得某一位置的元素=====================");
        System.out.println(list.get(0));
        System.out.println("===================修改某一位置的元素=====================");
        list.set(0, 1);
        System.out.println(list);
        System.out.println("================subList()创建一个新的LinkedList==========");
        List<Integer> list1 = list.subList(1, 3);//前闭后开
        System.out.println(list1);
        list1.set(0, 0);
        System.out.println(list);//修改链表1,但是原链表也改变了,说明公用一个链表
        System.out.println("====================清空链表===========================");
        list.clear();
        System.out.println(list);
        System.out.println(list.size());
    }
}

3.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);
        //foreach遍历
        for (int a : list) {
            System.out.print(a + " ");
        }
        System.out.println();
        //迭代器,正向遍历
        ListIterator<Integer> it = list.listIterator();
        while (it.hasNext()) {
            System.out.print(it.next() + " ");
        }
        System.out.println();
        //使用迭代器,反向遍历
        ListIterator<Integer> rit = list.listIterator(list.size());
        while(rit.hasPrevious()) {
            System.out.print(rit.previous() + " ");
        }
        System.out.println();
    }
}

4.ArrayList和LinkedList的区别

不同点

ArrayList

LinkedList

储存空间上

连续的大段空间

逻辑上连续,空间上不需要连续

随机访问

时间复杂度O(1)

时间复杂度O(N)

头插

需要移动后面元素,较为复杂

不需要移动后面元素,效率较高

插入

空间不够,需要扩容

没有容量的概念

应用场景

元素高效储存+频繁访问

任意位置插入+频繁增删

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

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

相关文章

Linux--权限

一、目录权限 文件的权限描述符&#xff0c;由10个字母组成 如下图所示&#xff0c;可以按照1-3-3-3的结构划分&#xff0c;用rwx表示拥有权限&#xff0c;r代表read&#xff08;可读&#xff09;&#xff0c;w代表write&#xff08;可写&#xff09;&#xff0c;x代表execut…

Python高阶技巧(十二)

python学习之旅(十二) &#x1f44d;查看更多可以关注查看首页或点击下方专栏目录 一.闭包 可以保存函数内变量&#xff0c;不会随着函数调用完而销毁 (1) 基本定义 在函数嵌套的前提下&#xff0c;内部函数使用了外部函数的变量&#xff0c;并且外部函数返回了内部函数&#x…

万字长文,带你从0到1的了解商业智能BI

借助互联网技术的发展&#xff0c;每天我们都会接触到大量的信息&#xff0c;信息的增长速度可以说是海啸级的。在这样一个信息爆炸的时代&#xff0c;掌握怎样利用数据就相当于掌握了一项生存技能&#xff0c;很多可以发掘并充分利用数据的企业会发现自己远远领先于竞争对手。…

Android 反编译初探-基础篇

前言 本文目标&#xff1a; 工具&#xff1a;介绍反编译需要用到的工具原理&#xff1a;反编译基本原理实践&#xff1a;替换一个未混淆&未加固apk的启动页面 工具 1.Android Studio 版本&#xff1a;Android Studio Dolphin | 2021.3.1 Patch 1 2.Jadx Class Decomp…

go 数组(array)和切片(slice)

文章目录数组ArraySlice 切片appendcopy&#xff08;切片复制&#xff09;goto数组Array 和以往的数组有很大的不同 数组时值类型&#xff0c;复制和传参会复制整个数组&#xff0c;而不是指针数组长度必须是常量&#xff0c;且是类型的组成部分。[2]int和[3]int是不同的数据…

Vue中Vue.use()的原理及基本使用

目录 &#x1f525; 前言 1. 举例理解 2. 源码分析 &#x1f525; 小结 相信很多人在用Vue使用别人的组件时,会用到 Vue.use() ,例如&#xff1a;Vue.use(VueRouter)、Vue.use(MintUI)&#xff0c;这篇文章主要给大家介绍了关于Vue中Vue.use()的原理及基本使用的相关资料&a…

Mysql索据-Mysql的innodb引擎为什么要使用b+tree作为索引数据结构?

目录 索引&#xff1f; 什么是索引&#xff1f;索引有什么优点&#xff1f;索引有什么缺点&#xff1f; 索引的分类 按照功能分类&#xff1a; 按照数据结构分类 相关数据结构&#xff08;b-tree、btree&#xff09; b-tree btree b-tree和btree的区别 为什么Innodb要…

65. 锚框的代码实现

目标检测算法通常会在输入图像中采样大量的区域&#xff0c;然后判断这些区域中是否包含我们感兴趣的目标&#xff0c;并调整区域边界从而更准确地预测目标的真实边界框&#xff08;ground-truth bounding box&#xff09;。 不同的模型使用的区域采样方法可能不同。 这里我们…

TiDB学习笔记(八)-数据库故障处理

一、数据丢失快速恢复 数据恢复前置条件-GC&#xff0c;tidb_gc_life_time 查询GC已经清理的时间点tikv_gc_safe_point 数据快速恢复操作方式 DML->tidb_snapshot参数 &#xff08;在tikv_gc_safe_point范围内&#xff09; DDL->flashback table/recover table (flas…

AIGC与搜索深度融合,百度定义“生成式搜索”

设想一下&#xff0c;当你搜索“公司活动通知怎么写”时&#xff0c;搜索引擎直接“写”了一篇送到眼前是什么体验&#xff1f;百度的“生成式搜索”正在让这样的场景成为现实。日前&#xff0c;百度宣布&#xff0c;百度搜索将升级“生成式搜索”能力&#xff0c;基于百度自研…

项目管理工具dhtmlxGantt甘特图入门教程(七):在服务器上使用甘特图

dhtmlxGantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表&#xff0c;可满足项目管理控件应用程序的所有需求&#xff0c;是最完善的甘特图图表库。 这篇文章给大家讲解如何在服务器上使用DHTMLX Gantt 。 DhtmlxGantt正版试用下载&#xff08;qun&#xff1a;764…

Cadence PCB仿真使用Allegro PCB SI元器件类别设置为IO,IC和Discrete的方法图文教程

⏪《上一篇》   🏡《总目录》   ⏩《下一篇》 目录 1,概述2,配置方法3,总结1,概述 本文简单介绍使用Allegro PCB SI软件配置电压地网络电压的方法。 2,配置方法 第1步:打开待仿真的PCB文件,并确认软件为Allegro PCB SI 如果,打开软件不是Allegro PCB SI则可这样…

ElementUI源码系列一-完整引入和按需引入

前言 本篇将介绍&#xff0c;ElementUI 是如何实现完整引入和按需引入的。 完整引入 官网使用 源码步骤 src/index.js 通过对外暴露 install()&#xff0c;让主项目通过 Vue.use(ElementUI) 引入&#xff0c;还需单独引入样式 import element-ui/lib/theme-chalk/index.c…

Selenium用法详解【Options选项】【JAVA爬虫】

简介本文主要讲解如何使用java代码利用selenium控制浏览器的启动选项Options的代码操作教程。Options选项这是一个Chrome的参数对象&#xff0c;在此对象中使用addArgument()方法可以添加启动参数&#xff0c;添加完毕后可以在初始化Webdriver对象时将此Options对象传入&#x…

minio分布式存储的go语言开发衔接

minio是分布式存储&#xff0c;可集群部署&#xff0c;阵列磁盘&#xff0c;纠错码等大数据存储必备的技术。由于它是go语言开发的&#xff0c;我们用go来与它衔接&#xff1a;上传文件&#xff0c;比如图片&#xff0c;然后预览。这里涉及几个重要的知识点。一是minio永久路径…

Vue学习笔记(二)

Vue学习笔记二脚手架利用脚手架软件生成项目包脚手架 随着时代的发展, WEB开发逐渐出现了 工程化 特征: 流水线作业! 脚本方式: 到饭店 自选点餐… 脚手架方式: 点 套餐, 一套完善的配置,扩展, 各种易用功能… 脚手架: 就是一款软件, 可以按照用户需求自动生成 开发环境: 包含…

[博士论文]基于图数据的可信赖机器学习

密歇根大学Towards Trustworthy Machine Learning on Graph Datahttps://deepblue.lib.umich.edu/handle/2027.42/174201摘要机器学习已经被应用于越来越多影响我们日常生活的与社会相关的场景&#xff0c;从社交媒体和电子商务到自动驾驶汽车和刑事司法。因此&#xff0c;为了…

7-2 洛希极限

科幻电影《流浪地球》中一个重要的情节是地球距离木星太近时&#xff0c;大气开始被木星吸走&#xff0c;而随着不断接近地木“刚体洛希极限”&#xff0c;地球面临被彻底撕碎的危险。但实际上&#xff0c;这个计算是错误的。 洛希极限&#xff08;Roche limit&#xff09;是一…

用Python实现十大经典排序算法(附动图)

排序算法是《数据结构与算法》中最基本的算法之一。 排序算法可以分为内部排序和外部排序&#xff0c;内部排序是数据记录在内存中进行排序&#xff0c;而外部排序是因排序的数据很大&#xff0c;一次不能容纳全部的排序记录&#xff0c;在排序过程中需要访问外存。常见的内部排…

69、CLIP-NeRF: Text-and-Image Driven Manipulation of Neural Radiance Fields

简介 官网&#xff1a;https://cassiepython.github.io/clipnerf/ 利用对比语言-图像预训练(CLIP)模型的联合语言-图像嵌入空间&#xff0c;提出了一个统一的框架&#xff0c;可以用短文本提示或示例图像以用户友好的方式操纵NeRF。改论文结合NeRF的新视图合成能力和生成模型潜…