快速排序
2021.10.28
参考文章:(以起点作为分界点)
这里是以中间值作为分界点进行分治,这样减小时间复杂度O()
另外注意如果分界点选在边界begin或end,在递归排序的时候会有些特殊情况
例如分界点=begin;quicksort第三个参数不能写i-1;会出现边际问题
故最稳妥的方案还是选择begin+end/2作为分界点;
快速排序(标准解法模板)
const int N = 1e5 + 10;
int n;
int a[N];
分界点设为中间值作为基准数,分治思想
void quicksort(int arr[], int begin, int end)
{
if (begin == end)
return;
传入首尾地址重合时结束递归
int mid = arr[(begin+end)>>1];
取中间数为分界,分界数不要取首位点,一是会出现边界问题,二是运算时间会大于取中间数的情形
int i = begin-1;
int j = end+1;
这里-1的意思是为了方便边界判断,先移动哨兵再进行判断
while (i < j)
{
do i++; while (arr[i] < mid);
do j--;while (arr[j] > mid);
if (i < j)
{
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
quicksort(arr, begin,j);
递归调用快排函数,将基准数前面的数字用同样的方法排序
quicksort(arr, j+1, end);
递归调用快排函数,将基准数后面的数字用同样的方法排序
}
int main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0);
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
quicksort(a, 0, n - 1);
for (int i = 0; i < n; i++)
{
cout << a[i] << ' ';
}
return 0;
}
第K小的数
2021.10.29
采用快速排序的算法,函数最后一个IF句判断,如果k在当前左半边区间大小内,则继续对左边进行排序并压缩区间,如果跑到右边就对右边排序并压缩区间。
直到区间被压缩成1输出当前区间元素值即要找的k
时间复杂度O()
快速选择算法,找到第k小数
原理与快速排序一样,每次以中间数做分界点,直到区间大小为1的时候即要查找的数
const int N = 1e5 + 10;
int n, k;
int q[N];
int quicksort(int begin, int end, int k)
{
if (begin == end) return q[begin];
当递归到只剩一个数的时候,这个数必然是所选择的数
int x = q[(end+begin)>>1],i = begin - 1,j = end + 1;
解释同快速排序
while (i < j)
{
while (q[++i] < x);
while (q[--j] > x);
if (i < j) swap(q[i], q[j]);
}
int s1 = j - begin + 1;
基准数左边的元素个数此时的i=j;
if (k <= s1)return quicksort(begin,j,k);
else
return quicksort(j + 1, end, k - s1);
}
int main()
{
cin >> n >> k;
for (int i = 0; i < n; i++)
cin >> q[i];
cout << quicksort(0, n - 1, k) << endl;
}