当前位置:首页 > 随笔 > 正文内容

单链表特定值节点剔除算法详解

访客 随笔 2026年6月24日 1

需求概述

本题旨在处理单链表数据结构中的清理任务。输入参数包含链表的起始节点引用以及一个指定的整数阈值。核心目标是遍历列表,定位并移除所有节点存储值与该阈值相符的实例,最终返回经过清洗后的新链表头部。

解法一:分情况处理头节点

在不引入辅助节点的情况下,需要特殊关注链表的首部。因为修改普通节点的连接关系通常是通过前驱节点完成的,而头节点没有前驱,其移除操作涉及对头指针的直接赋值。

  • 前置调整:循环检查头节点的值,若等于目标值,则将头指针向后移动一位,直到头节点有效或链表为空。
  • 主体遍历:使用游标从新的头节点开始,检查其后继节点。若后继节点的值需要被剔除,则修改当前游标的 next 指针跳过该节点;否则游标正常向后移动。
public class ListProcessor {

    public static ListNode removeSpecificValue(ListNode root, int target) {
        // 预处理头部,移除所有符合条件的头结点
        while (root != null && root.value == target) {
            root = root.next;
        }
        
        if (root == null) return null; // 链表已空
        
        ListNode ptr = root;
        while (ptr.next != null) {
            if (ptr.next.value == target) {
                // 跳过目标节点
                ptr.next = ptr.next.next;
            } else {
                // 移动到下一位
                ptr = ptr.next;
            }
        }
        return root;
    }

    // 标准链表节点定义
    static class ListNode {
        int value;
        ListNode next;
        ListNode(int v) { value = v; }
    }

    public static void main(String[] args) {
        // 构造测试数据:1 -> 2 -> 6 -> 3 -> 4 -> 5 -> 6
        ListNode n1 = new ListNode(1);
        ListNode n2 = new ListNode(2);
        ListNode n3 = new ListNode(6);
        ListNode n4 = new ListNode(3);
        ListNode n5 = new ListNode(4);
        ListNode n6 = new ListNode(5);
        ListNode n7 = new ListNode(6);
        
        n1.next = n2; n2.next = n3; n3.next = n4; 
        n4.next = n5; n5.next = n6; n6.next = n7;

        System.out.print("处理后结果:");
        ListNode result = removeSpecificValue(n1, 6);
        while (result != null) {
            System.out.print(result.value + " ");
            result = result.next;
        }
    }
}

解法二:利用虚拟头结点统一逻辑

为了消除对首节点的边界判断,可以采用"哨兵模式"(Sentinel Pattern)。创建一个值为任意数的虚拟节点作为新的头,并将其 next 指向原始头节点。这样,原本的头节点就变成了普通中间节点,从而允许使用统一的逻辑来遍历和删除后续节点。算法执行完毕后,返回虚拟节点的下一个即可。

  • 创建哨兵:初始化一个 dummy 节点,链接原链表。
  • 统一遍历:从 dummy 开始向后扫描,只要后继节点是目标值就进行断链操作,无需额外判断是否为表头。
public class ListProcessor {

    public static ListNode removeWithSentinel(ListNode chainHead, int target) {
        // 构建虚拟前导节点
        ListNode sentinel = new ListNode(0);
        sentinel.next = chainHead;
        
        ListNode curr = sentinel;
        while (curr.next != null) {
            if (curr.next.value == target) {
                // 发现目标节点,切断连接
                curr.next = curr.next.next;
            } else {
                // 继续遍历
                curr = curr.next;
            }
        }
        // 返回真实的新头节点
        return sentinel.next;
    }

    static class ListNode {
        int value;
        ListNode next;
        ListNode(int v) { value = v; }
    }

    public static void main(String[] args) {
        // 快速构建测试序列 1->2->6->3->4->5->6
        ListNode head = createTestChain();
        
        System.out.println("优化版处理结果:");
        ListNode cleanedHead = removeWithSentinel(head, 6);
        traverseAndPrint(cleanedHead);
    }
    
    private static ListNode createTestChain() {
        ListNode[] nodes = new ListNode[7];
        int[] vals = {1, 2, 6, 3, 4, 5, 6};
        for (int i = 0; i < 7; i++) nodes[i] = new ListNode(vals[i]);
        for (int i = 0; i < 6; i++) nodes[i].next = nodes[i+1];
        return nodes[0];
    }

    private static void traverseAndPrint(ListNode start) {
        ListNode temp = start;
        while (temp != null) {
            System.out.print(temp.value + " ");
            temp = temp.next;
        }
    }
}
标签: Javalinked-list

相关文章

可以按小时收费的VPS

很多 VPS 提供商都支持 按小时计费(hourly billing),想短期试用 / 临时搭建节点、测试网络、短期项目等场景非常合适。下面是当前最主流且靠谱的按小时 VPS 选项,分别按不同需求场景整理: 1. Vultr(全球节点,包括日本) 按小时计费 可选机房:东京 / 大阪 / 洛杉矶 / 法兰克福 / 伦敦 … 支持 PayPal(部分情况),但更常用信用卡/PayPal+卡价格参考$...

在 iPhone 上下载国外App

地区/国家限制App Store 会根据 Apple ID 的国家或地区限制应用下载。如果你的 Apple ID 绑定的是中国大陆,就可能无法下载 OpenAI 官方的 ChatGPT 应用,因为它在大陆 App Store 不上架。解决办法:换成美国、加拿大、香港等地区的 Apple ID。或者在现有 Apple ID 上更改地区。注册一个国外 Apple ID(推荐)比如注册 美国区 Appl...

Node.js 中的异步编程:回调与 Promise

Node.js 是一个基于 JavaScript 构建的单线程、非阻塞运行环境,它通过异步编程机制来高效处理多个操作。在执行如文件读取、API 请求或数据库查询等任务时,Node.js 不会等待这些操作完成,而是使用回调函数和 Promise 来避免阻塞主线程。 回调方式实现异步 那么当异步操作完成后,Node.js 如何知道接下来要做什么呢?这就要用到 回调函数(callback)。 回调本质上...

Selenium自动化测试入门指南

Selenium自动化测试入门指南

什么是自动化测试? 自动化测试是指利用软件工具自动执行测试用例,模拟用户操作,如打开网页、点击链接、输入文本等,并验证结果是否符合预期。 其主要优点包括: 大幅减少人工成本 测试速度快 可以在非工作时间运行 支持持续集成和交付 然而,它也存在一些局限性,例如开发成本较高、不适合快速变化的项目、依赖稳定的UI界面等。 自动化测试的应用条件 适合引入自动化测试的情况包括: 手动测试耗时且需要大量...

MariaDB Galera集群故障快速恢复指南

OpenStack控制节点采用三节点MariaDB Galera集群架构。当数据库集群因故障重启时,有时会出现Galera集群无法正常启动的问题。虽然有多种方法可以恢复数据库服务,但如何实现快速启动同时确保数据完整性呢? 通过分析日志发现,MariaDB Galera集群节点宕机时会在日志中输出以下信息: [Note] WSREP: 新集群视图:全局状态: 874d8e7e-5980-11e8-8...

Android 中 EventBus 的通信机制与实现原理深度解析

EventBus 核心设计思想 EventBus 是一个基于观察者模式的事件总线框架,广泛应用于 Android 平台以实现组件解耦。它通过中心化的消息分发机制,使不同层级、不同线程的对象能够以"发布-订阅"方式通信,避免了传统接口回调或广播带来的强依赖问题。 核心角色说明 事件(Event):任意 Java 对象,作为数据载体,如网络状态变更通知、用户登录信息等。 发布者(Publi...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。