java实现单链表

链表是java数据结构中一种很基础很常见却也很重要的数据结构,JDK中许多内置jar包基于单链表实现,比如像我们熟悉的linkedList等,为什么要使用链表呢?

我们知道java中很多集合的底层是基于数组实现的,数组有一个很重要的结构就是索引,通过索引可以快速定位数据,并对数据进行删除等操作,但问题是,我们的业务中,数组有自身的局限性,如果知道索引还好,如果不知道索引就需要一个个遍历查找,然后再进行操作,假如是删除一个数据,对于数组来说,要进行的操作是:根据索引定位到数据,然后删除这条数据,然后数组中的数据进行重新位置的移动,平均来看,这个时间复杂度应该是2logN,尤其是重新调整位置使得性能开销较大,

我们看看下面这张链表的图:

在这里插入图片描述

链表的结构很简单,就是一个个节点连接在一起,形成一个完整的链条,每个节点包含2部分,数据域,和一个指向下一个节点引用的指针next,具体的更详细的大家可以参考相关资料解释,再说说删除操作,同样需要找到数据所在的位置,然后进行删除,不同的是,删除的时候,链表只需要改变一下前后节点的引用关系即可,就完成了节点的删除,而没有像数组那样触发一次全部数据的移动,从这个描述来看,链表在进行删除的时候,速度比数组快,

链表的分类有很多种,比如单链表,双端链表,双向链表,单向链表等,下面说说单链表的具体实现,单链表是其他链表的基础,掌握了单链表实现其他的就好理解了,下面直接上代码,可以结合注释看,

class ListNode<T> {private int foot;		//根节点索引位置private int count;		//代表链表程度private Node root;		//标识根节点//链接点类,内部方法实现,外部使用private class Node{private T data;		//数据信息private Node next;	//下一个节点引用public Node(T data) {this.data = data;}//添加节点private void add(T data){if(this.next == null){this.next = new Node(data);		//如果当前节点的next为null,直接创建一个新的节点}else {this.next.add(data);			//否则进行递归调用,直到最后在某个为空的节点创建一个新节点}}//删除节点1public void remove(Node previous, int index){if(ListNode.this.foot++ == index){previous.next = this.next;	//this表示当前要删除的节点this.next = null;	ListNode.this.count--;return;}else{this.next.remove(this,index);	//递归删除}}//删除节点2 public void remove(Node previous, T data){if(this.data.equals(data)){previous.next = this.next;this.next = null;ListNode.this.count--;return ;}else{if(this.next != null){this.next.remove(this,data);}else{return;}}}//修改数据  -- 新数据替换旧数据public void replace(T oldData,T newData){if(this.data.equals(newData)){this.data = newData;}else{this.next.replace(oldData, newData);  //递归修改,寻找当前节点下一个节点,直到某个节点的值匹配入参}}//修改数据  -- 利用索引修改public void replace(int index,T newData){if(ListNode.this.foot++ == index){	//找到了某个值的索引和传入的索引相同,直接替换this.data = newData;}else{this.next.replace(index, newData);}}//查询public T get(int index){if(ListNode.this.foot++ == index){return this.data;}else{return this.next.get(index);}}//链表是否包含某个节点public boolean contains(T data){if(this.data.equals(data)){	//如果当前的这个data正好和传入的data匹配return true;}else{//如果当前的这个不匹配,则需要查找下一个节点if(this.next == null){return false;}else{return this.next.contains(data);}}}}public ListNode() {}//检查链表是否为空public boolean isEmpty(){if(count == 0 || this.root == null){return true;}else{return false;}}//获取链表的长度public int size(){return this.count;}//添加public void add(T data){if(this.isEmpty()){ //如果链表为空,新建一个节点this.root = new Node(data);}else{this.root.add(data);}this.count++;}//删除  -- 按照索引删除public void remove(int index){if(this.isEmpty()){return;}if(index < 0 || this.count <= index){return ;}if(index == 0){	//想要删除根节点Node temp = this.root;this.root = this.root.next;temp.next = null;this.count--;return ;}else{this.foot = 0;this.root.remove(this.root, index);}}//根据传入的数值删除public void remove(T data){if(this.isEmpty()){return;}if(this.root.data.equals(data)){	//如果删除的正好是根节点Node temp = this.root;this.root = this.root.next;temp.next = null;this.count--;return ;}else{this.root.remove(this.root, data);}}//修改  -- 根据索引修改public void replace(int index,T newData){if(this.isEmpty()){return;}if(index < 0 || this.count <= index){return ;}this.foot = 0;this.root.replace(index, newData);}//修改 -- 新老数据替换public void replace(T oldData,T newData){if(this.isEmpty()){return;}this.root.replace(oldData, newData);}//查询 --- 根据索引查找public T get(int index){if(this.isEmpty()){return null;}this.foot = 0;return this.root.get(index);}//是否包含public boolean contains(T data){if(this.isEmpty()){return false;}return this.root.contains(data);}//打印  toArraypublic Object[] toArray(){if(this.isEmpty()){return null;}int count = this.count;Object[] retVal = new Object[count];for(int i=0;i<count;i++){retVal[i] = this.get(i);}return retVal;}
}

