分治算法求n个元素序列中第k个大的元素

版权声明:@ly https://blog.csdn.net/lytwy123/article/details/82884540

     首先,我们应该设定产生随机数的序列存储在数组中,然后我们应该最容易想到的是排序对吧,做一个降序排序,就很容易找到第k个大的元素。但是用排序算法的话,时间复杂度最快的也是快速排序O(logn),如果我们使用分治算法求得话,会得到一个线性的时间复杂度O(n)。分治算法是将一个问题分成若干个子问题去实现。分治算法是离不开递归算法的。

怎么实现?

我们可以在数组中产生一个随机的下标,让他作为一个标志,然后我们可以先将比改下标对应的元素大的放在该下标所对应的元素放在左边区间,小的放在右边区间。

然后我们可以模仿二分查找来寻找第k个大的元素,首先我们在将大的元素放在左边区间的循环中加入一个计数器,我们可以统计在标志下标左边区间的元素数量是多少,既然我们要找的是第k个大的元素,我们可以将k与计数器比较,如果小于左边区间的元素个数,那么第k个大的元素必然在左区间,我们就可以使用递归继续找,反之,如果大于计数器说明在右边区间,我们就递归右边区间即可。

算法源代码实现:

#include<iostream>
#include<cstdlib>
#include<ctime>
#include<algorithm>
using namespace std;
int num[1000];

int random(int a,int b) 
{

	 return (rand()%(b-a+1)+a);
}

int  find(int a[],int left,int right,int k)
{
	int index = random(left,right - left + 1);    //随机选取一个下标的元素作为定值来进行比较 
	swap(a[left],a[index]);
	int middle = left;
	int count = 1;                     //记录比选定元素大的元素的个数 
	int i,j;
	for(i = left + 1;i<=right;i++)     //计算所选定的元素左边的元素的个数 
	{
		if(a[i]>a[left])  			 	//将大的元素排在所选定点得左边 
		{
			count++;
			middle++; 
			swap(a[middle],a[i]);      
		}
	} 

	swap(a[middle],a[left]);   

	if(k<count){ 					//如果需要找的第k个大的元素小于左边的元素数量,那么第k个大的元素一定在这个区间,在递归调用去找 
		find(a,left,middle-1,k);
	}
	else if(k>count){			//相反的,如果大于左边元素数量,则在右边的区间找 
		find(a,middle+1,right,k-count);
	}
	else
		return a[middle];   //如果k==count说明要找的元素是在middle 
	
}


int main()
{
	srand((unsigned)time(0));
	int n,k;
	cout<<"请输入产生多少个元素:"<<endl;
	cin>>n;
	cout<<"寻找第k个最大元素"<<endl;
	cin>>k;
	for(int i = 0;i<n;i++)
	{
		num[i] = random(1,100);
	}
	
	for(int i = 0;i<n;i++)
	{
		cout<<num[i]<<",";
	}
	cout<<endl;
	cout<<find(num,0,n-1,k);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/lytwy123/article/details/82884540