算法之链表

一 翻转链表

1.1 区域翻转链表

cpp 复制代码
class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        // 1. 创建虚拟头节点 dummy,其 next 指向原链表头节点
        // 作用:统一处理 left=1 的边界情况(此时反转起点是原链表头,需要一个前驱节点)
        ListNode dummy(0, head);  // 示例:dummy -> 1 -> 2 -> 3 -> 4 -> 5
  
        // 2. 定义 p0 指针,初始指向 dummy,用于定位「反转区间的前一个节点」
        ListNode* p0 = &dummy;
        
        // 3. 将 p0 移动到「反转区间的前一个节点」(即第 left-1 个节点的位置)
        // 循环次数:left-1 次(因为从 dummy 开始,dummy 是第 0 个节点)
        // 示例:left=2,循环 1 次后,p0 指向 1(此时 p0->next 是 2,即反转起点)
        for (int i = 0; i < left - 1; i++) {
            p0 = p0->next;
        }

        // 4. 初始化反转用的指针:pre 记录前一个节点,cur 记录当前节点
        ListNode* pre = nullptr;       // 初始为空(反转的第一个节点的前一个是 null)
        ListNode* cur = p0->next;      // cur 指向反转区间的第一个节点(示例:cur 初始指向 2)
        
        // 5. 反转「left 到 right」之间的节点(共 right-left+1 个节点)
        // 每次循环将 cur 节点的 next 指向 pre,完成单个节点的反转
        for (int i = 0; i < right - left + 1; i++) {
            ListNode* nxt = cur->next;  // 先保存 cur 的下一个节点(防止丢失后续链表)
            cur->next = pre;            // 反转:当前节点指向前一个节点(核心步骤)
            pre = cur;                  // pre 后移:指向当前节点(下一次循环的「前一个节点」)
            cur = nxt;                  // cur 后移:指向之前保存的下一个节点
        }
        // 循环结束后:
        // pre 指向反转区间的最后一个节点(即反转后的新头部,示例:pre=4)
        // cur 指向反转区间后的第一个节点(示例:cur=5)

        // 6. 连接反转后的链表与原链表的前后部分
        // p0->next 是反转前的第一个节点(现在是反转后的最后一个节点,示例:p0->next=2)
        // 让其 next 指向 cur(反转区间后的节点,示例:2->5)
        p0->next->next = cur;
        // 让 p0 的 next 指向 pre(反转后的新头部,示例:1->4)
        p0->next = pre;
        
        // 7. 返回虚拟头节点的 next(即反转后的链表头)
        return dummy.next;
    }
};

【1】dummy node :开始节点的前驱节点,这个节点是new出来的

【2】需要理解指针的含义,即使链表的指针本质上也是相同的

【3】翻转部分就是翻转列表的基础代码

1.2 翻转列表

cpp 复制代码
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* prev = nullptr;
        ListNode* curr = head;
        while(curr){
            ListNode* next = curr->next;
            curr->next = prev;
            prev = curr;
            curr = next;
        }
        return prev;
        
    }
};