查找第K大的数据

来源:互联网 发布:软件企业质量体系认证 编辑:程序博客网 时间:2024/05/01 07:18

// 查找第K大的数据
//   平均复杂度 O(N)
//   最坏复杂度 O(N*N)
// 参考:
// BFPRT(median-of-medians algorithm)
// http://en.wikipedia.org/wiki/Selection_algorithm
// VC2008

#include "stdafx.h"
#include <algorithm>
#include <iostream>

// 查找参考值在数据中的位置
// iLeft: 数组的起始偏移量
// iRight: 数组的结束偏移量, 总数据量是 (iRight-iLeft+1)
// pivotIndex: 参考值位置
// 返回值:
//   参考值在数组总的位置
//   该位置之前的值都小于参考值, 该位置之后都大于等参考值
template<typename T>
int partition(T iData[], int iLeft, int iRight, int pivotIndex)
{
 // 取出参考数据,并将这个数据保存在最后
 T pivotValue = iData[pivotIndex];
 std::swap(iData[pivotIndex], iData[iRight]);
 
 // 准备存放小于参考值的位置
 int storeIndex = iLeft;

 // 遍历所有数据(除了保存于最后的参考数据)
 for(int i=iLeft; i<iRight; ++i)
 {
  // 将小于参考值的数据挪到前面
  if(iData[i]<pivotValue)
  {
   // 注意如果i等于storeIndex, 可以考虑优化掉swap
   std::swap(iData[storeIndex], iData[i]);
   ++storeIndex;
  }
 }

 // 将参考值存放在分割位置
 std::swap(iData[iRight], iData[storeIndex]);

 // 至此, 分割位置为参考值, 位置之前全部都是小于参考值的, 此后都是大于(等于)参考值的

 // 返回分割位置
 return storeIndex;
}

//
template<typename T>
void quickfindFirstK(T iData[], int iLeft, int iRight, int k)
{
 if(iLeft < iRight)
 {
  // 任意取一个作为参考值
  // 这里取位置k的数据
  int pivotIndex = k;

  // 查找参考数据在数组中的位置
  int pivotNewIndex = partition(iData, iLeft, iRight, pivotIndex);

  if(pivotNewIndex > k)
  {
   // 如果选中的参考数据在要确定的位置之后
   // 则在后面数据中查找
   quickfindFirstK(iData, iLeft, pivotNewIndex-1, k);
  }
  if(pivotNewIndex < k)
  {
   // 如果选中的参考数据在要确定的位置之前
   // 则在前面数据中查找
   quickfindFirstK(iData, pivotNewIndex+1, iRight, k);
  }

  // 如果参考数据正好在要确定的位置
  // 则该数据已经放到位置k, 且之前的数据都不大于这个值, 之后的数据都不小于这个值
 }
}

 

int _tmain(int argc, _TCHAR* argv[])
{

 int iData[] = {20,1,19,2,18,3,17,4,16,5,15,6,14,7,13,8,12,9,11,10};

 int nCount= sizeof(iData)/sizeof(iData[0]);
 quickfindFirstK(iData, 0, nCount-1, nCount/2);

 std::cout << "iData[" << nCount/2 << "] = " << iData[nCount/2] << std::endl;
 for(int i=0; i<nCount; ++i)
 {
  std::cout << iData[i] << "  ";
 }
 std::cout << std::endl;

 return 0;
}


// 运行结果:
// iData[10] = 11
// 1  2  3  4  5  6  7  8  10  9  11  12  13  14  15  19  17  20  16  18

原创粉丝点击