数组快排 链表归并

什么是数组快排

快速排序是一种:

分治思想的排序算法

平均时间复杂度 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 = a[l]

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)

稳定排序、实现简洁

相关推荐
李斯啦果2 小时前
【PTA】L1-019 谁先倒
数据结构·算法
Mr Xu_18 小时前
告别硬编码:前端项目中配置驱动的实战优化指南
前端·javascript·数据结构
czxyvX18 小时前
017-AVL树(C++实现)
开发语言·数据结构·c++
数智工坊18 小时前
【数据结构-队列】3.2 队列的顺序-链式实现-双端队列
数据结构
elseif12318 小时前
【C++】并查集&家谱树
开发语言·数据结构·c++·算法·图论
徐小夕@趣谈前端18 小时前
Web文档的“Office时刻“:jitword共建版2.0发布!让浏览器变成本地生产力
前端·数据结构·vue.js·算法·开源·编辑器·es6
Nebula_g19 小时前
线程进阶: 无人机自动防空平台开发教程(更新)
java·开发语言·数据结构·学习·算法·无人机
xuxie9920 小时前
day 23 树
数据结构
EnglishJun21 小时前
数据结构的学习(四)---栈和队列
数据结构·学习