1.快速排序
i找到>=x的数后停止,j找到<=x的数后停止,如果i<j就交换,否则就递归分出来的两段
1.1 步骤:
- 确定分界点:由于跳出循环时是i == j或者j = i - 1,当j = i - 1时,由于i找到>=x的数停止,当[i]==x时,j走过去也会因为==[x]而停止;当[i]>x时,j会走过去走到左边就遇到小数停止了。所以拿[l,j]和[j+1,r]会将两段分开,[l,i-1]和[i,r]也可以,这样左段是<=x的数,右段是>=x的数。
- 调整左段是<=x的数,右段是>=x的数,x不一定在中间
- 递归左右两边
- 取整方式:采用[l,j]和[j+1,r]需要下取整,因为假如数组[1,2],上取整的话,i==j==1,永远是[1,2]递归;同理[l,i-1]和[i,r]要上取整~
1.2 基本代码
#include <iostream>
using namespace std;
const int N = 1e6 + 10;//开辟一个最大数组
int n;
int q[N];
void quick_sort(int q[], int l, int r)
{
if(l >= r) return;//为空或者只有一个值返回
//第一步确定边界点,此处用中间那个值
int x = q[l + r >> 1], i = l - 1, j = r + 1;//这样可以方便判断第一个数和最后一个数
while ( i < j)
{
do i ++ ; while (q[i] < x);
do j -- ; while (q[j] > x);
if ( i < j) swap(q[i], q[j]);//手写swap:int t = q[i];q[i]=q[j];q[j]=t
}
quick_sort(q,l,j);
quick_sort(q,j + 1,r);
}
int main()
{
scanf("%d",&n);
for(int i = 0; i < n; i ++) scanf("%d",&q[i]);//输入数组
quick_sort(q, 0, n-1);//快排数组q中0到n-1的字段
for(int i = 0;i < n;i ++) printf("%d ",q[i]);//输出答案,注意q[i]不加&
return 0;
}
1.3 最小的k个数
#include <iostream>
using namespace std;
const int N = 100010;
int n, k;
int q[N];
int quick_sort(int l,int r,int k)
{
if(l == r) return q[l];//区间长度是1的时候一定是答案:因为每次都会按照某个值大小从中间分开,所以会不断缩小范围
int x = q[l],i = l - 1,j = r + 1;
while(i < j)
{
while(q[ ++ i] < x);//求最大的k个数做法一样,左边找>x右边找<x即可
while(q[ -- j] > x);
if(i < j) swap(q[i], q[j]);
}
int sl = j - l + 1;//多了计算个数的部分
if(k <= sl) return quick_sort(l, j, k);
return quick_sort(j + 1, r, k-sl);
}
int main()
{
cin>>n>>k;
for(int i = 0;i < n;i ++) cin>>q[i];
cout<<quick_sort(0, n - 1, k)<<endl;
return 0;
}
1.4 347. 前 K 个高频元素
class Solution {
public:
/*
在快排模版基础上改为PII:值-频率 的数据结构,对频率快排即可
*/
using PII = pair<int,int>;
vector<PII> arra;
vector<int> res;
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> mp;
for(auto i: nums) mp[i] ++;
for(auto p: mp) arra.push_back(p);
quick_sort(k, 0, arra.size() - 1);
return res;
}
void quick_sort(int k, int l, int r)
{
if(l == r)
{
res.push_back(arra[l].first);
return;
}
PII x = arra[(l + r) >> 1];
int i = l - 1, j = r + 1;
while(i < j)
{
do ++ i; while(arra[i].second > x.second);
do -- j; while(arra[j].second < x.second);
if(i < j) swap(arra[i],arra[j]);
}
if(j - l + 1 >=k) quick_sort(k, l, j);//左边够了
else
{
for(int m = l; m <= j; m ++)
res.push_back(arra[m].first);
quick_sort( k - (j - l + 1), j + 1, r);
}
}
};
1.5 973. 最接近原点的 K 个点
class Solution {
public:
vector<vector<int>> res;
using PII = pair<vector<int>, int>;
vector<PII> arra;
vector<vector<int>> kClosest(vector<vector<int>>& points, int k) {
for(auto p: points) arra.push_back(make_pair(p,p[0]*p[0]+p[1]*p[1]));
quick_sort(0, arra.size() - 1,k);
return res;
}
void quick_sort(int l, int r, int k)
{
if(l == r)
{
res.push_back(arra[l].first);
return;
}
PII x = arra[(l + r) >> 1];
int i = l - 1, j = r + 1;
while(i < j)
{
do i ++; while(arra[i].second < x.second);
do j --; while(arra[j].second > x.second);
if(i < j) swap(arra[i], arra[j]);
}
int left = j - l + 1;
if(k <= left) quick_sort(l, j, k);
else
{
for(int t = l; t <= j; t ++) res.push_back(arra[t].first);
quick_sort(j + 1, r, k - left);
}
}
};
2.归并排序
2.1 步骤
- 确定分界点:q[l + r >> 1]
- 递归左右排序
- 归并合二为一:o(n)辅助数组tmp
2.2 基本代码
#include <iostream>
using namespace std;
const int N = 1000010;
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);
//第三步归并,用辅助数组tmp
int k = 0, i = l, j = mid + 1;
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 ++];
//归并后把[l,r]复制回去
for(i = l, j = 0; i<= r;i ++,j ++) q[i] = tmp[j];
}
int main()
{
scanf("%d",&n);
for(int i = 0;i < n; i ++) scanf("%d",&q[i]);
merge_sort(q,0,n-1);
for(int i = 0;i < n; i ++) printf("%d ",q[i]);
return 0;
}
2.3 剑指 Offer 51. 数组中的逆序对
class Solution {
public:
int tmp[50010];
vector<int> q;
int reversePairs(vector<int>& nums) {
int n = nums.size();
if(nums.empty()) return 0;
q = nums;
int res = merge_sort(0, n - 1);
return res;
}
int merge_sort(int l, int r)
{
if(l == r) return 0;
int mid = (l + r) >> 1;
long long res = merge_sort(l, mid) + merge_sort(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
{
res += mid - i + 1;//当第16行的子层返回的是res = 0+0时,这里需要加上那里的结果,再作为子层返回到上一层的16行,其实递归就是这样的,递归在最后,则顺序的执行下去,直到执行结束,在中间则到叶子节点后返回,才会执行下半段的内容
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;) q[i ++] = tmp[j ++];
return res;
}
};