手敲MyLinkedList,简单了解其运行逻辑

1.LinkedList的介绍和结构

        LinkedList的底层是双向链表结构,相对于之前的单向无头非循环链表来说,LinkedList最大的区别就是该链表可以增加了一条链接逻辑,可以从最后一个节点通过地址访问来到整个链表的头结点。

        通过以下集合框架,LinkedList也实现了List接口,具体如下:

        注意: 

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

        1.1 LinkedList的结构 

        双向无头非循环链表的节点是由三部分构成的,用来存储数据的value域,存放下一个节点地址的next域,以及用来存放前一个节点地址的prev域,其节点和链表结构如下图所示;

                   

        简单要点如下: 

                   

2.无头双向非循环链表的实现

2.1 自定义MyLinkedList类

        1、建立一个Ilist接口,在里面构造mylinkedlist链表要实现的抽象方法;

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

        无头双向非循环链表的节点是由三个属性(value域、prev域和next域构成的),同时也要在自定义MyLinkedList类里面使用内部类创建链表节点类,之后在链表类里面创建一个头结点head来代表当前链表的引用,同时创建一个节点last来表示当前链表的最后一个节点;同时让该自定义类实现我们之前创建的接口,接下来重写接口里面的方法,让其能够具体化; 

public class MyLinkedList implements IList {static class ListNode {public int value;public ListNode prev;public ListNode next;public ListNode(int value) {this.value = value;}}public ListNode head;public ListNode last;@Overridepublic void addFirst(int data) {}@Overridepublic void addLast(int data) {}@Overridepublic void addIndex(int index, int data) {}@Overridepublic boolean contains(int key) {return false;}@Overridepublic void remove(int key) {}@Overridepublic void removeAllKey(int key) {}@Overridepublic int size() {return 0;}@Overridepublic void clear() {}@Overridepublic void display() {}
}

2.2头插法 

        思路(图解如下):

        1、如果是空链表(头节点head为null),则要添加的节点node就是头节点,也是尾节点.

        2、头节点不为null:

        2.1 将原先head的前驱节点指向新增节点位置,新增节点后驱节点指向head节点的位置,注意和新节点建立连接一定要从前往后建立;

        

        2.2 head指向新增节点位置(新的链表的第一个节点为head)。

@Overridepublic void addFirst(int data) {ListNode node = new ListNode(data);if (head == null){head = node;last = node;}else {node.next = head;head.prev = node;head = node;}}

         执行结果在2.3中;

2.3 遍历链表

        思路:与mysinglelist链表的相同,这里略;代码如下

@Overridepublic void display() {ListNode cur = head;while (cur != null){System.out.print(cur.value+"->");cur = cur.next;}System.out.println(" ");}public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addFirst(1);myLinkedList.addFirst(0);
//        myLinkedList.addFirst(2);myLinkedList.display();}

        执行结果如下:

        

2.4尾插法        

        思路:

          1、如果是空链表(头节点head为null),则要添加的节点node就是头节点,也是尾节点.

          2、头节点不为null:

          2.1 将原先last的后驱节点(last.prev)指向新增节点(node)位置,新增节点前驱节点指向last节点的位置,注意和新节点建立连接一定要从前往后建立

        2,2将node节点改为新的last节点;

        代码和测试结果如下:

@Overridepublic void addLast(int data) {ListNode node = new ListNode(data);if (head == null){head = node;last = node;}else {last.next = node;node.prev = last;last = node;}}
public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addFirst(1);myLinkedList.addFirst(0);myLinkedList.display();myLinkedList.addLast(7);myLinkedList.addLast(8);myLinkedList.display();}

                    

2.5 链表长度

        对整个链表进行遍历,使用计数器进行记录遍历的次数,最后将计数器的值返回即可,下图代码是该方法的具体实现;

 @Overridepublic int size() {int count = 0;ListNode cur = head;while (cur != null){count++;cur=cur.next;}return count;}
public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addFirst(1);myLinkedList.addFirst(0);myLinkedList.display();myLinkedList.addLast(7);myLinkedList.addLast(8);myLinkedList.display();System.out.println(myLinkedList.size());}

        测试结果如下:

        

2.6 任意位置插入

 思路:

        1、需要插入的位置必须为合法,如果不合法,我们会抛出一个异常进行提醒,所以首先自定义一个异常;

public class ListIndexOutOfException extends RuntimeException{public ListIndexOutOfException() {}public ListIndexOutOfException(String message) {super(message);}
}

         2、任意位置插入,首先分几种情况,插在开头,插在结尾,插在中间

        2.1 当插在链表开头和结尾时,可以使用头插法和尾差法

        2.2 如下图所示,按照z字形进行赋值和写代码;当插在其他的位置时,首先让cur走到index的位置(此处创建一个方法,找到index位置的节点并将这个节点定义为cur返回)(这时候就需要考虑将下一个节点加在index的位置时如何处理建立连接的顺序);其次注意建立连接的时候,一定要先建立原index前的节点和node节点添加节点的连接,其次再建立添加节点(node)和原index节点的连接,链表图解如下:

         具体方法代码如下:

