本博客只基于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.奇数码问题