线性时间选择 5元组选中位数法

来源:互联网 发布:hexo 阿里云 编辑:程序博客网 时间:2024/06/06 05:32

///////////////////////////////////////////////////////////////////////////*//  [8/7/2011] By Whisper对那些证明,O(X)我真的不太懂怎么证,数学学的不是太好。希望读到这篇代码的,懂的朋友可以留言帮助我理解一下,我只是简单的将代码实现了,需要的就来拿吧。在看这个选择算法的时候,应该对前面那个三位取中划分有些了解。其中有好多细节,我就不写了,代码能表述一切。http://blog.csdn.net/v_july_v/article/details/6431001 这里有一篇很不错的讲解。算法导论9.3节代码实现主要思想:1. 对输入的数组分成 N/5个5元组,最后一个元组个数为 n % 52. 对 N/5 个5元组,进行排序,找出其中的中位数(就是第3个数),再存成一个有N/5个数的中位数数组3. 再对这N/5个中位数, 递归查找中位数。4. 按找到的这个数,进行左右划分5. 如果要查找的第K大个数与这个划分点位置相等,则返回,如果小于,则在左边,否则在右边。*/////////////////////////////////////////////////////////////////////////////test.cpp VC6 编译通过//////////////////////////////////////////////////////////////////////////#include <iostream>#include <time.h>#include "initFuncs.h"       //此文件包含了随机初始化函数 RndInitArray() 和 输出函数 Outprint()//下面是initFuncs.h的辅助函数代码,可以自己组织一下。 /*#ifndef _FUNC_INIT_#define _FUNC_INIT_  #include <STDLIB.H>#include <time.h>#include <stdio.h>#endif  void RndINitArray(int nArray[], int nArraySize);void OutPrint(int nArrany[], int nArraySize);  void RndINitArray(int nArray[], int nArraySize){srand(time(NULL));for (int i = 0; i < nArraySize; i++){nArray[i] = rand() % 90 + 10;}}void OutPrint(int nArray[], int nArraySize){  for (int i = 0; i < nArraySize; i++)  {  printf("%3d", nArray[i]);  }  printf("\n\n");}*/#define  ARRAY_SIZE 12void Swap(int *x, int *y);   //交换函数void InsertSort(int nArray[], int left, int right);        //插入排序int RandomizedPartition(int a[], int left, int right);     //分隔函数int RandomizedSelect(int a[], int left, int right, int k); //线性选择主函数int MidNum(int nArray[], int left, int right);             //选取5元组的中位数的中位数const int nMidArraySize = ARRAY_SIZE / 5 + 1;int nMidArray[nMidArraySize];//------------------------测试-------------------------int main(void){int nArray[ARRAY_SIZE];RndINitArray(nArray, ARRAY_SIZE);printf("\n\tArray Size is %d\n\n", ARRAY_SIZE);printf("original Array:\n");OutPrint(nArray, ARRAY_SIZE);printf("RandomizedSelected from 1 to %d\n", ARRAY_SIZE); for (int i = 1; i <= ARRAY_SIZE; i++) { printf("%3d", RandomizedSelect(nArray, 0, ARRAY_SIZE, i));   }//printf("%d\n", RandomizedSelect(nArray, 0, ARRAY_SIZE, 5));printf("\n\n");printf("Compare with InsertSort:\n");InsertSort(nArray, 0, ARRAY_SIZE);OutPrint(nArray, ARRAY_SIZE);return 1;}//----------------------------插入---------------------------void InsertSort(int nArray[], int left, int right){for (int i = left + 1; right > 1; right--){int nTmpKey = nArray[i];int j = i++ - 1;while (j >= left && nArray[j] > nTmpKey){nArray[j + 1] = nArray[j];j--;}nArray[j + 1] = nTmpKey;}}void Swap(int *x, int *y)  {    int t = *x;*x =  *y;*y = t;}int RandomizedPartition(int a[], int left, int right)  {//寻找中位数    int x =  MidNum(a, left, right);int index = left;while(x != a[index++]);       //寻找中位数在数组中的位置index--;  //也可以从新设计存储结构Swap(&a[index], &a[left]);    int i = left,         j = right;    while (true)    {while (a[++i] < x);while (a[--j] > x);if (i >= j){break;}Swap(&a[i], &a[j]);    }Swap(&a[j], &a[left]);    return j;        //返回Select位置}//--------------------------利用快排思想,一半一半的找--------------int RandomizedSelect(int a[], int left, int right, int k){    int i = RandomizedPartition(a, left, right),        j = i - left+1;if (j == k)       //终结状态    {        return a[i];    }    else if (k < j)    {        return RandomizedSelect(a, left, i, k);        //在左边    }    else    {        return RandomizedSelect(a, i+1, right, k-j);    //在右边    }}//-------------------------选取5元组的中位数----------------------------int MidNum(int nArray[], int left, int right){if (1 == right)   //直到最后只剩一个元素,即是中位数的中位数{return nArray[left];}int remainder = (right - left) % 5;int i = left, j = 0;for (; i < right - remainder; i += 5){InsertSort(nArray, i, 5);          //对每个5元组进行插入排序nMidArray[j++] = nArray[i + 2];    //存放中位数}//如果存在剩余元素则处理剩余元素if (remainder > 0){InsertSort(nArray, i, remainder);nMidArray[j++] = nArray[i + remainder / 2]; }//从中位数组中寻找中位数int nMidElem = (right - left) / 5 + (0 != remainder); return MidNum(nMidArray, 0, nMidElem);}

下面是测试结果:


原创粉丝点击