算法之链表
一 翻转链表
1.1 区域翻转链表
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 翻转列表
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;}
};