最近在读《数据结构与算法分析(C语言描述)》,在优先队列(堆)一节中,作者总结了关于“选择问题——求第k个最大的元素”的几种思路,在此简单总结一下:
第一种
将这N个数读进一个数组中,再通过某种简单的算法,比如冒泡排序、选择排序等,以递减顺序将数组进行排序,然后返回位置k上的元素。假设使用最简单的排序算法,则运行时间为O(N2)
第二种
这是对第一种算法的简单优化。申请一个大小为k的数组,然后先把前k个元素读入数组并以递减顺序进行排序。接着,将剩下的元素再逐个读入。当新元素被读到时,如果它小于数组中的第k个元素则忽略,否则将其放到数组中正确的位置上(就是插入排序啊!),同时将数组中最后一个元素挤出数组。当算法终止时,位于第k个位置上的元素就是最终结果,即第k个最大的元素。
该算法的平均运行时间为O(N?k),但是最差时间为O(N2)
第三种
简单来说:建最大堆!
将N个元素读入数组,然后对该数组执行BuildHeap算法(就是将这N个元素进行建堆,当然也可以边读数边建堆),最后,执行k次DeleteMin操作(就是删除根结点,也就是删除当前堆中最大的那个数)。从该堆中最后提取的那个元素就是我们的答案。
时间复杂度分析:
- 如果使用BuildHeap,构造堆的最坏情形用时是O(N),而每次DeleteMin用时O(logN)(要随时调整堆),由于有k次DeleteMin,因此总运行时间为O(N+klogN)。
- 如果k=O(N/logN),那么运行时间取决于BuildHeap操作,即O(N)
- 对于大的k的值,运行时间为O(klongN)
第四种
算是第二种和第三种思路的结合。
也就是用堆来实现大小为k的数组S,前k个元素通过调用一次BuildHeap,以总时间O(k)被置入堆中,处理其余每个元素的时间为O(1)(检测元素是否进入数组)再加上时间O(longk)(在必要时删除根结点并插入新元素)。因此总的时间为O(k+(N?k)longk)=O(Nlongk)。
时间: 2024-10-03 04:09:10