[链表] - 代码随想录 707. 设计链表

[链表] - 代码随想录 707. 设计链表

1. 题目要求

在链表类中需要实现以下功能:

  1. get(index) :获取链表中第 index 个节点的值(索引无效时返回 -1
  2. addAtHead(val) :在链表头部插入值为 val 的新节点
  3. addAtTail(val) :在链表尾部追加值为 val 的新节点
  4. addAtIndex(index, val)
    • 在指定索引 index 前插入新节点
    • index = 链表长度 时插入到末尾
    • index > 链表长度 时不插入
    • index < 0 时插入到头部
  5. deleteAtIndex(index):删除指定索引的节点(索引无效时不操作)

2. 实现代码

java 复制代码
/**
 * 单链表实现类
 * 核心技巧:使用虚拟头节点(dummy head)简化边界处理
 */
class MyLinkedList {
    // 虚拟头节点(不存储实际数据)
    private Node dummyHead;
    // 链表当前长度
    private int size;
    
    // 节点内部类
    private class Node {
        int val;
        Node next;
        
        Node(int val, Node next) {
            this.val = val;
            this.next = next;
        }
    }

    // 构造函数初始化空链表
    public MyLinkedList() {
        this.dummyHead = new Node(0, null); // 虚拟头节点
        this.size = 0;                      // 初始长度
    }
    
    /**
     * 获取节点值
     * @param index 目标索引(0-indexed)
     * @return 值或-1(索引无效时)
     */
    public int get(int index) {
        // 索引有效性检查
        if (index < 0 || index >= size) return -1;
        
        Node curr = dummyHead.next; // 从实际头节点开始
        // 遍历到目标节点
        for (int i = 0; i < index; i++) {
            curr = curr.next;
        }
        return curr.val;
    }
    
    /**
     * 头部插入
     * 时间复杂度:O(1)
     */
    public void addAtHead(int val) {
        // 新节点指向原头节点,虚拟头节点指向新节点
        dummyHead.next = new Node(val, dummyHead.next);
        size++;
    }
    
    /**
     * 尾部插入
     * 时间复杂度:O(n)
     */
    public void addAtTail(int val) {
        Node curr = dummyHead;
        // 遍历到最后一个节点
        while (curr.next != null) {
            curr = curr.next;
        }
        // 尾部插入新节点
        curr.next = new Node(val, null);
        size++;
    }
    
    /**
     * 指定位置插入
     * 处理三种特殊情况:
     * 1. index < 0 → 头部插入
     * 2. index = size → 尾部插入
     * 3. index > size → 不操作
     */
    public void addAtIndex(int index, int val) {
        // 处理负索引(插入头部)
        if (index < 0) {
            addAtHead(val);
            return;
        }
        // 超范围索引不操作
        if (index > size) return;
        
        Node curr = dummyHead;
        // 定位到插入位置的前驱节点
        for (int i = 0; i < index; i++) {
            curr = curr.next;
        }
        // 创建新节点并插入
        curr.next = new Node(val, curr.next);
        size++;
    }
    
    /**
     * 删除节点
     * 注意:需确保前驱节点.next不为空
     */
    public void deleteAtIndex(int index) {
        // 索引有效性检查
        if (index < 0 || index >= size) return;
        
        Node curr = dummyHead;
        // 定位到删除位置的前驱节点
        for (int i = 0; i < index; i++) {
            curr = curr.next;
        }
        // 跳过目标节点(自动GC回收)
        curr.next = curr.next.next;
        size--;
    }
}

/**
 * 使用示例:
 * MyLinkedList obj = new MyLinkedList();
 * int param_1 = obj.get(index);
 * obj.addAtHead(val);
 * obj.addAtTail(val);
 * obj.addAtIndex(index,val);
 * obj.deleteAtIndex(index);
 */

3. 关键实现细节

  1. 虚拟头节点(dummy head)

    • 始终位于链表头部之前,确保空链表操作统一
    • 消除头节点操作的特殊逻辑分支
    • 插入/删除操作无需单独处理头节点情况
  2. 时间复杂度控制

    操作 时间复杂度 说明
    addAtHead O(1) 直接操作虚拟头节点
    get O(n) 需遍历到指定位置
    addAtTail O(n) 需遍历到链表末尾
    addAtIndex O(n) 需遍历到目标位置前驱节点
    deleteAtIndex O(n) 需遍历到目标位置前驱节点
  3. 边界处理强化

    • 所有操作前进行索引有效性验证
    • addAtIndex 明确处理负索引和超范围索引
    • deleteAtIndex 确保不操作无效索引
  4. 结构设计要点

    • 内部 Node 类封装节点数据与指针
    • size 计数器实时维护链表长度
    • 所有操作后同步更新 size
相关推荐
Liu628885 小时前
C++中的工厂模式高级应用
开发语言·c++·算法
AI科技星5 小时前
全尺度角速度统一:基于 v ≡ c 的纯推导与验证
c语言·开发语言·人工智能·opencv·算法·机器学习·数据挖掘
条tiao条6 小时前
KMP 算法详解:告别暴力匹配,让字符串匹配 “永不回头”
开发语言·算法
干啥啥不行,秃头第一名6 小时前
C++20概念(Concepts)入门指南
开发语言·c++·算法
tobias.b6 小时前
计算机基础知识-数据结构
java·数据结构·考研
zzh940776 小时前
Gemini 3.1 Pro 硬核推理优化剖析:思维织锦、动态计算与国内实测
算法
2301_807367196 小时前
C++中的解释器模式变体
开发语言·c++·算法
愣头不青6 小时前
617.合并二叉树
java·算法
MIUMIUKK7 小时前
双指针三大例题
算法
灵感__idea7 小时前
Hello 算法:复杂问题的应对策略
前端·javascript·算法