@Overridepublic void addIndex(int index, int data) {ListNode node = new ListNode(data);if(index < 0 || index > size()) {//抛自定义的异常throw new ListIndexOutOfException("你当前输入的索引有问题");}if(index == 0) {addFirst(data);return;}if(index == size()) {addLast(data);return;}ListNode cur = findIndex(index);node.next = cur;cur.prev.next = node;node.prev = cur.prev;cur.prev = node;}private ListNode findIndex(int index) {ListNode cur = head;while (index != 0){index--;cur = cur.next;}return cur;}
public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addFirst(1);myLinkedList.addFirst(0);myLinkedList.display();myLinkedList.addLast(7);myLinkedList.addLast(8);myLinkedList.display();System.out.println(myLinkedList.size());myLinkedList.addIndex(3,99);myLinkedList.display();}

2.7 查找关键字

        对链表进行遍历,然后将关键字key和链表数值进行比较,如果存在key关键字则返回true;反之则返回false;

        方法具体实现的代码如下:

 @Overridepublic boolean contains(int key) {ListNode cur = head;while (cur != null) {if (cur.value == key) {return true;}cur = cur.next;}return false;} 
public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addFirst(1);myLinkedList.addFirst(0);myLinkedList.addLast(7);myLinkedList.addLast(8);myLinkedList.addIndex(3,99);myLinkedList.display();System.out.println(myLinkedList.contains(1));}

         测试代码和执行结果如下:

