查找第k大的数

来源:互联网 发布:淘宝男装外贸原单店铺 编辑:程序博客网 时间:2024/04/30 09:24

查找第K个大数存在着很多方法,有些类似于查找前K个大的数。下面给出一些代码实现,可以完成这个功能。

1. 排序后查找

/*******************************************  第一种方法当然是排序,对整个数组进行排序,需要O(nlgn)的时间复杂度,在定位到第K个元素复杂度为O(1),故整体复杂度为O(nlgn).  为简单起见,整个数组的元素无重复,且假定为整数。*******************************************/#ifndef Method1_H#define Method1_H#include <algorithm>int SearchKthNumber(int array[],int length,int K){if(length<K)return array[length-1];std::sort(array,array+length);//注意这里第K大的数是length-K,而不是K-1return array[length-K];}#endif


2. 利用堆的性质

/*******************************************    方法1对所有的元素进行排序存在着较大的浪费,另一种方法是建立一个为K个元素的最小堆结构,然后依次遍历剩下的元素来替换堆顶元素,这样每次调整复杂度为O(lgK),总共需要调整n-K次,因此时间复杂度为O(nlgK).比较方法1,可以得到一定的性能提升。而且这种方法在数据量较大时仍然可用。*******************************************/#ifndef Method2_H#define Method2_H#include <iostream>//辅助函数,用于建堆和调整堆结构void AdjustHeap(int array[],int i,int length){int left=2*i+1;int right=left+1;while(right<length){if(array[left]<array[i]&&array[right]<array[i]){if(array[left]<array[right]){std::swap(array[left],array[i]);i=left;}else{std::swap(array[right],array[i]);i=right;}}else if(array[left]<array[i]&&array[right]>array[i]){std::swap(array[left],array[i]);i=left;}else{std::swap(array[right],array[i]);i=right;}left=2*i+1;right=left+1;}if(left<length){if(array[left]<array[i])std::swap(array[left],array[i]);}}int SearchKthNumber(int array[],int length,int K){//建堆for(int i=K/2-1;i>=0;--i)AdjustHeap(array,i,K);for(int i=K;i<length;++i){if(array[i]>array[0]){   std::swap(array[0],array[i]);   AdjustHeap(array,0,K);}}return array[0];}#endif


3.类似快速排序方法

 
/******************************************   第三种可以采用跟踪的方式,因为我们知道第K大的元素(如果采用降序排列的话)必然位于数组中K-1的位置。采用类似快速排序的方法,每一次对包含这个位置的数组进行分类,这样可以递减需要进行分类的数组个数,直至分类到第K-1个位置,此时这个位置上的数即为我们想要的结果。时间复杂度为T(n)=T(n/2)+T(n/4)+...+1,结果近似为O(n)。*******************************************/#ifndef Method3_H#define Method3_H#include <iostream>int Partition(int array[],int begin,int end)  {      //键值确定       int key=array[begin];      while(begin<end)      {          while(array[begin]>key)              ++begin;          while(array[end]<key)              --end;          //交换过程          if(begin<end)   std::swap(array[begin],array[end]);    }      //返回的是键值所在元素位置,以此元素位置将数组划分为两部分       return begin;  }  /****************************************************/  /****************************************************/  //定位部分  void Quick_Location(int array[],int begin,int end,int K)  {      if(begin<end)      {         int middle=Partition(array,begin,end);   if(K-1<middle)  Quick_Location(array,begin,middle-1,K);   else if(K-1>middle)   Quick_Location(array,middle+1,end,K);    }  }  int SearchKthNumber(int array[],int length,int K){Quick_Location(array,0,length-1,K);return array[K-1];}/****************************************************/  #endif  
修改部分:上述代码写的略显潦草,下面给出递归方法,原理同上,但代码更为简洁。
<pre name="code" class="cpp">////  KthNumber.h//  The_Kth_Number////  Created by CHM on 14-6-25.//  Copyright (c) 2014年 CHM. All rights reserved.//  select the kth begger number#ifndef The_Kth_Number_KthNumber_h#define The_Kth_Number_KthNumber_h#include <iostream>using namespace std;template <typename Type>Type Random_Select(Type array[],int begin,int end,int k){    int size=end-begin+1;    if(size<k)        cerr<<"There will not be correct result!"<<endl;    int i=begin;    int j=end;    //随机选择一个键值分割,避免输入数据顺序影响    int rand_number=rand()%size;    Type key=array[begin+rand_number];    //等同于快速排序中等分割,这里采用双端法    while(i<j)    {        while(array[i]<key)            ++i;        while(array[j]>key)            --j;        if(i<j)            swap(array[i],array[j]);    }    int pre_number=i-begin;    //位置i前面刚好有k-1个元素,则位置i处的元素就是第i个元素    if(pre_number==k-1)        return array[i];    //前面第元素个数大于或者等于k,第k个元素位于前半部分    else if(pre_number>k-1)        return Random_Select(array,begin,i-1,k);    //否则,第k个元素位于后半部分    else        return Random_Select(array,i+1,end,k-(pre_number+1));   }#endif

4. 测试用代码

#include <iostream>//#include "Method1.h"//#include "Method2.h"#include "Method3.h"using namespace std;int main(){int a[]={6,5,4,15,14,13,3,2,1,12,11,10,9,8,7};int result=SearchKthNumber(a,15,10);cout<<result<<endl;system("pause");return 0;}


当然还存在着许多其他种方法,这里只是给出一部分。
 

0 0
原创粉丝点击