查找第K大数

        所谓序列的第K大数就是对于一个给定的有N个元素的序列,为了讨论方便,假设序列元素值都不相同。这个序列的第1大数就是元素值最大的那个,第N大数就是元素值最小的那个。那么第2大就是除去最大值之外剩下元素中最大的那个。以此类推,可知第3大、第4大。。。。。。从描述中可以看出,对于查找序列的第K大数的问题,最直观的方法就是每次找到最大的那个,如果不是要找的,再从剩下的元素中再找最大的,如果还不是,则继续找。如此重复K次就能找到。那么除此之外,还有其他方法吗?

        可以借鉴归并排序的思路,从要查找的序列中每次随机挑一个值出来作为参考值,把序列中比它大的值放到这个值的左边,比它小的值放到这个值的右边。然后检查一下这个值在序列中的位置,如果正好等于K,那么它就是要找的值。如果它的位置比我们要找的K要大,那么说明第K大数位于该值左边的序列中,如果它的位置比K小,说明第K大数位于该值右边的序列中。这样我们就缩小了查找范围,然后在剩下的序列中继续采用这种方法查找,直到找到为止。

       以序列{11, 21, 9, 4, 33, 2, 18, 20}为例,假设我们要查找第3大元素。每次挑选第1个元素值作为参考值,对于这个序列是11。把大于11的元素都放到左边,小于11的元素都放到右边。得到序列{21,33,18,20,11,9,4,2}。11在调整后的序列中处于第5位,表示11是第5大元素。而我们要查找的是第3大元素。说明我们要找的元素在11左边的序列中,即{21,33,18,20}序列中。且在该序列中仍查找第3大元素。同样的,我们再以21作为参考元素,运用同样的规则得到{33,21,18,20}。21在该序列中处于第2位,表示21是该序列的第2大元素。而我们要查找的是第3大元素。说明我们要找的元素在21右边的序列中,即{18,20}序列中。且是该序列的第1大元素。注意,这里是需要查找第1大元素。因为21是第2大元素,所以第3大元素就是右边序列中的第1大元素。然后在{18,20}序列中重复之前的步骤,最后可以得到第3大元素就是20。

 1 //在一个序列中查找第K大元素
 2 #include <stdio.h>
 3 int findKthNum(int* array, int size, int k);
 4 int main(void){
 5     int array[] = {11, 21, 9, 4, 33, 2, 18, 20};
 6     for(int i = 1; i <= 8; i++){
 7         printf("第%d大元素是:%d
", i, findKthNum(array, 8, i));
 8     }
 9     return 0;
10 }
11 
12 int findKthNum(int* array, int size, int k){
13     int key = array[0];         //参考元素
14     int flag = 0;               //标识每次移动元素的终点
15     int index = 0;              //标识参考元素是第几大元素
16     int tmp;
17     for(int i = 1; i < size; i++){
18         if(array[i] > key){
19             tmp = array[i];
20             for(int j = i; j > flag; j--){
21                 array[j] = array[j-1];
22             }
23             array[flag] = tmp;
24             flag = i;
25         }
26     }
27     index = flag + 1;
28     if(k == index){
29         return array[flag];
30     }else if(k > index){
31         return findKthNum(&array[flag + 1], size - index, k - index);           //继续在右边序列中查找第k-index大元素
32     }else{
33         return findKthNum(array, index - 1, k);                                 //继续在左边序列中查找第k大元素
34     }
35 }

这里使用的是移动数组元素的方法来最终确定参考元素的位置。flag是用来标识下一次移动数组元素的起点位置。

原文地址:https://www.cnblogs.com/zhang-15-506/p/13258180.html