数组快排 链表归并

什么是数组快排

快速排序是一种:

分治思想的排序算法

平均时间复杂度 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)

稳定排序、实现简洁

相关推荐
UIU1146 小时前
P1233 [ICPC 2001 Taejon R] 木棍加工
数据结构·c++·算法·动态规划
niyongsheng9 小时前
3D 装箱算法工程化:数据结构、放置启发式与支撑规则
数据结构·算法·rust
叉烧滑蛋11 小时前
B站台湾大学郭彦甫|MATLAB 学习笔记|04 变量与档案存取
数据结构
j7~12 小时前
【穷举、深搜与回溯算法】一棵决策树讲透全排列与子集
数据结构·c++·算法·leetcode·回溯·递归
not coder14 小时前
一文讲通--从树到红黑树
数据结构·算法
爱吃香菜的初学者15 小时前
八.数据结构——哈希表(1)
数据结构·散列表
二十七日秋17 小时前
算法刷题笔记「Day 1|四道 OJ 入门题里的深坑」
c语言·汇编·数据结构·c++·笔记·python·算法
小白起 v18 小时前
02-数组与链表
数据结构·链表
路灯上の马陈1 天前
二叉树的定义与性质
数据结构·二叉树·树结构·1024程序员节
Bshaya_1 天前
红黑树详解:概念、规则与插入实现
数据结构·红黑树·二叉搜索树·平衡树·插入逻辑