手敲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; 精…

【双指针】283. 移动零

题目 两种方法时间复杂度相同都是O(n)&#xff0c;方法2操作更少一些 1.解法1: 有优化空间 class Solution {public void moveZeroes(int[] nums) {int slow 0, fast 0;while (fast < nums.length) {if (nums[fast] ! 0) {if (slow fast) {slow;fast;} else {nums[slow…

网页开发 HTML

目录 HTML概述 HTML结构 HTML标签语法 基本标签 标题标签 换行标签 段落标签 文本格式化标签 特殊符号 div和span标签 超链接标签 锚点 img标签 列表标签 表格标签 表单标签 HTML概述 HTML&#xff0c;即超文本标记语言&#xff08;HyperText Markup Language …

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…

【已解决】if lock.acquire(block, timeout):KeyboardInterrupt

问题描述 Traceback (most recent call last): File "/media/visionx/monica/project/ResShift/app.py", line 134, in <module> demo.launch(shareFalse) File "/home/visionx/anaconda3/envs/ResShift/lib/python3.9/site-packages/gradio/bloc…

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;引入…

Linux 设置程序开机自启动的方法

目录 前言开机自启动参考 前言 CentOS Linux release 7.9.2009 (Core) 开机自启动 shell> vim /etc/rc.d/rc.local添加开机后执行的命令 sh /xxx/xxx.sh参考 https://www.cnblogs.com/xlmeng1988/archive/2013/05/22/3092447.html

软件工程导论学习资料

软件工程的概述&#xff1a;软件工程就是为了经济地获得可靠的且能在实际机器上有效地运行的软件&#xff0c;而建立和使用完善的工程原理。Software engineering is to establish and use sound engineering principles in order to economically obtain reliable software th…

深入理解Java中的锁机制

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

【JavaSE】API(学习笔记)

一、Math 包含执行基本数字运算的方法没有构造方法&#xff0c;但方法是静态的&#xff0c;可以用类名直接调用 1、Math类常用方法 1&#xff09;绝对值&#xff1a;abs public static int abs(int a)2&#xff09;小数的最近整数&#xff1a;ceil(最小整数) / floor(最大整…