快速排序02

本文介绍了两种不同的方法解决求第k小的数问题,一种是利用快速排序(O(nlog2n)),另一种是变种快速排序(O(n)),并提及了利用随机基准元素减少最坏情况概率的优化版本。
摘要由CSDN通过智能技术生成
题目来源:【深基9.例4】求第 k 小的数 - 洛谷
解题思路:
解法1 对原数组进行快速排序,时间复杂度是 O(nlog2​n)
#include<iostream>
#include<algorithm>

using namespace std;

int a[5000010], k;


int main()
{
    ios_base::sync_with_stdio(false);//
    cin.tie(NULL);
    int n;
	cin >> n >> k;
	for (int i = 0; i < n; i++)
	{
		cin >> a[i];
	}

	sort(a, a + n);
	cout << a[k] << endl;

	return 0;

}

解法2 变种的快速排序,时间复杂度为O(n),利用分治的思想,如果 k 在左边的范围,则递归左边的数组;如果在右边,则递归右边的部分;但是也有可能两边都不属于(比如说 j=4 时 i=6,但是你要 k=5),那么在递归时可以省略掉这部分。

#include<iostream>

#define maxn 5000010

using namespace std;

int a[maxn], n,k,ans = 0;


void findkth(int a[], int l, int r)
{
	//引入数组的地址
	if (l == r)
	{
		ans = a[l];//区间长度为1时,记录答案
		return;
	}
	int i = l, j = r, flag = a[(l + r) / 2], tmp;
	do {
		while (a[i] < flag)i++;//从左边找比哨兵大的数
		while (a[j] > flag)j--;//从右边找比哨兵小的数
		if (i <= j)
		{
			//交换
			tmp = a[i];
			a[i] = a[j];
			a[j] = tmp;
			i++;
			j--;
		}
	} while (i <= j);
	if (k <= j)findkth(a, l, j);//第k小的数字在左区间
	else if (i <= k)findkth(a, i, r);//第k小的数字在右区间
	else findkth(a, j+1, i-1);//第k小的数字即不在左区间也不在右区间

}
int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin >> n >> k;
	for (int i = 0; i < n; i++)
	{
		cin >> a[i];
	}

	findkth(a, 0, n - 1);
	cout << ans << endl;

	return 0;

}

  下面代码,利用 srandtime 来设置随机种子,使用随机基准元素而不是中点元素,这样可以减少遇到最坏情况的概率。

#include<iostream>
#include<cstdlib> // 引入以使用rand()和srand()
#include<ctime>   // 引入以使用time()

#define maxn 5000010

using namespace std;

int a[maxn], n, k;

int findkth(int a[], int l, int r, int k) {
    if (l == r) {
        return a[l];
    }

    // 随机选择基准
    srand((unsigned)time(NULL));
    int pivotIndex = l + rand() % (r - l + 1);
    swap(a[pivotIndex], a[(l + r) / 2]);

    int flag = a[(l + r) / 2], i = l, j = r, tmp;
    do {
        while (a[i] < flag) i++;
        while (a[j] > flag) j--;
        if (i <= j) {
            tmp = a[i]; a[i] = a[j]; a[j] = tmp;
            i++; j--;
        }
    } while (i <= j);

    if (k <= j) return findkth(a, l, j, k);
    else if (k >= i) return findkth(a, i, r, k);
    return flag; // 当k在i和j之间时,说明找到了第k小的元素
}

int main() {
    ios::sync_with_stdio(false); // 关闭cin和stdout的同步,这样可以加快I/O速度
    cin.tie(NULL); // 解除cin与cout的绑定,这也可以稍微提高I/O性能

    cin >> n >> k;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }

    cout << findkth(a, 0, n - 1, k) << endl; // 直接打印返回的第k小元素

    return 0;
}

  • 14
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值