【算法】快速排序(第k小的数)

快速排序

2021.10.28

参考文章:(以起点作为分界点)

快速排序法(详解)_小白的博客-CSDN博客_快速排序假设对以下10个数进行快速排序:61279345108我们先模拟快速排序的过程:首先,在这个序列中随便找一个数作为基准数,通常为了方便,以第一个数作为基准数。61279345108在初始状态下,数字6在序列的第1位。我们的目标是将6挪到序列中间的某个位...https://blog.csdn.net/qq_40941722/article/details/94396010?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163537950516780366518379%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=163537950516780366518379&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-94396010.first_rank_v2_pc_rank_v29&utm_term=%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F&spm=1018.2226.3001.4187

 这里是以中间值作为分界点进行分治,这样减小时间复杂度O(n{log_{2}}^{n})

另外注意如果分界点选在边界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(n{log_{2}}^{n})

快速选择算法,找到第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;
}

猜你喜欢

转载自blog.csdn.net/nathanqian123/article/details/121022685