Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
Java双向链表指定索引节点删除操作详解_创想鸟

Java双向链表指定索引节点删除操作详解

Java双向链表指定索引节点删除操作详解

本文详细阐述了在Java中实现双向链表指定索引节点删除操作的完整方法。内容涵盖了双向链表节点和列表的泛型化设计、delete方法的参数校验、以及针对删除头节点、尾节点和中间节点等多种边界情况的精确处理。通过清晰的代码示例和关键注意事项,旨在帮助读者掌握双向链表删除操作的严谨实现,确保链表结构的完整性和数据一致性。

双向链表基础结构

在深入探讨删除操作之前,我们首先需要理解双向链表的基本构成。双向链表中的每个节点不仅指向下一个节点,还指向上一个节点,这使得从两个方向遍历链表成为可能。

节点(Node)类

双向链表的节点类通常包含数据域以及指向前后节点的引用。为了实现更强的通用性,我们采用泛型来定义节点,使其能够存储任意类型的数据。

public class Node {    T data; // 存储节点数据    Node next; // 指向下一个节点    Node previous; // 指向上一个节点    public Node(T data) {        this.data = data;        this.next = null;        this.previous = null;    }    @Override    public String toString() {        return data.toString();    }}

这里,T 是泛型类型参数,代表节点中存储的数据类型。

双向链表(DoublyLinkedList)类

双向链表类维护了链表的头部(head)、尾部(tail)以及当前节点数量(size)。为了保持与节点类的泛型一致性,DoublyLinkedList 也应是泛型的。如果需要对链表中的元素进行比较操作(例如排序),则泛型类型 T 需要实现 Comparable 接口。

public class DoublyLinkedList<T extends Comparable> {    protected Node head;    protected Node tail;    int size = 0;    public DoublyLinkedList() {        this.head = null;        this.tail = null;    }    /**     * 在链表末尾添加一个新节点     * @param data 要添加的数据     * @return 新添加的节点     */    public Node append(T data) {        Node newNode = new Node(data);        if (head == null) { // 链表为空时            head = newNode;            tail = newNode;        } else { // 链表不为空时            newNode.previous = tail;            tail.next = newNode;            tail = newNode;        }        size++;        return newNode;    }    // toString 方法用于方便地打印链表内容    @Override    public String toString() {        StringBuilder sb = new StringBuilder();        sb.append(String.format("[%d]: ", size));        Node current = head;        while (current != null) {            sb.append(current.data);            if (current.next != null) {                sb.append("  ");            }            current = current.next;        }        return sb.toString();    }}

核心实现:指定索引删除节点 (delete) 方法

删除双向链表中的节点比单向链表更为复杂,因为它涉及到同时更新 next 和 previous 两个指针。此外,我们需要特别处理多种边界情况,包括删除头节点、尾节点,以及链表为空或只有一个节点的情况。

立即学习“Java免费学习笔记(深入)”;

方法签名与参数校验

delete 方法接收一个整数 location 作为参数,表示要删除节点的索引位置(从0开始)。在执行删除操作前,必须对 location 的有效性进行严格校验。

public void delete(int location) throws IllegalArgumentException {    // 1. 参数校验:检查链表是否为空,以及索引是否越界    if (head == null || location = size) {        throw new IllegalArgumentException("无效的索引位置或链表为空。");    }    // ... 后续删除逻辑}

此校验确保了操作的安全性,避免了空指针异常和非法访问。

删除逻辑分类处理

根据 location 的值和链表当前的大小,删除操作可以分为以下几种情况:

删除链表中唯一的节点 (size == 1 && location == 0)当链表中只有一个节点,且要删除的就是这个节点时,链表将变为空。此时,head 和 tail 都应设置为 null。

删除头节点 (location == 0 且 size > 1)如果链表包含多个节点,删除头节点意味着将 head 指针移动到当前头节点的下一个节点。新头节点的 previous 指针必须设为 null。

删除尾节点 (location == size – 1 且 size > 1)删除尾节点时,tail 指针需要移动到当前尾节点的前一个节点。新尾节点的 next 指针必须设为 null。

删除中间节点 (0 < location < size – 1)删除链表中间的节点需要调整其前一个节点和后一个节点的指针。具体来说,目标节点的前一个节点的 next 指针应指向目标节点的后一个节点,同时目标节点的后一个节点的 previous 指针应指向目标节点的前一个节点。

完整 delete 方法实现

结合上述分析,以下是 delete 方法的完整实现:

public void delete(int location) throws IllegalArgumentException {    // 1. 参数校验    if (head == null || location = size) {        throw new IllegalArgumentException("无效的索引位置或链表为空。");    }    // 2. 处理删除链表中唯一节点的情况    if (size == 1 && location == 0) {        head = null;        tail = null;    }     // 3. 处理删除头节点的情况 (链表有多个节点)    else if (location == 0) {        head = head.next; // 新的头节点是原头节点的下一个        if (head != null) { // 确保新头节点不为空            head.previous = null; // 新头节点的previous指向null        }        // 如果删除后只剩一个节点(原有两个节点),则新的head也是tail        // 实际上,如果head.next是null,那么head就是null,tail也应该为null,这在size==1时已处理        // 如果head.next不为null,且size-1 == 0,即原size为1,已处理        // 如果原size为2,location=0,head变为原tail,此时head即是tail        if (size == 2) { // 原始链表有两个节点,删除头节点后,剩下的一个节点既是头也是尾            tail = head;        }    }     // 4. 处理删除尾节点的情况 (链表有多个节点)    else if (location == size - 1) {        tail = tail.previous; // 新的尾节点是原尾节点的前一个        if (tail != null) { // 确保新尾节点不为空            tail.next = null; // 新尾节点的next指向null        }        // 注意:如果原size为1,location=0,已在上面处理        // 如果原size为2,location=1,删除尾节点后,剩下的一个节点既是头也是尾        if (size == 2) { // 原始链表有两个节点,删除尾节点后,剩下的一个节点既是头也是尾            head = tail; // head也指向这个唯一的节点        }    }     // 5. 处理删除中间节点的情况    else {        Node current = head;        // 遍历到要删除的节点        for (int i = 0; i < location; i++) {            current = current.next;        }        // current 现在指向要删除的节点        // 调整前一个节点的next指针        current.previous.next = current.next;        // 调整后一个节点的previous指针        current.next.previous = current.previous;    }    size--; // 链表大小减一}

对delete方法的进一步优化和简化

上述delete方法在处理size == 2时的tail = head和head = tail逻辑有些冗余,因为head和tail的正确性会在其他分支中自然维护。更简洁和鲁棒的实现如下:

public void delete(int location) throws IllegalArgumentException {    if (head == null || location = size) {        throw new IllegalArgumentException("无效的索引位置或链表为空。");    }    if (size == 1) { // 链表中只有一个节点        head = null;        tail = null;    } else if (location == 0) { // 删除头节点        head = head.next;        head.previous = null;    } else if (location == size - 1) { // 删除尾节点        tail = tail.previous;        tail.next = null;    } else { // 删除中间节点        Node current = head;        for (int i = 0; i < location; i++) { // 遍历到要删除的节点            current = current.next;        }        // current 是要删除的节点        current.previous.next = current.next;        current.next.previous = current.previous;    }    size--; // 链表大小减一}

这个优化后的版本更清晰地分离了逻辑,特别是当size == 1时,直接清空链表,避免了后续分支的复杂性。

示例数据类型:Student 类

为了演示双向链表的功能,我们可以创建一个简单的 Student 类作为存储在链表中的数据类型。由于 DoublyLinkedList 泛型要求 T 实现 Comparable,Student 类也需要实现此接口。

class Student implements Comparable {    private static int counter;    private int id;    public Student() {        id = ++counter; // 每次创建新学生时,ID自动递增    }    @Override    public int compareTo(Student o) {        return id - o.id; // 根据ID比较学生    }    @Override    public boolean

以上就是Java双向链表指定索引节点删除操作详解的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/80295.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
如何建立有效的CRM系统?提供5个关键步骤
上一篇 2025年11月15日 14:49:43
一个完整的CRM应具有哪些功能?详述5个核心功能
下一篇 2025年11月15日 14:50:03

相关推荐

  • 压力测试(Benchmark)Swoole服务的工具与方法

    进行swoole服务的压力测试是为了确保服务在高负载下稳定运行。1. 选择工具:apache jmeter、wrk、locust。2. 使用方法:jmeter通过脚本配置,wrk通过命令行,locust通过python脚本。3. 注意事项:环境隔离、数据监控、脚本设计。4. 优化点:内存泄漏、连接池…

    2026年9月21日
    000
  • Windows11内存占用率过高怎么解决_Windows11内存占用过高修复方法

    1、通过任务管理器结束高内存占用进程;2、禁用Superfetch(SysMain)服务以降低内存负担;3、优化启动项减少后台负载;4、升级物理内存条提升系统性能。 如果您发现Windows 11系统运行缓慢,并且任务管理器显示内存占用率持续处于高位,这可能是由于后台进程过多、系统服务占用资源或硬件…

    2026年9月21日
    100
  • mysql常用存储引擎有哪些

    InnoDB是现代MySQL应用的首选存储引擎,因其支持事务(ACID)、行级锁、外键约束、崩溃恢复和MVCC,适用于高并发、数据完整性要求高的OLTP场景;MyISAM虽读取快但仅支持表级锁且无事务和外键,适用于读多写少的简单场景,已逐渐被淘汰;Memory引擎将数据存于内存,速度快但易失,适合临…

    2026年9月21日
    000
  • iPhone 12 Pro Max如何启用防水提示

    iPhone 12 Pro Max 具备 IP68 级防水,依赖密封设计无需启用;进水时会提示“闪电符号”,需晾干并避免使用吹风机,防水性能随时间可能下降。 iPhone 12 Pro Max 没有需要“启用”的防水提示功能。它的防溅、抗水和防尘能力是出厂时的硬件设计特性,无法通过设置开关来开启或关…

    2026年9月21日
    100
  • Linux目录结构与Windows目录结构对比

    Linux采用单一树状结构,所有文件系统挂载于根目录/下,如/home、/etc;Windows以C:\、D:\等独立盘符划分,无统一根节点。2. Linux将配置集中于/etc,用户数据存于/home,系统文件在/bin、/usr等,配置明文可编辑;Windows程序装在Program Files…

    用户投稿 2026年9月21日
    100
  • 在Java中多态是如何通过虚方法实现的

    多态通过动态方法调度实现,JVM利用虚方法表(vtable)在运行时根据对象实际类型确定方法调用。Java中除private、static、final方法和构造器外均为虚方法,子类重写方法后其vtable指向新实现,调用时JVM通过对象类型查找vtable定位具体方法。如Animal a = new…

    2026年9月21日
    000
  • 利用蝴蝶号搭建多账号无人直播系统的完整方案

    利用蝴蝶号搭建多账号无人直播系统的完整方案利用蝴蝶号搭建多账号无人直播系统的完整方案利用蝴蝶号搭建多账号无人直播系统的完整方案利用蝴蝶号搭建多账号无人直播系统的完整方案

    搭建多账号无人直播系统并非一键操作,而是通过“蝴蝶号”实现自动化流程。首先,“蝴蝶号”负责多账号的生命周期管理,包括登录、状态维护、ip代理分配和设备指纹模拟;其次,内容调度系统决定直播内容及播放时间,可为预录视频或动态生成流;再次,推流引擎将内容实时推送至平台,推荐使用ffmpeg结合python…

    2026年9月21日 • 用户投稿
    100
  • 大润发优鲜如何邀请新用户

    你可以通过生成个人专属的邀请链接来参与大润发优鲜的“邀请有礼”活动。在App内找到相关入口后,系统会为你生成唯一的邀请链接。将这个链接通过微信、QQ、短信或其他社交渠道分享给朋友或家人,一旦对方点击链接并完成大润发优鲜App的下载与注册,你就能获得平台发放的奖励,例如购物优惠券或积分,而新用户通常也…

    2026年9月21日
    000
  • 锚定AI终端存储市场,康盈半导体连发三款新品

    锚定AI终端存储市场,康盈半导体连发三款新品锚定AI终端存储市场,康盈半导体连发三款新品锚定AI终端存储市场,康盈半导体连发三款新品锚定AI终端存储市场,康盈半导体连发三款新品

    ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ 三款新品聚焦AI存储需求 在最新举行的产品发布会上,康盈半导体正式推出三款专为AI应用场景打造的全新存储解决方案,覆盖嵌入式存储与高性能固态硬盘等多个品类,旨在满足多样化AI终端对高效、紧凑、低…

    2026年9月21日 • 用户投稿
    100
  • linux内核定时器实验

    linux内核定时器实验linux内核定时器实验linux内核定时器实验linux内核定时器实验

    大家好,又见面了,我是你们的朋友全栈君。 文章目录一、linux时间管理和内核定时器简介1.内核时间管理简介2.内核定时器简介1.init_timer 函数2.add_timer 函数3.del_timer 函数4.del_timer_sync 函数5.mod_timer 函数3.linux内核短延…

    2026年9月21日 • 用户投稿
    000
  • WordPress插件定制:使用Filter Hook修改邮件通知接收者

    本教程将指导您如何在WordPress中利用Filter Hook定制插件行为,特别是修改第三方插件的邮件通知接收者。我们将详细讲解如何识别目标Filter、理解其参数,并正确编写回调函数来拦截或修改数据,以实现自定义的邮件发送逻辑,避免因参数不匹配导致的错误。 WordPress Hook机制概览…

    2026年9月21日
    100
  • 谷歌浏览器官方在线访问 最新版Chrome官网登录

    谷歌浏览器官方在线访问入口是https://www.google.cn/chrome/,提供简洁界面、跨设备同步、高效内核、安全防护和丰富扩展生态。 谷歌浏览器官方在线访问入口在哪里?这是不少网友都关注的,接下来由PHP小编为大家带来最新版Chrome官网登录地址,想要获取纯净浏览体验的网友一起随小…

    2026年9月21日
    200
  • Java Collections.singletonList如何创建单元素集合

    Collections.singletonList(T item) 返回只含一个元素的不可变列表,传入指定对象后生成轻量级只读集合,适用于需高效传递单元素场景。该列表禁止修改操作,否则抛出异常,允许 null 元素,内部优化减少内存开销,常用于 API 参数传递或流处理中的临时数据构造。 Java …

    2026年9月21日
    100
  • JavaScript中的模块联邦如何实现微前端的代码共享?

    模块联邦通过运行时动态加载实现微前端代码共享,无需打包公共依赖。使用 ModuleFederationPlugin 配置 name、remotes、exposes 和 shared,使应用可暴露或引入远程模块,支持组件、工具函数及状态管理共享,提升复用性并减少冗余。 模块联邦通过在构建时让不同应用直…

    2026年9月21日
    200
  • 天眼查app怎么看一个公司的法院判决书_天眼查公司法院判决书查询

    通过天眼查App可查询公司法律纠纷详情。首先登录并搜索企业名称进入主页,再点击“法律诉讼”板块查看案件列表,最后筛选已结案案件并点击查看裁判文书获取判决书全文,部分敏感信息可能不予展示。 如果您想了解一家公司涉及的法律纠纷详情,查阅其法院判决书是重要的途径之一。天眼查App整合了公开的司法信息,可以…

    2026年9月21日
    100
  • Swoole如何实现一个UDP服务器

    答案:使用Swoole可轻松创建高性能UDP服务器。通过new SwooleServer()设置UDP套接字,监听Packet事件接收数据,利用sendto()回复客户端;结合set()配置worker_num等参数优化性能,配合PHP UDP客户端测试通信,适用于高并发、低延迟场景。 使用Swoo…

    2026年9月21日
    100
  • MySQL执行计划中的Extra字段代表什么_怎么看优化空间?

    MySQL执行计划中的Extra字段代表什么_怎么看优化空间?MySQL执行计划中的Extra字段代表什么_怎么看优化空间?MySQL执行计划中的Extra字段代表什么_怎么看优化空间?MySQL执行计划中的Extra字段代表什么_怎么看优化空间?

    在 mysql 查询优化中,执行计划的 extra 字段用于说明查询执行时的额外操作,常见的值包括:1. using filesort 表示需要额外排序,应尽量通过建立索引避免;2. using temporary 表示使用了临时表,常见于 group by 或复杂 join,需优化减少其使用;3.…

    2026年9月21日 • 用户投稿
    100
  • 如何通过tracert命令追踪数据包从本地到目标服务器的完整路径?

    打开命令提示符,输入cmd并回车;2. 执行tracert 目标地址命令追踪路径;3. 查看每跳响应时间与IP,分析延迟变化定位网络瓶颈;4. 注意部分节点可能因防火墙不响应导致超时。 使用 tracert(Windows 系统)命令可以追踪数据包从你的计算机到目标服务器所经过的每一跳网络节点,帮助…

    2026年9月21日
    1000
  • iPhone声音小如何解决

    确认音量是否被调低 第一步,检查iPhone的音量是否被误调至最低。可以通过按压手机左侧的音量加减键,观察屏幕上的音量条是否处于合理范围。同时留意是否启用了静音模式——手机左侧的静音开关若拨到静音位置(显示橙色),声音会明显变小甚至无声,将其拨回非静音状态即可恢复正常。 清洁扬声器孔 扬声器出声孔被…

    2026年9月21日
    100
  • 如何在Java中理解Java I/O与NIO机制

    传统I/O是阻塞式流模型,适用于低并发场景;NIO基于缓冲区与通道,支持非阻塞和多路复用,适合高并发网络应用,核心区别在于线程模型与资源利用率。 Java中的I/O(输入/输出)与NIO(New I/O)是处理数据读写的核心机制,理解它们的区别和使用场景对开发高性能应用至关重要。传统I/O基于流模型…

    2026年9月21日
    100

发表回复

登录后才能评论
关注微信