2.8删除第一个关键字为key的节点

        思路:

        1、链表为空链表,不用操作;
        2、删除数据在第一个:首先让cur节点移动到第二个节点,其次判断新的链表是否只有一个节点

        2.1 如果只剩下cur这个节点,则让head指向null,让last指向null

        2.2让cur这个节点的prev指向null,其他的不变


        3、没有你要删除的数据,不用操作
        4、有你要删除的数据且不是第一个(cur节点是要删除的节点)

        4.1 删除数据最后一个:让last节点往前移一个单位

        4.2删除的数据不是最后一个:首先让cur的前一个节点的next域直接存cur下一个节点的地址,其次让cur下一个节点的prev域存放cur前一个节点的地址

        代码如下:

    @Overridepublic void remove(int key) {ListNode cur = head;while (cur != null) {if (cur.value == key){if(cur == head) {//整个链表的头结点为要删除的节点head = head.next;//head == nullif(head == null) {last = null;}else {head.prev = null;}}else {//链表的其他节点是要删除的cur.prev.next = cur.next;if(cur.next == null) {//要删除的是最后一个节点last = last.prev;}else {cur.next.prev = cur.prev;}}return;}else {cur =cur.next;}}}

2.9删除所有值为key的节点

        与删除第一次出现关键字为key的节点几乎是一模一样的;我们只需要遍历完整个链表,将return删掉就好。

        代码如下:

 @Overridepublic void removeAllKey(int key) {ListNode cur = head;while (cur != null) {if (cur.value == key){if(cur == head) {//整个链表的头结点为要删除的节点head = head.next;//head == nullif(head == null) {last = null;}else {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;}}

2.10清空链表

        1、只需要遍历整个链表,将每个节点的前驱与后继节点都置为null就好

    public void clear(){ListNode cur = head;while(cur != null) {cur.prev  = null;cur = cur.next;cur.prev.next = null;}}

         2、将链表的首节点和为节点指向null即可;

 public void clear() {head = null;last = null;}

 ps:本次内容就到这里了,如果你喜欢的话就请一键三连!!!

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

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

相关文章

计算机毕业设计 基于Web的铁路订票管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

Fiddler抓包工具之高级工具栏中的重定向AutoResponder的用法

重定向AutoResponder的用法 关于Fiddler的AutoResponder重定向功能&#xff0c;主要是时进行会话的拦截&#xff0c;然后替换原始资源的功能。 它与手动修该reponse是一样的&#xff0c;只是更加方便了&#xff0c;可以创建相应的rules&#xff0c;适合批处理的重定向功能。 …

tar文件覆盖漏洞 CVE-2007-4559

文章目录 前言原理例题 [NSSRound#7 Team]新的博客方法一 手搓文件名方法二 python脚本 前言 做到[NSSRound#6 Team]check(Revenge)时发现是tar文件覆盖&#xff0c;但是对概念和执行过程理解不够深就光光记住脚本&#xff0c;所以在做本题[NSSRound#7 Team]新的博客时打算重新…

数据链路层之VLAN基本概念和基本原理

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

笔记-基于CH579M模块通过网线直连电脑进行数据收发(无需网络)

刚学习&#xff0c;做个记录。 基于CH579M模块通过网线直连电脑进行数据收发(无需网络) 目录 一、工具1、CH579模块2、 网线3、电脑以及网络调试工具 二、操作步骤1、TCP/UDP等程序下载以及设置以太网IP2、网络断开3、检查以太网是否正常显示并稳定4、打开网络调试助手进行测试…

揭秘原型链:探索 JavaScript 面向对象编程的核心(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

【Android】Android Framework系列--Launcher3桌面图标加载流程

Launcher3桌面加载流程 Android Launcher3(简称Launcher&#xff09;启动后会加载桌面。基于Android12代码&#xff0c;分析一下桌面加载的流程。 一些相关的概念&#xff1a; WorkSpace&#xff1a;桌面。在桌面上可以添加快捷方式、Hoseat或Dock&#xff08;就是手机或者车…

项目中遇到的半导体公司

作为一个技术人&#xff0c;我并不是亲美&#xff0c;从技术的实事求是角度讲&#xff0c;不得不感叹欧美的半导体技术。他们的datasheet能学到的东西太多太多&#xff1b;我甚至佩服他们缜密的逻辑。从他们的文章中领悟我们技术到底有多low&#xff0c;没办法一个一个了解所有…

【重点】【双指针】11. 盛最多水的容器

题目 注意&#xff1a;二维接雨水&#xff0c;有墙的&#xff0c;有线的&#xff0c;着这个属于线的。 class Solution {public int maxArea(int[] height) {if (height.length < 2) {return 0;}int left 0, right height.length - 1, res 0;while (left < right) {…

avue-crud中时间范围选择默认应该是0点却变成了12点

文章目录 一、问题二、解决三、最后 一、问题 在avue-crud中时间范围选择&#xff0c;正常默认应该是0点&#xff0c;但是不知道怎么的了&#xff0c;选完之后就是一直是12点。具体问题如下动图所示&#xff1a; <template><avue-crud :option"option" /&g…

Linux文件系统 -- inode和block

目录 重要参数目录项fsck软连接&#xff0c;硬链接 重要参数 dumpe2fs /dev/sda1|more查看ext4文件元数据&#xff08;描述文件系统的数据&#xff09;&#xff0c;xfs_info查看xfs文件系统 superblock&#xff1a;超级块&#xff0c;记录此file system的整体信息&#xff0c…

每日一练:冒泡排序

1. 概述 冒泡排序&#xff08;Bubble Sort&#xff09;也是一种简单直观的排序算法。它重复地走访过要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换&#xff0c;也就是说该数列已经排…

Vue---Echarts

项目需要用echarts来做数据展示&#xff0c;现记录vue3引入并使用echarts的过程。 1. 使用步骤 安装 ECharts&#xff1a;使用 npm 或 yarn 等包管理工具安装 ECharts。 npm install echarts 在 Vue 组件中引入 ECharts&#xff1a;在需要使用图表的 Vue 组件中&#xff0c;引入…

深入理解Java中的锁机制

引言 大家好&#xff0c;我是小黑。今天咱们来聊聊Java中的锁机制&#xff0c;这可是并发编程的核心。你知道吗&#xff0c;在并发编程的世界里&#xff0c;正确地使用锁就像是掌握了一把神奇的钥匙&#xff0c;它能帮咱们在多线程的混战中保持秩序&#xff0c;防止数据被乱改…

opencv知识库:基于cv2.flip()函数对图像进行随机翻转(水平/垂直)

需求场景 欲对RGB格式的lena图像进行随机翻转&#xff0c;要求这些图像不翻转、水平翻转、垂直翻转的概率都为1/3。 功能代码 import cv2 import random# 读取并展示图像 img cv2.imread("lena.jpg") cv2.imshow(lena, img) cv2.waitKey(0)for i in range(6): #…

Hdoop学习笔记(HDP)-Part.18 安装Flink

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

头歌JUnit单元测试相关实验入门

一、入门实验 1.1第一个Junit测试程序 任务描述 请学员写一个名为testSub()的测试函数&#xff0c;来测试给定的减法函数是否正确。 相关知识 Junit编写原则 1、简化测试的编写&#xff0c;这种简化包括测试框架的学习和实际测试单元的编写。 2、测试单元保持持久性。 3、利用…

短线买入卖出有哪些交易技巧?

前面两节课&#xff0c;我们认识了短线交易&#xff0c;知道了短线交易常见的买入卖出时机&#xff0c;这节课&#xff0c;我们来讲解一下短线买入卖出的一些交易技巧。话不多时&#xff0c;直接进入重点&#xff01; 一、短线交易要果断 短线波动快&#xff0c;在出现买卖信号…

排序算法总结(Python、Java)

Title of Content 1 冒泡排序 Bubble sort&#xff1a;两两交换&#xff0c;大的冒到最后概念排序可视化代码实现Python - 基础实现Python - 优化实现Java - 优化实现C - 优化实现C - 优化实现 2 选择排序 Selection sort&#xff1a;第i轮遍历时&#xff0c;将未排序序列中最小…

反序列化漏洞详解(一)

目录 一、php面向对象 二、类 2.1 类的定义 2.2 类的修饰符介绍 三、序列化 3.1 序列化的作用 3.2 序列化之后的表达方式/格式 ① 简单序列化 ② 数组序列化 ③ 对象序列化 ④ 私有修饰符序列化 ⑤ 保护修饰符序列化 ⑥ 成员属性调用对象 序列化 四、反序列化 …