[链表] - 代码随想录 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
相关推荐
scx201310042 小时前
20260112树状数组总结
数据结构·c++·算法·树状数组
FastMoMO2 小时前
Qwen3-VL-2B 在 RK3576 上的部署实践:RKNN + RKLLM 全流程
算法
光算科技2 小时前
AI重写工具导致‘文本湍流’特征|如何人工消除算法识别标记
大数据·人工智能·算法
宵时待雨2 小时前
数据结构(初阶)笔记归纳3:顺序表的应用
c语言·开发语言·数据结构·笔记·算法
智者知已应修善业2 小时前
【C语言 dfs算法 十四届蓝桥杯 D飞机降落问题】2024-4-12
c语言·c++·经验分享·笔记·算法·蓝桥杯·深度优先
罗湖老棍子2 小时前
最优乘车(travel)(信息学奥赛一本通- P1377)
算法·图论·bfs·最短路·字符串流·单向边
副露のmagic2 小时前
更弱智的算法学习 day36
学习·算法
core5122 小时前
SVD 算法详解:给数据做个“CT扫描”
算法·svd·图片压缩·目标函数
有一个好名字2 小时前
力扣-确定两个字符串是否接近
算法·leetcode·职场和发展