第九章中位数と順序統計学の「第i小要素の最悪の状況を探す線形時間の選択最悪の運行時間はO(n)アルゴリズムである」


このアルゴリズムを用いてi番目の小要素を検索する最悪の動作時間はO(n)である.運行時間の証明はすごい!ああ、こんなにたくさんの証明を見て、私が発見したのは実は最も難しいのは数学の模型を提出して、数学の説明をして、この一歩を踏み出して、残りは集まったのです.
このアルゴリズムは9.2節の「所望運転時間こそO(n)」のRandomizedPartitionアルゴリズムよりも強く,最悪運転時間はO(n)である.なぜこんなにキックアスなのか、それは毎回区分するたびに最適な区分である「中分」を保証することができるからだ.中点を実現するには、まず中位数を見つけなければなりません.
アルゴリズムfind()プロセスは次のとおりです.
(1)まず元の配列aを5つのグループに分け,5つのグループ,,,そして各グループを挿入ソートし,各グループの中位数を得て配列bを構成する.この関数はSelect()です.
(2)b要素の個数が1でない場合、bに対してステップ1を実行し続ける.つまりSelect()再帰です.中位数xが見つかるまで.
(3)中位数xを一つのパラメータとしてPartition()関数に持ち込み,この関数はその分割関数をすばやく並べ替える変形である.分割後の中位数の下付きqを返します.
(4)qは配列aを2つの部分に分割し,i=q−p+1であればa[q]はi番目の小要素である.iコードは次のとおりです.
#include <iostream>
#include <string.h>
using namespace std;


//            
void InsertionSort(int *a,int p,int r,int &mid)
{
	int i;
	for(int j=p+1;j<=r;j++)
	{
        i=j-1;
		int key=a[j];
		while(i>=p && a[i]>key)
		{
			a[i+1]=a[i];
			i--;
		}
		a[i+1]=key;
	}
	int d=r-p+1;
	if(d%2==0)
	{
		d=d/2-1;
	}
	else
	{
		d=d/2;
	}
	//cout<<d;
	mid=a[d+p];
}

//    a    ,  x 
void Select(int *a,int p,int r,int &x)
{
	if(p==r)
	{
		x=a[p];
		return;
	}
	int n=r-p+1;
	int m=0;
	if(n%5==0)
	{
		m=n/5;
	}
	else
	{
		m=n/5+1;
	}
	
	//              ...,         ,              ,    b 
    int b[m];
	int i=p;
	for(int j=0;j<m;j++)
	{
		int mid;
		if(i+4<=r)
		{
			InsertionSort(a,i,i+4,mid);
			b[j]=mid;
			i+=5;
		}
		else
		{
			InsertionSort(a,i,r,mid);
			b[j]=mid;
		}
		//cout<<"i="<<i<<" mid="<<mid<<" j="<<j<<" m="<<m<<" r="<<r;system("pause");
	}
	
	//            b,    Select,     x
	Select(b,0,m-1,x);
}

//     x,   a     
int Partition(int *a,int p,int r,int x)
{
	int index=-1;
	for(int i=p;i<=r;i++)
	{
		if(a[i]==x)
		{
			index=i;//cout<<i;system("pause");
			break;
		}
	}
	if(index==-1)
	{
	    cout<<"error"<<endl;
		exit(1);
	}
	int temp=a[index];
	a[index]=a[r];
	a[r]=temp;
	
	int i=p-1;
	for(int j=p;j<r;j++)
	{
		if(a[j]<=x)
		{
			i++;
			int tmp=a[i];
			a[i]=a[j];
			a[j]=tmp;
		}
	}
	int pivot=a[r];
	a[r]=a[i+1];
	a[i+1]=pivot;
	
	return i+1;
}

//   i   
void find(int *a,int p,int r,int i,int &result)
{
	int x;
	Select(a,p,r,x);
	
	// x   ,   a    
	int q=Partition(a,p,r,x);
	int k=q-p+1;
	if(k==i)
	{
		result=a[q];
	}
	else if(k>i)
	{
		find(a,p,q-1,i,result);
	}
	else
	{
		find(a,q+1,r,i-k,result);
	}
}

void Output(int *a,int n)
{
     for(int i=0;i<n;i++)
     {
         printf("%d ",a[i]);
     }
     cout<<endl;
}

int main()
{
    int n=11;
    int a[n];
    srand((unsigned int)time(NULL));
    for(int i=0;i<n;i++)
    {
         a[i]=rand()%n;
    }
    Output(a,n);
	int result=-1;
	int i;
	while(1)
	{
    	cout<<"        i :i="; 
    	cin>>i;
        find(a,0,n-1,i,result);
    	cout<<"i="<<i<<" result="<<result<<endl;
     }
    //Output(a,n);
    system("pause");
    return 0;
}