当前位置: 首页 > news >正文

Java链表(1)

🐵本篇文章将对单链表进行讲解,模拟实现单链表中常见的方法


一、什么是链表

链表是一种逻辑结构上连续而物理结构上不一定连续的线性表,链表由一个一个节点组成:

每一个节点中都由数据域(val)和指针域(next)组成,数据域用于存放要存放在该节点的数据,指针域用于存放节点的地址,上图中链表的每一个节点的指针域存放的是下一个节点的地址,最后一个节点的指针指向空

二、链表的种类

链表细分可以分为八种,分别为:

1. 单向不带头非循环链表 2. 单向不带头循环链表 

3. 单向带头非循环链表     4. 单向带头循环链表

5. 双向不带头非循环链表 6. 双向不带头循环链表 

7. 单向带头非循环链表     8. 双向带头循环链表

三、链表的模拟实现

首先对第一种单链表的增删查改等操作用Java进行模拟实现,先将要模拟实现的方法写到IList接口中:

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

之后再创建一个MySingleList类实现上述接口并重写接口中所有的方法

public class MySingleList implements IList{static class ListNode {public int val;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head; //指向第一个节点/*以下是要重写IList接口中的方法*/...}

在MySingleList类中创建一个静态内部类ListNode用于描述一个节点对象,val用于存放数据,next用于存放下一个节点的地址,构造方法用于初始化数据va,接下来对上述方法进行模拟实现

3.1 方法的实现

public void addFirst(int data);

在链表的头部新增一个节点newNode

很明显要在头部新增一个节点就应让newNode的next指向head,并让newNode成为head

    public void addFirst(int data) {ListNode newNode = new ListNode(data);newNode.next = head;head = newNode;}

public void addLast(int data);

在链表的尾部新增一个节点

应让最后一个节点的next引用指向newNode,链表无法像顺序表一样可以直接找到某个位置的节点,所以应该通过循环先找到最后一个节点:

ListNode cur = head; //通常一个链表的头指针不动,需要定义一个cur来遍历链表、while (cur.next != null) {cur = cur.next; //只要cur的next不是空,cur就指向下一个节点
}//循环完成后cur就是最后一个节点
cur.next = newNode; 

完成以上操作后还要考虑一个特殊情况:如果链表为空,上述代码能否完成尾插操作?答案是不能的,因为如果链表为空,则head为空,cur为空,在循环条件处cur.next != null就会抛出一个NullPointerException的空指针异常,所以要单独处理链表为空的情况:

    public void addLast(int data) {ListNode newNode = new ListNode(data);if (head == null) { //如果链表为空,则直接让head指向newNodehead = newNode;} else {ListNode cur = head;while (cur.next != null) {cur = cur.next;}cur.next = newNode;}}

public int size();

求链表的长度也就是该链表有几个节点,只要直接遍历链表即可

    public int size() {ListNode cur = head;int count = 0;while(cur != null) { //注意这里和尾插的循环条件不一样count++;cur = cur.next;}return count;}

public boolean contains(int key);

判断链表中是否有节点的val值等于key,也是只要直接遍历链表即可

    public boolean contains(int key) {ListNode cur = head;while(cur != null) {if (cur.val == key) {return true;}cur = cur.next;}return false;}

public void addIndex(int index,int data);

在任意位置处插入一个节点,第一个节点的索引为0

首先要判断一下index是否合法:

public class IndexException extends RuntimeException{public IndexException(String message) {super(message);}
}=======================================================public void addIndex(int index, int data) {if (index < 0 || index > size()) {throw new IndexException("下标错误");}...
}

在任意位置插入节点,所以如果index为0或等于链表长度,就可以直接使用刚刚实现过的头插和尾插方法

public void addIndex(int index, int data) {if (index < 0 || index > size()) {throw new IndexException("下标错误");}if (index == 0) {addFirst(data);}if (index == size()) {addLast(data);}...
}

然后就是一般情况下:

如果要在1位置处插入新节点,那就应该先找到1位置处的节点的前驱节点,这里定义为cur,令newNode.next = cur.next;这样newNode的next就指向1位置处的节点,之后令cur.next = newNode这样就插入完成了

    public void addIndex(int index, int data) {if (index < 0 || index > size()) {throw new IndexException("下标错误");}if (index == 0) {addFirst(data);}if (index == size()) {addLast(data);}ListNode newNode = new ListNode(data);ListNode cur = head;for (int i = 0; i < index - 1; i++) { 找到插入节点的前驱节点cur = cur.next;}newNode.next = cur.next;cur.next = newNode;}

public void remove(int key);

假如要删除val = 20的节点(这里先定义为del)如果要删除该节点就应让del的前驱节点的next指向del的后继节点:

    public void remove(int key) {ListNode cur = head;while(cur.next.val != key) { //通过循环找到del的前驱节点cur = cur.next; }cur.next = cur.next.next;}

写完后还要考虑两种特殊情况:

第一,如果链表为空,上述代码不能满足要求,因为在循环条件处会抛出空指针异常

第二,如果要删除的节点是第一个节点,上述代码也不能满足要求,因为该循环是从第一个节点的下一个节点开始判断的

以上两种情况都需要单独处理:

    public void remove(int key) {if (head == null) {return;}if (head.val == key) {head = head.next;return;}ListNode cur = head;while(cur.next.val != key) {cur = cur.next;}cur.next = cur.next.next;}

public void removeAllKey(int key);

删除所有val = key的节点,那就需要遍历整个链表,在遍历过程中删除节点:

    public void removeAllKey(int key) {ListNode cur = head;while (cur.next != null) {if(cur.next.val == key) {cur.next = cur.next.next;} else {cur = cur.next;}}}

在循环的结束也要判断一下第一个节点是否为要删除的节点,因为上述循环条件为cur.next != null没有判断第一个节点:

    public void removeAllKey(int key) {if (head == null) { //如果链表为空则直接返回return;}ListNode cur = head;while (cur.next != null) {if(cur.next.val == key) {cur.next = cur.next.next;} else {cur = cur.next;}}if (head.val == key) {head = head.next;}}

public void clear();

清空链表,由于对象在没有被引用时,就会自动被回收,所以只需要将head置为空就行了

public void clear() {head = null;
}

🙉本篇文章到此结束,下篇文章将对LinkedList类进行讲解

相关文章:

  • 14、Kafka ------ kafka 核心API 之 流API(就是把一个主题的消息 导流 到另一个主题里面去)
  • 25考研每日的时间安排
  • 6 时间序列(不同位置的装置如何建模): GRU+Embedding
  • 批量数据之DataX数据同步
  • 制作一个简单的HTML个人网站
  • flink学习之窗口处理函数
  • 【算法练习】leetcode算法题合集之动态规划篇
  • 防火墙在企业园区出口安全方案中的应用(ENSP实现)
  • 网络安全进阶试题——附答案
  • GPT-5不叫GPT-5?下一代模型会有哪些新功能?
  • VR数字展厅,平面静态跨越到3D立体化时代
  • 决策树的基本构建流程
  • 选择排序(堆排序和topK问题)
  • live555搭建流式rtsp服务器
  • 电脑文件mfc140.dll丢失的解决方法指导,怎么快速修复mfc140.dll
  • 2017-09-12 前端日报
  • dva中组件的懒加载
  • Git 使用集
  • Git学习与使用心得(1)—— 初始化
  • js写一个简单的选项卡
  • Spark RDD学习: aggregate函数
  • TypeScript实现数据结构(一)栈,队列,链表
  • vue中实现单选
  • windows下使用nginx调试简介
  • 闭包--闭包之tab栏切换(四)
  • 持续集成与持续部署宝典Part 2:创建持续集成流水线
  • 给自己的博客网站加上酷炫的初音未来音乐游戏?
  • 工作手记之html2canvas使用概述
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 理解IaaS, PaaS, SaaS等云模型 (Cloud Models)
  • 时间复杂度与空间复杂度分析
  • 首页查询功能的一次实现过程
  • 数组大概知多少
  • 职业生涯 一个六年开发经验的女程序员的心声。
  • 智能网联汽车信息安全
  • Hibernate主键生成策略及选择
  • ​【原创】基于SSM的酒店预约管理系统(酒店管理系统毕业设计)
  • ​ssh免密码登录设置及问题总结
  • ###STL(标准模板库)
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第5节(封闭类和Final方法)
  • (done) 两个矩阵 “相似” 是什么意思?
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (附源码)计算机毕业设计大学生兼职系统
  • (论文阅读30/100)Convolutional Pose Machines
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (三)Hyperledger Fabric 1.1安装部署-chaincode测试
  • (一)Dubbo快速入门、介绍、使用
  • (转)从零实现3D图像引擎:(8)参数化直线与3D平面函数库
  • (转)为C# Windows服务添加安装程序
  • 、写入Shellcode到注册表上线
  • .net framwork4.6操作MySQL报错Character set ‘utf8mb3‘ is not supported 解决方法
  • .Net Web项目创建比较不错的参考文章
  • [\u4e00-\u9fa5] //匹配中文字符