下面是测试代码,

public static void main(String[] args) {ListNode<String> myList = new ListNode<String>();myList.add("a");myList.add("b");myList.add("c");myList.add("d");myList.add("e");myList.add("f");System.out.println("第三个元素是:" + myList.get(3));myList.remove(3);System.out.println("删除之后,第三个元素是:"+myList.get(3));System.out.println("-----------替换之后--------");myList.replace(1, "b11");System.out.println(myList.get(1));}

运行一下上述main函数,我们随意写了几个测试方法,控制台打印结果:

在这里插入图片描述

大家可以看到,代码中大量使用了递归来实现,主要是想深入的使用一下递归,同时使用递归来实现节省了较多的代码量,而且比较容易理解,单链表的实现到此结束,谢谢观看!

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

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

相关文章

sql 两表数据合并_多表查询SQL语句

本篇文章中主要讲述以下内容&#xff1a;一、表的加法合并两张表的过程&#xff1a;然后运用sql语句&#xff1a;select 课程号,课程名称 from course union select 课程号,课程名称 from course1以上子句会把两个表中重复数据删除。要想不删除重复的行&#xff0c;则需要在上面…

angularjs增删改查数据_MongoDB数据读写操作(增删改查)总结

《大数据和人工智能交流》头条号向广大初学者新增C 、Java 、Python 、Scala、javascript 等目前流行的计算机、大数据编程语言&#xff0c;希望大家以后关注本头条号更多的内容。一、在执行mongo.exe文件后&#xff0c;进入MongoDB的shell 操作1、创建一个数据库use users2、查…

SpringAop与AspectJ的联系与区别____比较分析 Spring AOP 和 AspectJ 之间的差别

SpringAop与AspectJ的联系与区别 区别 AspectJ AspectJ是一个面向切面的框架&#xff0c;它扩展了Java语言。AspectJ定义了AOP语法&#xff0c;所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。 spring aop Spring提供了四种类型的Aop支持 * 基于经典的…

ssrf漏洞内网渗透_渗透小白看了也能明白的SSRF

什么是SSRF含义服务器端请求伪造&#xff08;SSRF&#xff09;是指攻击者能够从易受攻击的Web应用程序发送精心设计的请求的对其他网站进行攻击。(利用一个可发起网络请求的服务当作跳板来攻击其他服务)攻击者能够利用目标帮助攻击者访问其他想要攻击的目标攻击者要求服务器为他…

高并发之服务降级和服务熔断____服务降级、熔断、限流的区别

高并发之服务降级和服务熔断 服务降级&#xff1a; 服务压力剧增的时候根据当前的业务情况及流量对一些服务和页面有策略的降级&#xff0c;以此环节服务器的压力&#xff0c;以保证核心任务的进行。 同时保证部分甚至大部分任务客户能得到正确的相应。也就是当前的请求处理…

Controller数据导出Excel 详细教程——easypoi-base,easypoi-web,easypoi-annotation

Controller获取数据导出Excel&#xff0c;详细教程 1&#xff1a;导入对应依赖 <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-base</artifactId><version>4.1.3</version></dependency><dependency&g…

01 - java 开始

Java 的优势 java适合做web后台 java配置环境的时候 java的安装目录&#xff1a;JAVA_HOMEjdk的安装目录&#xff1a;%JAVA_HOME%\bin java的执行机制 先将.java的文件用 javac 编译成 .class的字节码文件再将这些 .class 的字节码文件用 java 执行&#xff08;执行的是文…

15 - java 继承

java继承 This > Son Super > Father Object 类是所有类的顶级父类 只要创建一个类默认都会继承这个顶级父类 – Object 在子类继承父类里面 构造器必须先构造一个父类&#xff08;先有爸爸&#xff0c;才有儿子&#xff09;&#xff0c;必须首先构造父类&#xff0…

easyPOI基本用法详解

文章目录easyPOI基本用法1.Excel文件的简单导入和导出1.1准备工作1.2导入1.3导出1.4图片的导出1.5图片的导入1.6excel模板导出文件1.7excel转html2.Word文件导出2.1使用word模板导出2.2使用word模板导出多页3.excel导入时验证3.1环境准备3.2实战演练3.3注意事项easyPOI基本用法…

