您的位置:首页 > 其它

算法探究:线性时间选择问题

2016-10-18 22:03 302 查看
一.什么是线性时间选择问题

前几天,女票问到了快速排序,然后我看了一下代码,发现不对呀,为什么连基本的递归都没有,后来仔细看了整个程序之后,发现,这个程序并不是普通的快速排序,而这也就引出了今天要讲的问题,线性时间选择问题,其实它也就是随机化的快速排序,以求加快效率,最快求解。

二.大体思路

RandomizedSelect算法,因为该算法是想要求解在一个序列中某一个等级大小的数,那么这个算法的大体思路其实就是随机选取基准元素,根据基准元素进行分区,小的分在左边,大的分在右边,每次分完之后返回基准元素所在数组中的索引,同时比较等级,小的话在左边查找,大的话在右边查找,那么这样说的话大家是不是又想到了快速排序算法,是不是特别熟悉呢。

三.具体实现

谈及具体实现的话,我还是先把代码贴上来然后一点一点地分析。

int RandomizedSelect(int a[],int low,int high,int k)
{
if(low==high)
return a[low];
int i=RandomizedPartition(a,low,high);
int j=i-low+1;
if(k<=j)
return RandomizedSelect(a,low,i,k);
else
return RandomizedSelect(a,i+1,high,k-j);
}
这就是其中最核心的部分。

03,04:和快排类似,倘若low==high,那么说明基准点已经到了我们需要的等级的位置,直接返回当前值。

05:假如不相等,那么就得重新分区。

06--10:重新分区之后,就得根据基准元素返回的索引考虑接下来往哪边寻找。

接下来是随机选取基准元素的函数

int RandomizedPartition(int a[],int low,int high)
{
Random rm = new Random();
int i = rm.Next(low,high);
Swap(a[i],a[low]);
return Partition(a,low,high);
}
前两句就是在新的分区里面寻找新的随机基准点,在这里我们把随机选取的基准点和第一个元素交换,因为后面分区的时候一直以第一个元素为基准,后两句就是重新分区。

最后就是分区函数,其实这里就用到了快排

int Partition(int a[],int low,int high)
{
int i=low,j=high+1;
int x=a[low];
while(true)
{
while(a[++i]<x&&i<high);
while(a[--j]>x);
if(i>=j) break;
Swap(a[i],a[j]);
}
a[low]=a[j];
a[j]=x;
return j;
}


相信这里就不用过多解释了,很容易理解。

最后附上整个实例。

#include<iostream>
#include<cstdlib>
#include<time.h>
using namespace std;

void Swap(int &a,int &b)
{
int tmp=a;
a=b;
b=tmp;
}

int Partition(int a[],int low,int high) { int i=low,j=high+1; int x=a[low]; while(true) { while(a[++i]<x&&i<high); while(a[--j]>x); if(i>=j) break; Swap(a[i],a[j]); } a[low]=a[j]; a[j]=x; return j; }

int RandomizedPartition(int a[],int low,int high) { Random rm = new Random(); int i = rm.Next(low,high); Swap(a[i],a[low]); return Partition(a,low,high); }

int RandomizedSelect(int a[],int low,int high,int k) { if(low==high) return a[low]; int i=RandomizedPartition(a,low,high); int j=i-low+1; if(k<=j) return RandomizedSelect(a,low,i,k); else return RandomizedSelect(a,i+1,high,k-j); }

/* 测试 */
int main()
{
int a[]={4,7,9,5,8,3,0,1};
int k=2;
int result=RandomizedSelect(a,0,7,k);
cout<<"第"<<k<<"小的元素是"<<result<<endl;
return 0;
}



四.总结

首先要强调的是,RandomizeSelect算法,最好能够达到O(n)的时间复杂度,这时很不错的,另外最坏也是O(n*n),而不是像一些普通算法,平均复杂度是O(n*n),其次呢,该算法跟数据的准备还是有比较大的关系的,这个我们之后再另外写一篇好好叙述。总的说来呢,我主要是看到之后耳目一新,自己实现了一下,其实我完全是算法方面的小白,如果有错误还希望指正。

  email: wuzhicheng@bjfu.edu.cn  

  谢谢!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: