归并排序
此代码为邓俊辉数据结构课堂归并排序代码,个人感觉很直观而且节省空间。
//
// Created by Lone Kriss on 2021/3/17.
//
#include <iostream>
#include <vector>
using namespace std;
void mergeSort(vector<int>& nums, int lo, int mi, int hi)
{
int i =0, j = 0, k = 0;
int* A = &nums[lo];
int lb = mi - lo;
int *B = new int[lb];
int *C = &nums[mi];
int lc = hi - mi;
for(int i = 0;i < lb; i++)
{
B[i] = A[i];
}
while(j < lb && k < lc)
{
A[i++] = (B[j] <= C[k]) ? B[j++] : C[k++];
}
while(j < lb)
{
A[i++] = B[j++];
}
delete[] B;
}
void merge(vector<int>& nums, int lo, int hi) //[lo,hi)
{
if( hi - lo < 2) return ;
int mi = (lo + hi) / 2;
merge(nums, lo, mi);
merge(nums,mi,hi);
mergeSort(nums, lo, mi, hi);
}
int main()
{
vector<int> nums{2,6,1,3,5,4,7,9,8};
merge(nums,0, nums.size());
for(auto c: nums)
{
cout<< c <<' ';
}
}
快排
该版本为 坐在马桶学算法 博客介绍的算法。
缺点在于每次选取左边界为排序基准点。
我们如果每次选取的基准恰好把数据分成0,N-1,则会倒是退化成o(N^2)。
//
// Created by Lone Kriss on 2021/3/17.
//
#include <iostream>
#include <vector>
using namespace std;
void quickSort(vector<int>& nums, int lo, int hi) //[lo,hi)
{
if(lo >= hi) return ; //递归终别忘了
int base = nums[lo];
int _lo = lo,_hi = hi - 1;
while(_lo < _hi)
{
while(nums[_hi] >= base && _lo <_hi)
{
_hi--;
}
while(nums[_lo] <= base && _lo <_hi)
{
_lo++;
}
swap(nums[_hi], nums[_lo]);
}
swap(nums[lo], nums[_lo]);
quickSort(nums,lo,_lo);
quickSort(nums, _lo+1,hi);
}
int main()
{
vector<int> nums{2,6,1,3,5,4,7,9,8};
quickSort(nums,0, nums.size());
for(auto c: nums)
{
cout<< c <<' ';
}
}
acwing版本:
#include <algorithm>
#include <iostream>
using namespace std;
void quick_sort(int q[], int l, int r)
{
if (l >= r) return;
int i = l - 1, j = r + 1, x = q[l + 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]);//记住判断
}
quick_sort(q, l, j), quick_sort(q, j + 1, r); //边界
}
int main(){
int N;
cin >> N;
int nums[100010];
for(int i= 0;i<N;i++){w
scanf("%d",&nums[i]);
}
quick_sort(nums,0,N-1);
//quickSort(nums,0,N-1);
for(int i= 0;i<N;i++){
cout << nums[i] <<' ';
}
return 0;
}
写法简洁,但是也避免不了如果中间值恰好把数据分成0,N-1.
如何避免
采用三数取中方法,在选取基准的时候选择左边界,中间,右边界之中的中间值作为基准,就可以避免最坏情况。
具体参考:
blog.csdn.net/liuyi120716…
对acwing排序过程中的一些疑惑
打印每一轮交换后的结果。可以看到第三轮base 49 并没有放它应该在的位置。
根据定义:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
那么第三轮迭代结果就不符合快排定义,因为49之后的31比49小却出现在了它左边。
但是该写法为什么又能保证最终结果是正确的?
以及为什么递归参数是j,j+1?
同时,如果使用该写法,因为选取的base 不一定放在了它本该在的位置上,所以类似 前k个最小数 就不能使用此写法了?
自问自答
之前思考受到了马桶法快排算法误导,认为选择的基数交换后一定会放在正确的位置上,实际上不是。
在每一轮迭代,数据被划分成2个区间[快排定义也说的很清楚是两个区间被排好序],小于等于基准的和大于基准的,例如上面第三轮[31 49 37] [88 97 68 54 59].
而j恰好是闭区间划分点,所以参数就是j和j+1.