数据结构——链表的实现(Java版)

目录

一、链表

二、代码实现

1.创建结点

2.构造函数

3.链表的相关属性

4.添加虚拟节点

5.判断链表是否为空

6.添加方法

(1)在头部添加

(2)在尾部添加

(3)在索引位置添加

(4)对头插法和尾插法代码进行简化(调用任意位置添加的方法)

7.打印链表(遍历,重写toString方法)

8.获取链表元素个数(链表长度)

9.获取链表结点

(1)获取头结点

(2)获取尾结点

(3)获取指定位置结点

10.判断结点是否存在

11.删除结点

(1)删除头结点

(2)删除尾节点

(3)在指定位置删除结点

(4)删除元素

(5)不使用虚拟节点删除


一、链表

链表是真正的动态数据结构,也是最简单的动态数据结构。

动态数据结构还有:二叉树,trie等

优点:不需要处理固定容量的问题,真正的动态

缺点:丧失了随机访问的能力

学习链表有助于更深理解引用和递归

二、代码实现

1.创建结点

使用内部类来创建结点

//使用内部类——创建结点class Node<T>{T data;//节点本身Node next;//指向下个节点

2.构造函数

两个构造函数(传入的参数不同)

public Node(T data){this.data=data;this.next=null;}public Node(T data,Node next){this.data=data;this.next=null;}}

3.链表的相关属性

头结点和结点个数(链表长度)

private Node head;//头结点private int size;//表示链表中有多少个结点

4.添加虚拟节点

