数组快排 链表归并

什么是数组快排

快速排序是一种:

分治思想的排序算法

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

稳定排序、实现简洁

相关推荐
wabs6661 小时前
关于二叉树【力扣572.另一棵树的子树的思考】
数据结构·c++·算法·leetcode·二叉树
雨落在了我的手上3 小时前
Java数据结构(十四):Map和Set
数据结构
码行山野赴时序归途3 小时前
链表家族收官篇:循环链表
c语言·开发语言·数据结构·链表
船厂电气自动化ai大模型5 小时前
AI大模型与数学|第81天 课程:正交向量、正交基、格拉姆‑施密特(Gram‑Schmidt)正交化
开发语言·数据结构·人工智能·线性代数·机器学习
库玛西5 小时前
数据结构与算法之美:树、森林与二叉树全解析
c语言·数据结构·笔记·考研·算法·学习方法
careathers5 小时前
【数据结构】队列
java·数据结构
Rabitebla6 小时前
【Linux系统编程】指令(三):创建、删除、复制、移动、看内容
linux·数据结构·c++·算法
我不会起名字3227 小时前
一天一道力扣Hot100(36):深度优先算法---组合总和
数据结构·c++·后端·python·算法·go
雨落在了我的手上8 小时前
Java数据结构(十五):哈希表
数据结构
有点。18 小时前
C++03阶段练习(练习题)
数据结构·算法·图论