Java进阶(7)——手动实现LinkedList 内部node类的实现 增删改查的实现 toString方法 源码的初步理解

目录

  • 引出
  • 从ArrayList到Linkedlist
    • 手动实现ArrayList
    • 从ArrayList到LinkedList
  • 总体设计
    • Node类
    • Node的方法:根据index找node
  • 增删改查的实现
    • 增加元素
    • 删除元素
    • 修改元素
    • 查询元素
  • toString方法
  • 完整代码
    • List接口类
    • LinkedList的实现
    • 测试类
  • 总结

引出


1.linkedList的节点,当前,上一个,下一个的思想;
2.根据index找node的方法,根据index确定从头部还是尾部;
3.linkedlist的增删改查的实现,本质是改变节点的信息;
4.递归方法实现自定义链表的toString方法;

从ArrayList到Linkedlist

在这里插入图片描述

手动实现ArrayList

Java进阶(3)——手动实现ArrayList & 源码的初步理解分析 & 数组插入数据和删除数据的问题

在这里插入图片描述

从ArrayList到LinkedList

如果发生对表的一些插入和删除操作,特别是对表的前端进行,那么数组就不是一种好的选择。另一种数据结构:链表(linked list)。

在这里插入图片描述

链表由一系列节点组成,这些节点不必在内存中相连。每一个节点均含有表元素和到包含该元素后继元的节点的链(link)。我们称之为next链。最后一个单元的next链引用null。

在这里插入图片描述

链表的插入

在这里插入图片描述

让每一个节点持有一个指向它在表中的前驱节点的链,我们称之为双链表(doubly linked list)。

在这里插入图片描述

总体设计

在这里插入图片描述

在考虑设计方面,我们将需要提供三个类:
1.MyLinkedList类本身,它包含到两端的链、表的大小以及一些方法。
2.Noe类,它可能是一个私有的嵌套类。一个节点包含数据以及到前一个节点的链和到下一个节点的链,还有一些适当的构造方法。
3.LinkedListIterator类,该类抽象了位置的概念,是一个私有类,并实现接口Iterator。它提供了方法next、hasNext和remove的实现。

标记节点:

前端创建一个额外的节点,逻辑上代表开始的标记。这些额外的节点有时候就叫作标记节点(sentinel node);特别地,在前端的节点有时候也叫作头节点(header node),而在末端的节点有时候也叫作尾节点(tail node)

在这里插入图片描述

Node类

私有的内部类

  • 当前节点,前置节点,后续节点;
  • 表示链表中的一个基本元素;

在这里插入图片描述

