数组快排 链表归并

什么是数组快排

快速排序是一种:

分治思想的排序算法

平均时间复杂度 O(n log n)

原地排序(不需要额外数组)

实际中 非常快(STL sort 的核心思想之一)

核心一句话:

选一个 " 基准值 " ,把数组分成 " 比它小的 " " 比它大的 " ,递归排序

快排的直觉理解

假设有数组:

5, 1, 6, 2, 4, 3

选一个基准值

一般选:

第一个元素

最后一个元素

或中间元素

比如选 5作为基准值

一趟划分

目标是:

左边 <= 5 | 5 | >= 5 右边

执行完一趟后,5 会到它最终该在的位置

结果可能变成:

3, 1, 4, 2\] 5 \[6

注意:

左右两边不一定有序

5 的位置已经确定,不会再动

递归排序左右两部分

对左边 3,1,4,2 再做快排

对右边 6 不用排

快排的核心: 划分

常见做法:左右指针法(最经典)

假设:

pivot = al

i = l

j = r

步骤:

  1. 从右往左找 < pivot 的
  2. 从左往右找 > pivot 的
  3. 交换它们
  4. 重复,直到 i == j
  5. 把 pivot 放到中间位置

代码:

cpp 复制代码
void quickSort(int a[], int l, int r)
{
    if (l >= r) return;
int pivot = a[l];
    int i = l, j = r;
while (i < j)
    {
        // 从右往左找比 pivot 小的
        while (i < j && a[j] >= pivot) j--;
        // 从左往右找比 pivot 大的
        while (i < j && a[i] <= pivot) i++;
if (i < j)
            swap(a[i], a[j]);
    }
// pivot 放到正确位置
    swap(a[l], a[i]);
quickSort(a, l, i - 1);
    quickSort(a, i + 1, r);
}

时间复杂度

|-----------|------------|
| 情况 | 复杂度 |
| 平均 | O(n log n) |
| 最坏(已排序数组) | O(n²) |

为了避免最坏情况,实际中会:

随机选 pivot

或三数取中

链表归并排序核心思想

:用快慢指针把链表从中间断开

:递归排序左右两条链表

:合并两个有序链表

完美适配链表结构。

链表节点定义

cpp 复制代码
struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
};

主函数:链表归并排序

cpp 复制代码
ListNode* mergeSortList(ListNode* head)
{
    // 递归结束条件
    if (!head || !head->next)
        return head;
//  快慢指针找中点
    ListNode* slow = head;
    ListNode* fast = head->next;
while (fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
    }
// 断开链表
    ListNode* mid = slow->next;
    slow->next = nullptr;
//  递归排序左右部分
    ListNode* left = mergeSortList(head);
    ListNode* right = mergeSortList(mid);
// 合并两个有序链表
    return mergeTwoLists(left, right);
}

合并两个有序链表

cpp 复制代码
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2)
{
    ListNode dummy(0);
    ListNode* tail = &dummy;
while (l1 && l2)
    {
        if (l1->val <= l2->val)
        {
            tail->next = l1;
            l1 = l1->next;
        }
        else
        {
            tail->next = l2;
            l2 = l2->next;
        }
        tail = tail->next;
    }
// 接上剩余部分
    tail->next = l1 ? l1 : l2;
return dummy.next; 
}

复杂度分析(面试必说)

|--------|-------------------|
| 项目 | 复杂度 |
| 时间复杂度 | O(n log n) |
| 空间复杂度 | O(log n)(递归栈) |
| 是否稳定 | 稳定 |
| 是否原地 | (不新建节点) |

为什么链表「一定选归并排序」

三大理由:

不需要随机访问

合并链表天然 O(n)

稳定排序、实现简洁

相关推荐
positive_zpc30 分钟前
进阶数据结构图——关键路径(四)
数据结构·图论·关键路径
孙克旭_1 小时前
单链表进阶实操:5 道常考面试题详细解析【Java 实现】
java·开发语言·数据结构·单链表
Chester_19992 小时前
CSP202206C.角色授权
开发语言·数据结构·c++·蓝桥杯
旖旎夜光2 小时前
LeetCode 238:除自身以外数组的乘积(前缀和) —— 题解
数据结构·c++·算法·leetcode·前缀和
一条大祥脚2 小时前
26杭电暑期第八场(后半)快读|快写|tarjan|路径DP|mex转化|扫描线|前缀和|二分图
数据结构·算法·tarjan·杭电多校·强联通分量·动态规划dp
Chester_199911 小时前
CSP202203C.计算资源调度器
开发语言·数据结构·c++·蓝桥杯
专注仿真16 小时前
Spring AI 实现智能对话系统项目指南
数据结构·spring·机器学习
间歇性努力持续性发呆的野生快乐选手17 小时前
高级数据结构:树状数组
数据结构
每周报刊21 小时前
竞速座舱级视界:爱攻 AGP497UCZD 超宽 QDOLED 显示器解析
数据结构·游戏·计算机外设
布莱克6051 天前
链表详解:定义、作用、应用场景及与数组的区别(C/C++ 实战)
c语言·开发语言·c++·链表