假设数组是互异的,选择算法获得数组中的顺序统计量,期望时间为O(n),最坏时间为O(n平方)
算法有一些与快速排序相似,对数组选定参考元素左右分类以后,左边是小于参考元素reference的,右边是大于reference的,然后检查一下reference的位置,是i就对了,不是i就递归调用。同样可以通过数组随机重排来达到平均期望时间
//获得顺序统计量的选择算法
#include <iostream>
#include <time.h>
#include <stdlib.h>
#define N 10
using namespace std;
void Swap(int &a,int &b);
int RandLeftRight(int left,int right);//产生left到right的随机数
int RandPartition(int a[],int left,int right);随机选取元素进行left到right数组原址重排
int Partition(int a[],int left,int right);//对a数组分类,返回参考元素索引,左边的小于参考元素,右边的大于参考元素
int RandSelect(int a[],int left,int right,int i);//返回数组中排第i个位置的元素,(从小往大数i)
int main()
{
int a[N] = {9,5,1,4,4,2,3,6,10,7};
cout<<RandSelect(a,0,N-1,4)<<endl;
}
inline void Swap(int &a,int &b)
{
int temp;
temp = a;
a = b;
b = temp;
}
int RandLeftRight(int left,int right)//left,right是索引,所以应该产生left到right包括left,right的随机数
{
srand((unsigned)time(NULL));
return rand()%(right-left+1)+left;
}
int Partition(int a[],int left,int right)//子数组原址重排,把下面的粘贴上来的的
{
int reference = a[right];
int index_left = left,index_right = right;
while(index_left!= index_right)
{
while(index_left!=index_right)//两个索引没到一起的话
{
if(a[index_left]>reference) break;//找找到了应该往右放的数
index_left++;//没找到就继续往右搜索
}
while(index_left!=index_right)
{
if(a[index_right]<reference) break;
index_right--;
}
Swap(a[index_left],a[index_right]);
}
Swap(a[index_left],a[right]);
return index_left;//返回最后这个参考元素的索引
}
int RandPartition(int a[],int left,int right)//随机选取元素进行子数组原址重排
{
int i = RandLeftRight(left,right);
Swap(a[i],a[right]);
return Partition(a,left,right);
}
int RandSelect(int a[],int left,int right,int i)
{
if(left == right)
return a[left];
int q = RandPartition(a,left,right);
int len_left = q-left+1;
if(len_left == i) return a[q];
else if(len_left>i) return RandSelect(a,left,q-1,i);
else return RandSelect(a,q+1,right,i-len_left);
}