分治算法—求大数的top k问题

目录

引入

快排划分函数的思想

快排划分步骤如图​

代码实现


引入

例如问题需要求10万个整数中,值最大(小)的第10 个元素或者值最大(小)的前10个元素。

10万个整数如果是有序的那会很简单的就求出,但是如果是无序的,那就很困难。如果我们要将10万个数全部排序的话,那也是效率极低的。这时我们可以采用快排的划分函数的方法来解决此问题。

快排划分函数的思想

每次设置一个基准数,大于基准数的值放在右边,小于基准数的值放在左边,最后将基准数放在合适的位置,并且记录基准数的下标。

快排划分步骤如图

 

求值最小思想:将基准数所在的位置与topk的 k-1(因为这里的k值是数学中的k,需要-1变成下标k)比较,基准数和top k的k -1值相等了,直接返回基准数的下标,不用再继续寻找了,基准数就是要找的第k个元素,前k个元素就是基准数左边的所有元素。当基准数小于top k的k -1值 则需要在基准数的右边进行查找。当基准数大于top k的k -1值 则需要在基准数的左边进行查找。

求值最大思想:将基准数所在的位置与topk的 k比较,基准数和top k的k 值相等了,直接返回基准数的下标,不用再继续寻找了,基准数就是要找的第k个元素,前k个元素就是基准数左边的所有元素。当基准数小于top k的k 值 则需要在基准数的右边进行查找。当基准数大于top k的k 值 则需要在基准数的左边进行查找。

代码实现

#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int partation(vector<int> &vec, int i, int j)  
{
	int val = vec[i];
	int l = i;
	int r = j;
	while (l < r)
	{
		while (l < r && vec[r] >= val)
		{
			r--;
		}
		if (l < r)
		{
			vec[l++] = vec[r];
		}
		while (l < r && vec[l] <= val)
		{
			l++;
		}
		if (l < r)
		{
			vec[r--] = vec[l];
		}
	}
	vec[l] = val; //放置基准数
	return l; //返回基准数下标
}
int min_select_topk(vector<int> &vec, int i, int j, int k)
{
	int ret = partation(vec, i, j); //表示基准数的位置
	if (ret == k - 1) //基准数和top k的k -1值相等了  (这里的k值是数学中的k,需要-1变成下标k)
	{
		return ret;
	}
	else if (ret < k - 1) //基准数小于top k的k -1值 则需要在基准数的右边进行查找
	{
		return min_select_topk(vec, ret + 1, j, k);
	}
	else { //基准数大于top k的k -1值  则需要在基准数的左边进行查找
		return min_select_topk(vec, i, ret - 1, k);
	}
}
int max_select_topk(vector<int> &vec, int i, int j,int k)
{
	int pos = partation(vec, i, j); //表示基准数的位置
	if (pos == vec.size() - k) //基准数和top k的k值相等了
	{
		return pos;
	}
	else if (pos < vec.size() - k) //基准数小于top k的k值 则需要在基准数的右边进行查找
	{
		return max_select_topk(vec, pos + 1, j, k);
	}
	else { //基准数大于top k的k值  则需要在基准数的左边进行查找
		return max_select_topk(vec, i, pos - 1, k);
	}
}
int main()
{
	vector <int> vec;
	for (int i = 0; i < 11; ++i)
	{
		vec.push_back(rand() % 100);
	}
	for (int v : vec)
	{
		cout << v << " ";
	}
	cout << endl;
	int pos = max_select_topk(vec, 0, vec.size() - 1, 4);
	cout << "第topk大:" << vec[pos] << endl;
	cout << "前topk大:";
	for (int i = pos; i < vec.size(); ++i)
	{
		cout << vec[i] << " ";
	}
	cout << endl;
	int ret = min_select_topk(vec, 0, vec.size() - 1, 4);
	cout << "第topk小:" << vec[ret] << endl;
	cout << "前topk小:";
	for (int i = 0; i <= ret; ++i)
	{
		cout << vec[i] << " ";
	}
	cout << endl;
	sort(vec.begin(), vec.end());
	for (int v : vec)
	{
		cout << v << " ";
	}
	cout << endl;
	system("pause");
	return 0;
}

11个数的结果如图:

 100个数的结果如图:

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值