/*** 内部类,节点;属性,当前节点,前置节点,后续节点* @param <T>*/private static class Node<T> {T item; // 当前的节点Node<T> next; // 下一个节点Node<T> prev; // 前置节点Node(Node<T> prev,T element,Node<T> next) {this.item = element;this.prev = prev;this.next = next;}@Overridepublic String toString() {String nextStr = null;if (next!=null){nextStr = next.item.toString();}String prevStr = null;if (prev!=null){prevStr = prev.item.toString();}return "Node{" +" prev=" + prevStr +",item=" + item +", next=" + nextStr +'}';}}

在这里插入图片描述

Node的方法:根据index找node

思路:从头部开始找,进行循环

    public Node<T> NodeByIndex(int index){Node<T> x = first; // 从头部开始找for (int i = 0; i<index;i++){x = x.next;}return x;}

源码采用如下策略

  • 1.根据index和list的size确定从头部还是尾部找;
  • 2.根据index找node节点;

在这里插入图片描述

分析:

降低了复杂度:

如果都从头部找,时间复杂度就是O(i),在最极端的情况下,根据index找最后一个,时间复杂度是O(N);

如果是先确定从头部找,还是从尾部找,则时间复杂度最大是O(N/2);

增删改查的实现

增加元素

最简单的情况,都是从尾部新增元素

  • 1.新的节点的上一个节点为之前的尾部节点;
  • 2.新的尾部节点为当前新增的节点;
  • 3.如果是第一个节点,则需要把first设置为当前的节点
  • 4.链表的size+1;

在这里插入图片描述

    @Overridepublic void add(T e) {Node<T> l = last;Node<T> newNode = new Node<>(l, e, null); // 新增的节点,尾部添加last = newNode;if (l==null){// 是第一个节点first = newNode;System.out.println("FirstNode --->"+first);}else {l.next = newNode;System.out.println("Add {"+e+"} ---->"+l);}size++;}

更一般的情况如下,插入一个元素

在这里插入图片描述

删除元素

删除头部?尾部?中间

  • 1.如果删除的是头部节点,则让被删除的节点的下一个节点为first节点;
  • 2.如果删除的尾部节点,则让被删除的节点的上一个节点的下一个节点为null;
  • 3.如果删除的是中间的节点,让该节点的前置节点的下一个节点指向该节点的下一个节点;

在这里插入图片描述

    @Overridepublic void remove(int index) {// 找到要删除的节点,前置节点,后续节点// 1.如果删除的是头部节点if (index==0){first = NodeByIndex(index+1);return;}// 2.如果不是头部节点Node<T> tNode = NodeByIndex(index); // 当前节点Node<T> prev = tNode.prev; // 当前节点的上一个节点Node<T> next = tNode.next; // 当前节点的下一个节点if (next==null){// 删除的是尾部节点prev.next = null;return;}// 删除的是中间的某个节点// 让该节点的前置节点的下一个节点指向该节点的下一个节点prev.next = next;next.prev = prev;size--;}

修改元素

被修改的节点的节点关系不变,只需要把当前节点的元素变为最新的元素即可

在这里插入图片描述

代码实现

在这里插入图片描述

查询元素

调用node方法即可

    @Overridepublic T get(int index) {// 索引不能大于等于sizeif (index<0 || index>=size){throw new IndexOutOfBoundsException("LinkedList的索引越界");}return NodeByIndex(index).item;}

toString方法

在这里插入图片描述

完整代码

List接口类

package com.tianju.book.jpa.mlist;/*** 手工打造ArrayList*/
public interface MyList<T> {/*** 增加一个元素,涉及到容量的变化*/void add(T t);/*** 根据索引删除元素* @param index 要删除元素的索引,超过索引?索引不存在?*/void remove(int index);/*** 根据索引修改一个元素* @param index 要修改的索引* @param t 修改的值*/void set(int index,T t);/*** 根据索引获取元素* @param index 索引* @return 获取的元素*/T get(int index);int size();String toString();}

LinkedList的实现

package com.tianju.book.jpa.myLinkList;import com.tianju.book.jpa.mlist.MyList;public class MyLinkedList<T> implements MyList<T> {int size = 0;Node<T> first; // 头部节点Node<T> last; // 尾部节点/*** 内部类,节点;属性,当前节点,前置节点,后续节点* @param <T>*/private static class Node<T> {T item; // 当前的节点Node<T> next; // 下一个节点Node<T> prev; // 前置节点Node(Node<T> prev,T element,Node<T> next) {this.item = element;this.prev = prev;this.next = next;}@Overridepublic String toString() {String nextStr = null;if (next!=null){nextStr = next.item.toString();}String prevStr = null;if (prev!=null){prevStr = prev.item.toString();}return "Node{" +" prev=" + prevStr +",item=" + item +", next=" + nextStr +'}';}}@Overridepublic void add(T e) {Node<T> l = last;Node<T> newNode = new Node<>(l, e, null); // 新增的节点,尾部添加last = newNode;if (l==null){// 是第一个节点first = newNode;System.out.println("FirstNode --->"+first);}else {l.next = newNode;System.out.println("Add {"+e+"} ---->"+l);}size++;}public Node<T> NodeByIndex(int index){Node<T> x = first; // 从头部开始找for (int i = 0; i<index;i++){x = x.next;}return x;}@Overridepublic void remove(int index) {// 找到要删除的节点,前置节点,后续节点// 1.如果删除的是头部节点if (index==0){first = NodeByIndex(index+1);return;}// 2.如果不是头部节点Node<T> tNode = NodeByIndex(index); // 当前节点Node<T> prev = tNode.prev; // 当前节点的上一个节点Node<T> next = tNode.next; // 当前节点的下一个节点if (next==null){// 删除的是尾部节点prev.next = null;return;}// 删除的是中间的某个节点// 让该节点的前置节点的下一个节点指向该节点的下一个节点prev.next = next;next.prev = prev;size--;}@Overridepublic void set(int index, T element) {// 索引不能大于等于sizeif (index<0 || index>=size){throw new IndexOutOfBoundsException("LinkedList的索引越界");}Node<T> tNode = NodeByIndex(index); // 当前节点T oldVal = tNode.item; // 获取旧的元素tNode.item = element; // 把当前节点的元素设置成新的
//        System.out.println(oldVal);}@Overridepublic T get(int index) {// 索引不能大于等于sizeif (index<0 || index>=size){throw new IndexOutOfBoundsException("LinkedList的索引越界");}return NodeByIndex(index).item;}@Overridepublic int size() {return size;}/*** 为了实现toString方法*/String str = "null-->";// 通过第一个节点递归调用,获得LinkedList的链private String recursion(Node<T> first){if (!str.contains(first.item.toString())){str = str + first.item;}if (first.next==null){return str + "-->null";}str = str + "-->" +  first.next.item.toString();first = first.next;return recursion(first);}// 在每次调用后把str归位;private void backStr(){str = "null-->";}@Overridepublic String toString() {String recursion = recursion(first);backStr();return "MyLinkedList{ " + recursion +" }";}
}

测试类

package com.tianju.book.jpa.myLinkList;import org.hibernate.event.spi.SaveOrUpdateEvent;import java.util.List;public class MyLinkedListTest1 {public static void main(String[] args) {MyLinkedList<String> list = new MyLinkedList<>();list.add("PET1");list.add("PET2");list.add("PET3");System.out.println("**********");System.out.println(list);list.add("PET4");System.out.println(list);System.out.println(list.size());//        System.out.println(list.get(4));
//        list.remove(0);
//        System.out.println("删除头部节点");
//        System.out.println(list);
//
//        System.out.println("删除尾部节点");
//        list.remove(3-1);
//        System.out.println(list);System.out.println("删除中间的节点");list.remove(2);System.out.println(list);System.out.println("进行set");list.set(0, "SHI1");System.out.println(list);}
}

在这里插入图片描述


总结

1.linkedList的节点,当前,上一个,下一个的思想;
2.根据index找node的方法,根据index确定从头部还是尾部;
3.linkedlist的增删改查的实现,本质是改变节点的信息;
4.递归方法实现自定义链表的toString方法;

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

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

相关文章

从0开始学Python 01

Python学习01 文章目录 Python学习0101-字面量02-注释注释的分类1.单行注释2.多行注释 03-变量04-数据类型1.type()语句 05-数据类型转换常见的转换语句代码演示 06-标识符标识符命名规则1.内容限定&#xff1a;2.大小写敏感&#xff1a;3.不能使用关键字代码示例&#xff1a; …

MySQL Connection not available.

Mysql 报错 最近部署在服务器上的mysql总是报这种错。 但是在服务器上&#xff0c;使用命令行是可以登录进mysq的。 cursor db.cursor() File “/home/ubuntu/miniconda3/envs/chatbot_env/lib/python3.9/site-packages/mysql/connector/connection_cext.py”, line 700, in …

基于JJWT理解JWT,JWS,JWE

JWT &#xff0c; 全写JSON Web Token, 是开放的行业标准RFC7591&#xff0c;用来实现端到端安全验证. 从开发者理解的角度来说&#xff1a; JWT 是一个定义传递信息的标准JWT 的Token是一个Base64编码的字符串&#xff0c; 类似 eyJhbGciOiJIUzI1NyJ9.eyJzdWIiOiJvc2NhciJ9.…

[Python进阶] 类的设计模式

4.11 设计模式 在Python中&#xff0c;类的设计模式是指一种通用的解决方案或设计模板&#xff0c;针对特定的问题或需求构建类结构&#xff0c;并提供相关的方法和属性。这些设计模式可以帮助开发人员遵循最佳实践、提高代码质量、增强可读性、降低维护成本。 需要注意的是&a…

房屋结构健康监测,科技助力让建筑更安全

房屋建筑是人们赖以生存的场所&#xff0c;然而当前我国许多房屋已经达到了使用寿命的中期&#xff0c;房屋的安全系数逐年降低&#xff0c;风险也随着时间的推移而累积。长期以来&#xff0c;我国的房屋普遍存在寿命短、隐患多的问题&#xff0c;“重建设&#xff0c;轻管理”…

探索PDF校对:为何这是现代数字文档的关键步骤

在今日的数字化浪潮中&#xff0c;文档的创建与分享从未如此频繁。尤其是PDF&#xff0c;作为一个普遍接受的标准文件格式&#xff0c;其在企业、学术和日常生活中的应用已经无处不在。但随之而来的挑战是如何确保文档的准确性和专业性。让我们深入探索PDF校对的重要性以及它为…

[国产MCU]-W801开发实例-定时器

定时器 文章目录 定时器1、定时器介绍2、定时器驱动API3、定时器使用示例本文将详细介绍如何使用W801的定时器模块。 1、定时器介绍 W801的定时器包含一个32-bit自动加载的计数器,该计数器由系统时钟经过分频后驱动。 W801有 6路完全独立定时器。实现了精确的定时时间以及中断…

element-ui中的el-table的summary-method(合计)的使用

场景图片&#xff1a; 图片1&#xff1a; 图片2&#xff1a; 一&#xff1a;使用element中的方法 优点&#xff1a; 直接使用summary-method方法&#xff0c;直接&#xff0c;方便 缺点&#xff1a; 只是在表格下面添加了一行&#xff0c;如果想有多行就不行了 1&#xff1a;h…

一、MQ的基本概念

1、初识MQ MQ全称是Message Queue&#xff0c;消息队列&#xff0c;多用于系统之间进行异步通信。队列的概念数据结构中有详细介绍过&#xff0c;先进先出&#xff0c;消息队列就是存储消息的数据结构。 同步调用和异步调用两者之间的区别&#xff1a; 同步调用&#xff1a;发…

opencv-dnn

# utils_words.txt 标签文件 import osimage_types (".jpg", ".jpeg", ".png", ".bmp", ".tif", ".tiff")def list_images(basePath, containsNone):# return the set of files that are validreturn list_file…

gdb 条件断点

条件断点&#xff0c;顾名思义就是有条件才会触发的断点&#xff0c;一般设置此类断点形如&#xff1a;b xxx if xxx&#xff0c;如&#xff1a; 要触发此断点则需要 is_created 0。打完断点我们也可以用 info b 查看一下当前已经设置的断点信息&#xff0c;如&#xff1a; 断…

【JavaSE】接口

文章目录 接口的概念接口的使用接口的特性实现多个接口接口间的继承抽象类和接口的区别 接口的概念 接口就是公共的行为规范标准&#xff0c;大家在实现时&#xff0c;只要符合规范标准&#xff0c;就可以通用。在Java中&#xff0c;接口可以看成是&#xff1a;多个类的公共规…

Spring核心配置步骤-完全基于XML的配置

Spring框架的核心配置涉及多个方面&#xff0c;包括依赖注入&#xff08;DI&#xff09;、面向切面编程&#xff08;AOP&#xff09;等。以下是一般情况下配置Spring应用程序的核心步骤&#xff1a; 1. **引入Spring依赖&#xff1a;** 在项目的构建工具&#xff08;如Maven、…

23 WEB漏洞-文件上传之解析漏洞编辑器安全

目录 几种中间件解析漏洞简要演示几种常见WEB编辑器简要演示几种常见CMS文件上传简要演示贴近实际应用下的以上知识点演示 各个WEB编辑器安全讲解 https://navisec.it/编辑器漏洞手册/ 各个CMS文件上传简要讲解 wordpress&#xff0c;phpcms&#xff0c; 几种中间件解析漏洞简…

JDK 新版本中都有哪些新特性?

面试回答 JDK 8 推出了 Lambda 表达式、Stream、Optional、新的日期 API 等 JDK 9 中推出了模块化 JDK 10 中推出了本地变量类型推断 JDK 12 中增加了 switch 表达式 JDK 13 中增加了 text block JDK 14 中增加了 Records JDK 15 中增加了封闭类 JDK 17 中扩展了 switch…

探索未知世界:桌面端3D GIS引领地理信息新时代

近年来&#xff0c;桌面端的三维地理信息系统&#xff08;3D GIS&#xff09;在地理信息领域迎来了显著的发展&#xff0c;为我们带来了更深入、更丰富的地理空间认知和数据分析体验。从城市规划到环境保护&#xff0c;从资源管理到应急响应&#xff0c;桌面端的3D GIS正逐渐成…

Mysql定时备份事件

创建了一个名为backup_database的定时任务&#xff0c;每天自动在当前时间的后一天开始执行。备份数据库的代码使用mysqldump命令将数据库导出为sql文件保存在指定的备份目录中。 需要注意的是&#xff0c;上述代码中的用户名 (username)、密码 (password)、主机名 (hostname) …

Java程序设计——在一个给定的字符串中查找并解析姓名、出生日期、个人网站、身高和体重信息,并输出相应的结果

package ch4;public class FindMess {public static void main(String[] args) {String mess "姓名:张三 出生时间:1989.10.16。个人网站:http://www.zhang.com。身高:185 cm,体重:72 kg";int index (int)(mess.indexOf(":")); //mess调用indexOf(Stri…

如何解决跨域问题

跨域问题是指在浏览器中发起跨域请求时&#xff0c;由于浏览器的同源策略限制&#xff0c;导致请求被拒绝或无法正常发送和接收数据。同源策略要求两个页面具有相同的协议、域名和端口号&#xff0c;否则就会出现跨域问题。 为了解决跨域问题&#xff0c;可以采取以下方法之一…

git Update failed cannot lock ref

报错详情 解决方案 百度了很多方案&#xff0c;过滤出了有效方案 去该项目下的.git文件里找到报错文件&#xff0c;本例中即为&#xff1a;.git/refs/tags/pre-RELEASE-PRE-20230817-03 删除该文件&#xff0c;重新pull&#xff0c;pull成功问题解决