算法学习笔记(2)——归并排序

归并排序

归并排序的思想是基于分治法,其思路是:

  • 将待排序区间平分成左右两半,左右两侧分别递归地做归并排序。
  • 将这两个有序的区间合并(每次落一个较小的下来),就将这个区间排好序了。

归并排序相比快速排序,几乎没有什么难理解的边界问题。要注意代码中的q[i] <= q[j]时从左半边落下元素,如果改成q[i] < q[j]也是能正确排序的,但是这样会丢失【归并排序是稳定的】这个特性。要保持这个特性,在排序字段相等的时候,应该落下来自左侧区间的元素,所以这里用<=

我们知道,归并排序的过程中,需要对当前区间进行对半划分,直到区间的长度为1。也就是说,每一层的子区间,长度都是上一层的1/2。这也就意味着,当划分到第 logn 层的时候,子区间的长度就是1了。

而归并排序的merge操作,则是从最底层开始(子区间为1的层),对相邻的两个子区间进行合并,对于每一层来说,在合并所有子区间的过程中,n 个元素都会被操作一次,所以每一层的时间复杂度都是 O(n)。而之前我们说过,归并排序划分子区间,将子区间划分为只剩 1 个元素,需要划分 logn 次。每一层的时间复杂度为 O(n),共有 logn 层,所以归并排序的时间复杂度就是O(nlogn)

题目链接:AcWing 787. 归并排序

#include <iostream>

using namespace std;

const int N = 100010;

int n;
int q[N], tmp[N];

void merge_sort(int q[], int l, int r)
{
    if (l >= r) return;
    
    int mid = l + r >> 1;
    merge_sort(q, l, mid), merge_sort(q, mid + 1, r);
    
    int i = l, j = mid + 1, k = 0;
    while (i <= mid && j <= r) {
        if (q[i] < q[j]) tmp[k ++] = q[i ++];
        else             tmp[k ++] = q[j ++];
    }
    while (i <= mid) tmp[k ++] = q[i ++];
    while (j <= r)   tmp[k ++] = q[j ++];
    
    for (int i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
}

int main()
{
    cin >> n;
    for (int i = 0; i < n; i ++ ) cin >> q[i];
    merge_sort(q, 0, n - 1);
    for (int i = 0; i < n; i ++ ) cout << q[i] << ' ';
    return 0;
}
posted @   S!no  阅读(54)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示