16 - java 类加载顺序

类的加载顺序 类对象、静态变量是存在元空间的方法区&#xff0c;实例对象是new出来的&#xff0c;放在堆里面的 一个类加载到内存的完整过程 加载父类 --> 加载子类 --> 构造父类 --> 构造子类 class文件要从磁盘加载到内存形成对象 内存靠地址去取寻址 – 随机存…

360全景倒车影像怎么看_别克关怀-后视镜和倒车影像 倒车时到底看哪个

很多人在考驾照的时候&#xff0c;倒车倒的都很熟练&#xff0c;但是一上路就不行了。一方面&#xff0c;这是因为道路上的状况多变&#xff0c;时常有行人经过&#xff0c;另一方面&#xff0c;上路之后&#xff0c;遇见的停车位千奇百怪&#xff0c;什么样子的都有&#xff0…

17 - 引用类型比较内容

引用数据类型比较 引用数据类型直接比较一定是 false --> 比较的是它俩的地址 Animail a1 new Animal(); Animail a2 new Animal(); System.out.println(a1 a2); //false特殊的 String String s1 "a"; String s2 "a"; System.out.println(s1 s…

springboot使用jxls导出excel___(万能通用模板)--- SpringBoot导入、导出Excel文件___SpringBoot整合EasyExcel模板导出Excel

springboot使用jxls导出excel 实现思路&#xff1a; 首先在springBoot(或者SpringCloud)项目的默认templates目录放入提前定义好的Excel模板&#xff0c;然后在具体的导出接口业务代码里通过IO流加载到这个Excel模板文件&#xff0c;读取指定的工作薄(也就是excel左下角的Shee…

idea(mac) 使用收集

其实 idea 后面的 webstorm phpstorm pycharm… 都大同小异 idea 使用积累1. 设置代码区字体大小2. command​ 滚轮改变字体大小3. 去掉代码区中间的白线4. 查看项目配置5. 自动删除类中无用包、自动导入包6. 显示行号和方法分隔符7. 提示的时候忽略大小写8. 统一显示 utf - 8…

epp是什么意思_什么是1K/2K/3K注塑?

ABC小词条的出现是因为公众号后台大家留言提问的名词很多&#xff0c;我们每周挑一个成本分析相关的小知识点&#xff0c;可能是工艺&#xff0c;成本方法&#xff0c;产品方面等话题&#xff0c;来做一个简短的ABC解释&#xff0c;如有错误欢迎指出。文末会提出一个问题&#…

facebook对话链接_Facebook已开源其最新的聊天机器人Blender

它是一种更具人性化的聊天机器人&#xff0c;并击败了Google成为世界上最好的聊天机器人> Photo by Alex Haney on Unsplash4月29日&#xff0c;Facebook AI Research(FAIR)宣布已构建并开源了一个新的聊天机器人Blender。最先进的开源聊天机器人Facebook AI拥有开源的Blend…

基于easypoi实现自定义模板导出excel

项目中需要做一个统计报表功能&#xff0c;实现各种Excel报表数据导出。要求表头能够动态配置&#xff0c;表数据通过存储过程实现&#xff0c;也要求能够动态配置。 技术选型&#xff1a; 由于之前在项目中使用过easypoi&#xff0c;相对于原生apache poi&#xff0c;能够用很…

vb6 datagrid表格垂直居中_老板不喜欢看你的Excel表格,学完这些美化技巧,早日升职加薪...

Excel报表是工作中经常要制作的&#xff0c;给老板看的表格越是简单明了越好&#xff0c;工作得到认可&#xff0c;给你升职加薪&#xff0c;如果你发给你老板的表格是这样的&#xff1a;对齐方式各种各样&#xff0c;数据看起来也很枯燥&#xff0c;仅需简单4点&#xff0c;轻…

Java接口修饰符详解

接口就是提供一种统一的”协议”&#xff0c;而接口中的属性也属于“协议”中的成员。它们是公共的&#xff0c;静态的&#xff0c;最终的常量。相当于全局常量。抽象类是不“完全”的类&#xff0c;相当于是接口和具体类的一个中间层。即满足接口的抽象&#xff0c;也满足具体…

查看论坛隐藏链接_软连接与硬链接的区别

点击上方蓝色“后端开发杂谈”关注我们, 专注于后端日常开发技术分享硬链接与软连接的联系与区别文件都有文件名和数据, 这在Linux上被分为两部分: 用户数据(user data) 与 元数据(metadata). 用户数据, 即文件数据块( data block), 数据块是记录文件真实内容的地方; 元数据是文…