AcWing 算法基础课 排序总结(持续更新中······)

本文详细介绍了快速排序和归并排序的算法思想、AC代码及应用,并提供了相关题目链接。快速排序平均时间复杂度为O(nlogn),最坏情况为O(n^2);归并排序稳定且时间复杂度始终为O(nlogn)。通过实例解析了两种排序算法的递归边界问题和逆序对计算。同时推荐了一篇排序算法详解博客和一个算法学习网站。
摘要由CSDN通过智能技术生成

本博客只基于AcWing算法基础刷题总结,话不多说,先上总图

在这里插入图片描述

快速排序

题目链接:AcWing 785.快速排序
快速排序思想:主要思想是分治。先任意取一个数x(一般取区间中间那个数),然后把小于x的数放在x的左边,大于x的数放在x的右边,然后依次递归下去,最后得到的就一定是有序的。(PS:快排最差时间复杂度为 O ( n 2 ) O(n^{2}) O(n2)
AC代码如下:

#include<bits/stdc++.h>

using namespace std;

const int MAXN = 1e5 + 10;
int arr[MAXN];
int n;

void Q_sort(int begin, int end)
{
    if(begin >= end)//如果没有数,或者只有一个数就不用排了,直接返回
        return;
    int l = begin - 1;
    int r = end + 1;
    int k = arr[(l + r) >> 1];
    while(l < r)//这里用到了双指针
    {
        //依次找到大于k的数
        while(arr[++l] < k);//不管那么多,先把l+1,这也就解释了上面最开始要把l赋值成begin-1
        //依次找到小于k的数
        while(arr[--r] > k);//不管那么多,先把r-1,这也就解释了上面最开始要把l赋值成end+1
        if(l < r)
            swap(arr[l], arr[r]);//交换,这里可以用C++的内置交换函数swap
    }

    //程序进行到这里,k左端都是小于k的,k右端都是大于k的,但是k的两端内部不一定是有序的,这里保证里k两端的数与k这个数的相对大小关系
    Q_sort(begin, r);//注意这里边界问题,更多边界问题详看下面链接
    Q_sort(r + 1, end);
}

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &arr[i]);
    Q_sort(1, n);
    for(int i = 1; i <= n; ++i)
        printf("%d ", arr[i]);

    return 0;
}
特别注意:Q_sort()函数最低下两行递归代码的边界问题,也就是(begin,r)和(r+1,end),这里为什么要用r和r+1。这个问题非常复杂,需要严格证明,但是如果懒的话直接记住就可以了。点击详看大佬的严格证明

快速排序的应用题目

题目链接:数组中第K个最大的元素

归并排序

题目链接 :AcWing 787.归并排序
归并排序思想:主要思想也是分治。但与快排不同,快排是先排序再递归,归并排序是先递归再排序(也就是归并,把两个有序区间合并成一个有序区间),AC代码如下:

#include<bits/stdc++.h>
using namespace std;

const int MAXN=1e6+10;
int arr[MAXN];
int temp[MAXN];
int n;

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

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
        scanf("%d",&arr[i]);
    merge_sort(1,n);
    for(int i=1;i<=n;++i)
        printf("%d ",arr[i]);
    return 0;
}

归并排序的应用,求逆序对

题目链接:AcWing 788.逆序对
求逆序对用到了归并排序的思想,因为每次合并一次区间时,被合并的两个区间一定是有序的,所以可以根据这来求逆序对的数量,AC代码如下:(PS,结果要开成全局变量)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN = 1e5 + 10;
int arr[MAXN];
int temp[MAXN];
int n;
ll ans = 0;

void merge_sort(int begin, int end)
{
    if(begin >= end)
        return;
    int mid = (begin + end) >> 1;

    merge_sort(begin, mid);
    merge_sort(mid + 1, end);

    int l = begin, r = mid + 1;
    int k = 1;

    while(l <= mid && r <= end)
    {
        if(arr[l] <= arr[r])
            temp[k++] = arr[l++];
        else
        {
            temp[k++] = arr[r++];
            ans += mid - l + 1;
        }
    }
    while(l <= mid)
        temp[k++] = arr[l++];
    while(r <= end)
        temp[k++] = arr[r++];
    for(int i = begin, j = 1; i <= end; ++i, ++j)
        arr[i] = temp[j];
}

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &arr[i]);
    merge_sort(1, n);
    printf("%lld", ans);
}

逆序对的应用

逆序对的应用还是非常广泛的,很多比较难的题目其实就是一个逆序对,看出来就简单了,看不出来那就是真看不出来了。
题目链接:
AcWing 108.奇数码问题

另附一个大佬写的博客,里面有十种排序详解,点击即达
再附一个旧金山大学的算法学习网站,点击即达!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值