《编程之美》 : 寻找最大的K个数

用于解决类似:10亿个浮点数,找出当中最大的10000个之类的问题。《编程之美》上一共五种解法:
解法一:利用选择排序和冒泡排序,这两者的复杂度都属O(N*K)
解法二:和STL<algorithm>中的nth_element(first, nth, last)思路一样。首先在[first, last)上寻找一个阈值(可采用三点中值法),根据这个阈值将[first, last)分成两段,前一段所有值都小于等于(或大于等于)阈值,后一段所有数都大于等于(或小于等于)阈值。如果阈值所在的位置>nth,则说明第nth个数在前半段,否则nth个数的位置处于后半段。然后对子序列进行分割。直到子序列的长度小于等于3,然后对子序列进行插入排序。最后的结果是第nth个数一定是排好序的第nth个数,而且前段的数都比nth小(或大),后端的都比nth大(或小)。复杂度为O(N*logK)void nth_element( RandomAccessIterator first, RandomAccessIterator nth, RandomAccessIterator last) { while (last – first > 3) { valueType value = __median(*first, *(first + (last – first) / 2), *(last – 1)); RandomAccessIterator cut = __unguarded_partition(first, last, value); if (nth >= cut) // 如果cut == nth, 不能break { first = cut; } else { last = cut; } } __insertion_sort(first, last); //最后进行插入排序 } /* 该方法使得[first, 返回值)内的元素全都小于等于value, [返回值, last)内的元素全都大于等于value */ RandomAccessIterator __unguarded_partition(RandomAccessIterator first, RandomAccessIterator last, valueType v) { while (*first < value) { first++; } last–; while (*last > value) { last–; } if (first > last) { return first; } swap(first, last); first++; }解法三:
解法四:和STL<algorithm>中的partial_sort(first, middle, last)思路一样。对[first, middle)部分进行排序。在[first, middle)构造一个min_heap,然后遍历[middle, last)。如果有比堆顶大的数,就和堆顶元素交换,然后调整堆。这样,当遍历完之后,[first, middle)就存放着前middle-first个大数。而且第一个元素(堆顶)是第middle-first个数(从1开始算),如果从0开始算就是第middle-first个数。这种方法的复杂度为O(N*logK)void partial_sort ( RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last ) { make_heap(first, middle); for (RandomAccessIterator it = middle; it < last; it++) { if (*it > *first) { swap(first, it); } // 调整heap } }解法五:需要知道最大数MAX,然后分配一个MAX大小的空间count[MAX],用来记录每一个数出现的次数。然后从大到小的遍历数组,知道出现的次数总和加起来大于等于K的时候,那么此时的数就是第K大的数。这种方法的复杂度是线性的。int i, sum = 0; for (i = MAX – 1; i > = 0; i–) { sum += count[i]; if (sum >= K) { break; } } return i;

    原文作者:jiangyi711
    原文地址: https://blog.csdn.net/jiangyi711/article/details/5814656
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