public SelfLinkedList(){//创建一个虚拟头结点Node dummyHead=new Node(Integer.MIN_VALUE);this.head=dummyHead;this.size=0;dummyHead.next=head;}

5.判断链表是否为空

public boolean isEmpty(){return this.size==0;}

6.添加方法

(1)在头部添加

public void addHead(T data){//创建一个节点Node node= new Node(data);//挂接node.next=this.head;this.head=node;//更新sizethis.size++;}

(2)在尾部添加

public void addTail(T data){Node node=new Node(data);//针对空链表做处理if(this.head==null){this.head=node;this.size++;return;}Node curNode=this.head;while(curNode.next!=null){curNode=curNode.next;}curNode.next=node;this.size++;}

(3)在索引位置添加

//在任意位置添加public void add(int index,T data){//判断index是否有效if(index<0||index>this.size){throw new IllegalArgumentException("index is invalid");}//创建一个节点Node node= new Node(data);//特殊处理1:如果索引为0,if(index==0){this.head=new Node(data,this.head);this.size++;return;}//特殊处理2:链表为空(异常已抛出)//找前驱结点,从头开始找,让索引移动index-1次Node pre=this.head;for(int i=1;i<=index;i++){pre=pre.next;}//开始进行结点的挂接node.next=pre.next;pre.next=node;this.size++;}

(4)对头插法和尾插法代码进行简化(调用任意位置添加的方法)

//在头部添加public void addHead(T data){add(0,data);}//在尾部添加public void addTail(T data){add(this.size,data);}

7.打印链表(遍历,重写toString方法)

//打印整个链表@Overridepublic String toString() {//从this。head开始一直向后Node curNode=this.head.next;StringBuilder sb=new StringBuilder();while(curNode!=null){sb.append(curNode.data+"-->");curNode=curNode.next;}sb.append("null");return sb.toString();}

8.获取链表元素个数(链表长度)

 //获取链表中元素的个数public int getSize(){return this.size;}

9.获取链表结点

(1)获取头结点

//获取链表的头结点public Optional getFirst(){if(this.head.next==null){return Optional.empty();}return Optional.ofNullable(this.head.next.data);}

(2)获取尾结点

//获取链表的尾结点public Optional getLast(){if(this.head.next==null){return Optional.empty();}Node<T> curNode=this.head;while(curNode.next!=null){curNode=curNode.next;}return Optional.of(curNode.data);}

(3)获取指定位置结点

 //从链表中获取任意位置的结点public T get(int index) {if (index < 0 || index >= this.size) {throw new IllegalArgumentException("index is invalid");}Node<T> curNode = this.head.next;int i = 0;while (i < index) {curNode = curNode.next;i++;}return curNode.data;}

10.判断结点是否存在

 //从链表中查找指定位置元素是否存在public boolean contains(T data) {Node curNode = this.head.next;while (curNode != null) {if (curNode.data.equals(data)) {return true;}}return false;}

11.删除结点

(1)删除头结点

 //从链表的头部删除元素public T removeHead() {if (this.isEmpty()) {return null;}Node<T> delNode = this.head.next;this.head.next = delNode.next;delNode.next = null;//更新size;this.size--;return delNode.data;}

(2)删除尾节点

//链表的尾部删除元素public T removeTail() {if (this.isEmpty()) {return null;}Node<T> pre = this.head;while (pre.next.next != null) {pre = pre.next;}Node<T> delNode = pre.next;pre.next = delNode.next;delNode.next = null;//更新size;this.size--;return delNode.data;}

(3)在指定位置删除结点

//删除任意位置的结点public T remove(int index){if(index<0||index>=this.size){throw new IllegalArgumentException("index is invalid");}//找删除结点的前驱Node<T>pre=this.head;int i=0;while(i<index){pre=pre.next;i++;}Node<T>delNode=pre.next;pre.next=delNode.next;delNode.next=null;this.size--;return delNode.data;}

(4)删除元素

//根据值从链表中删除元素public int removeByValue(T value){int count=0;//定义前驱结点Node<T>pre=this.head;while(pre.next!=null){Node curNode=pre.next;if(curNode.data.equals(value)){pre.next=pre.next.next;curNode.next=null;this.size--;count++;}else{pre=pre.next;}}return count;}

(5)不使用虚拟节点删除

//不使用虚拟头结点public int removeByValue2(T val){int count = 0;Node<T> realHead = this .head.next;while(realHead!=null&&realHead.data.equals(val)){realHead=realHead.next;this.size--;count++;}//判断链表是否为空if(realHead==null){return count;}//头结点不是删除的点Node pre = realHead;while(pre.next!=null){Node<T> delNode = pre.next;if(delNode.equals(val)){pre.next = delNode .next;delNode.next = null;this.size--;count++;}else{pre = pre .next;}}return count;}

三、完整代码

package com.algo.lesson.lesson03;import java.util.Optional;
import java.util.Random;public class SelfLinkedList<T> {//使用内部类——创建结点class Node<T> {T data;//节点本身Node next;//指向下个节点public Node(T data) {this.data = data;this.next = null;}public Node(T data, Node next) {this.data = data;this.next = null;}}//链表相关的属性和方法private Node head;//头结点private int size;//表示链表中有多少个结点public SelfLinkedList() {//创建一个虚拟头结点Node dummyHead = new Node(Integer.MIN_VALUE);this.head = dummyHead;this.size = 0;dummyHead.next = head;}//判断链表是否为空public boolean isEmpty() {return this.size == 0;}//向链表中添加结点//在头部添加public void addHead(T data) {/*//创建一个节点Node node= new Node(data);//挂接node.next=this.head;this.head=node;//更新sizethis.size++;*/add(0, data);}//在尾部添加public void addTail(T data) {/*Node node=new Node(data);//针对空链表做处理if(this.head==null){this.head=node;this.size++;return;}Node curNode=this.head;while(curNode.next!=null){curNode=curNode.next;}curNode.next=node;this.size++;*/add(this.size, data);}//在任意位置添加public void add(int index, T data) {//判断index是否有效if (index < 0 || index > this.size) {throw new IllegalArgumentException("index is invalid");}//创建一个节点Node node = new Node(data);//特殊处理1:如果索引为0,if (index == 0) {this.head = new Node(data, this.head);this.size++;return;}//特殊处理2:链表为空(异常已抛出)//找前驱结点,从头开始找,让索引移动index-1次Node pre = this.head;for (int i = 1; i <= index; i++) {pre = pre.next;}//开始进行结点的挂接node.next = pre.next;pre.next = node;this.size++;}//打印整个链表@Overridepublic String toString() {//从this。head开始一直向后Node curNode = this.head.next;StringBuilder sb = new StringBuilder();while (curNode != null) {sb.append(curNode.data + "-->");curNode = curNode.next;}sb.append("null");return sb.toString();}//从链表中查找指定位置元素是否存在public boolean contains(T data) {Node curNode = this.head.next;while (curNode != null) {if (curNode.data.equals(data)) {return true;}}return false;}//获取链表中元素的个数public int getSize() {return this.size;}//获取链表的头结点public Optional getFirst() {if (this.head.next == null) {return Optional.empty();}return Optional.ofNullable(this.head.next.data);}//获取链表的尾结点public Optional getLast() {if (this.head.next == null) {return Optional.empty();}Node<T> curNode = this.head;while (curNode.next != null) {curNode = curNode.next;}return Optional.of(curNode.data);}//从链表中获取任意位置的结点public T get(int index) {if (index < 0 || index >= this.size) {throw new IllegalArgumentException("index is invalid");}Node<T> curNode = this.head.next;int i = 0;while (i < index) {curNode = curNode.next;i++;}return curNode.data;}//从链表的头部删除元素public T removeHead() {if (this.isEmpty()) {return null;}Node<T> delNode = this.head.next;this.head.next = delNode.next;delNode.next = null;//更新size;this.size--;return delNode.data;}//链表的尾部删除元素public T removeTail() {if (this.isEmpty()) {return null;}Node<T> pre = this.head;while (pre.next.next != null) {pre = pre.next;}Node<T> delNode = pre.next;pre.next = delNode.next;delNode.next = null;//更新size;this.size--;return delNode.data;}//删除任意位置的结点public T remove(int index){if(index<0||index>=this.size){throw new IllegalArgumentException("index is invalid");}//找删除结点的前驱Node<T>pre=this.head;int i=0;while(i<index){pre=pre.next;i++;}Node<T>delNode=pre.next;pre.next=delNode.next;delNode.next=null;this.size--;return delNode.data;}//根据值从链表中删除元素public int removeByValue(T value){int count=0;//定义前驱结点Node<T>pre=this.head;while(pre.next!=null){Node curNode=pre.next;if(curNode.data.equals(value)){pre.next=pre.next.next;curNode.next=null;this.size--;count++;}else{pre=pre.next;}}return count;}//不使用虚拟头结点public int removeByValue2(T val){int count = 0;Node<T> realHead = this .head.next;while(realHead!=null&&realHead.data.equals(val)){realHead=realHead.next;this.size--;count++;}//判断链表是否为空if(realHead==null){return count;}//头结点不是删除的点Node pre = realHead;while(pre.next!=null){Node<T> delNode = pre.next;if(delNode.equals(val)){pre.next = delNode .next;delNode.next = null;this.size--;count++;}else{pre = pre .next;}}return count;}

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

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

相关文章

华为云OBS-文件上传

前端配合后端 采用临时上传 相关参考文档 使用临时URL进行授权访问_对象存储服务 OBS_BrowserJS_临时授权访问_华为云 选择文件方法 【 isPay 是否上传完毕】 handleChange(file, fileList) {this.active 0;this.json_data [];console.log(file, fileList);fileList.forEa…

LiveGBS流媒体平台GB/T28181常见问题-如何配置使用自己已有的redis服务替换redis版本升级redis版本

LiveGBS如何配置使用自己已有的redis服务替换redis版本升级redis版本 1、Redis服务2、如何切换REDIS?2.1、停止启动REDIS2.2、配置信令服务2.3、配置流媒体服务2.4、启动 3、搭建GB28181视频直播平台 1、Redis服务 在LivGBS中Redis作为数据交换、数据订阅、数据发布的高速缓存…

Java二分查找-图文

一、二分查找概念 二分查找也叫折半查找&#xff0c;是在一组有序(升序/降序)的数据中查找一个元素&#xff0c;它是一种效率较高的查找方。 二、二分查找原理 1.二分查找的数组必须是有序数值型数组。 2.将想要查找的目标元素与查找范围内的中间元素进行比较&#xff0c;如果…

数据结构篇-01:单调栈

单调栈是栈的一种&#xff0c;可以使得每次新元素入栈后&#xff0c;栈内的元素都保持有序&#xff08;单调递增或者单调递减&#xff09;。 单调栈的用途不太广泛&#xff0c;只处理一类典型的问题&#xff0c;比如[下一个更大元素]、[上一个更小元素] 等。 在本文中&#x…

Pandas应用-股票分析实战

股票时间序列 时间序列&#xff1a; 金融领域最重要的数据类型之一 股价、汇率为常见的时间序列数据 趋势分析&#xff1a; 主要分析时间序列在某一方向上持续运动 在量化交易领域&#xff0c;我们通过统计手段对投资品的收益率进行时间序列建模&#xff0c;以此来预测未来的收…

六、VTK创建平面vtkPlaneSource

vtkPlaneSource创建位于平面中的四边形数组 先看看效果图: vtkPlaneSource 创建一个 m x n 个四边形数组,这些四边形在平面中排列为规则平铺。通过指定一个原点来定义平面,然后指定另外两个点,这两个点与原点一起定义平面的两个轴。这些轴不必是正交的 - 因此您可以创建平行…

css3表格练习

1.效果图 2.html <div class"line"></div><h3>获奖名单</h3><!-- 表格 cellspacing内边距 cellpadding外边距--><table cellspacing"0" cellpadding"0" ><!-- thead表头 --><thead><tr>…

蓝桥杯备战——6.串口通讯

1.分析原理图 由上图我们可以看到串口1通过CH340接到了USB口上&#xff0c;通过串口1我们就能跟电脑进行数据交互。 另外需要注意的是STC15F是有两组高速串口的&#xff0c;而且可以切换端口。 2.配置串口 由于比赛时间紧&#xff0c;我们最好不要去现场查寄存器手册&#x…

【搞懂设计模式】享元模式:共享节约,皆大欢喜!

什么是享元模式&#xff1f; 巧记&#xff1a;共享节约&#xff0c;皆大欢喜。 总结&#xff1a;享元模式是一种结构型设计模式&#xff0c;它通过共享技术有效地支持大量细粒度的对象。想象一个大家庭的餐桌&#xff0c;一顿饭需要的碗筷&#xff0c;如果每个人都自己带一套…

第七十一周周报

学习目标&#xff1a; 一、实验 二、小程序 学习时间&#xff1a; 2024.1.20-2024.1.26 学习产出&#xff1a; 一、小程序 这周花了两天根据陈勇和纪行之的代码优化了小程序的代码 二、实验 根据stylegan2仓库的redeme文件重新跑了stylegan2和diffusion-stylegan2 DV…

暴力破解

暴力破解工具使用汇总 1.查看密码加密方式 在线网站&#xff1a;https://cmd5.com/ http://www.158566.com/ https://encode.chahuo.com/kali&#xff1a;hash-identifier2.hydra 用于各种服务的账号密码爆破&#xff1a;FTP/Mysql/SSH/RDP...常用参数 -l name 指定破解登录…

MAX27——处理max模型导出Zbrush中,无UV,或者UV炸开,反向等问题。

现在很多小伙伴要做数字人的时候会用到zbrush拓补高模。制作法线。有些人喜欢在zbrush中去做封套。也有喜欢直接用max做低模&#xff0c;做好的uv导入到Zbrush中&#xff0c;直接把高模法线&#xff0c;烘焙到低模UV的。这里主要讲解以下max导出到zbrush中&#xff0c;UV炸开&a…

SQL注入:报错注入

SQL注入系列文章&#xff1a;初识SQL注入-CSDN博客 SQL注入&#xff1a;联合查询的三个绕过技巧-CSDN博客 目录 什么是报错注入&#xff1f; 报错注入常用的3个函数 UpdateXML ExtractValue Floor rand&#xff08;随机数&#xff09; floor&#xff08;向上取整&…

大模型日报-20240126

「think step by step」还不够&#xff0c;让模型「think more steps」更有用 https://mp.weixin.qq.com/s/3mdDYQI0WYgIpctyK6q2PA 如今&#xff0c;大型语言模型&#xff08;LLM&#xff09;及其高级提示策略的出现&#xff0c;标志着对语言模型的研究取得了重大进展&#x…

JavaScript 生成器(Generator)、高级 iteration用法详解

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》、《krpano中文文档》 ​ 目录 ✨ 前言 ✨ 正文 一、生成器(Generator) 什么是生成器 生成器函数 nex…

Unity 代理模式(实例详解)

文章目录 实例1&#xff1a;资源加载代理&#xff08;Asset Loading Proxy&#xff09;实例2&#xff1a;网络请求代理&#xff08;Network Request Proxy&#xff09;实例3&#xff1a;性能优化代理&#xff08;Performance Optimization Proxy&#xff09;实例4&#xff1a;权…

Docker容器部署OpenCV,打造高效可移植的计算机视觉开发环境

推荐 海鲸AI-ChatGPT4.0国内站点&#xff1a;https://www.atalk-ai.com 前言 在计算机视觉领域&#xff0c;快速部署和测试算法是研究和开发的关键。OpenCV作为一个强大的开源计算机视觉库&#xff0c;广泛应用于各种图像处理和视频分析任务。然而&#xff0c;配置OpenCV环境可…

python 调用SumatraPDF 静默打印PDF

SumatraPDF 文档 https://www.sumatrapdfreader.org/docs/Command-line-arguments ⽆边框 noscale/缩⼩到合适⼤⼩&#xff08;默认&#xff09;shrink/合适⼤⼩ fit/compat 兼容 # 分为 Portrait (纵向)和 Landscape (横向)两类 https://github.com/sumatrapdfreader/sumatrap…

光纤接口类型

光纤接口 网络设备基础知识 文章目录 光纤接口前言一、光纤接口二、光纤接口的优缺点总结前言 不同的接口类型适用于不同的光纤传输系统和应用需求。在选择光纤设备时,需要根据实际需求和系统要求选择适当的光纤接口类型。 一、光纤接口

计算机基础之微处理器简介

微处理器 微处理器定义 微型计算机的CPU也被称为微处理器&#xff0c;是将运算器、控制器和高速缓存集成在一起的超大规模集成电路芯片&#xff0c;是计算机的核心部件。能完成取指令、执行指令&#xff0c;以及与外界存储器和逻辑部件交换信息等操作。 微处理器发展 CPU从…