如何实现最小堆排序以找到第k个最小元素?

时间:2011-04-10 01:28:48

标签: c++ sorting selection heapsort

我一直在为类实现选择排序问题,其中一个分配是使用最小堆找到数组中的第k个最小元素。我知道程序是:

  • 堆化数组
  • 删除最短(root)k次
  • 返回组中的第k个最小元素

创建最小堆时没有任何问题。我只是不确定如何正确删除最小k次并成功返回组中的第k个最小元素。这是我到目前为止所做的:

 bool Example::min_heap_select(long k, long & kth_smallest) const {
//duplicate test group (thanks, const!)
Example test = Example(*this);

//variable delcaration and initlization
int n = test._total ;
int i;

//Heapifying stage (THIS WORKS CORRECTLY)
for (i = n/2; i >= 0; i--) {
    //allows for heap construction
    test.percolate_down_protected(i, n);
}//for  


//Delete min phase (THIS DOESN'T WORK)  
for(i = n-1; i >= (n-k+1); i--) {


    //deletes the min by swapping elements
    int tmp = test._group[0];
    test._group[0] = test._group[i];
    test._group[i] = tmp;       

    //resumes perc down
    test.percolate_down_protected(0, i);        


}//for

    //IDK WHAT TO RETURN 
    kth_smallest = test._group[0];



void Example::percolate_down_protected(long i, long n) {

//variable declaration and initlization:    
int currPos, child, r_child, tmp;
currPos = i;
tmp = _group[i];
child = left_child(i);  

//set a sentinel and begin loop (no recursion allowed)
while (child < n) {

    //calculates the right child's position
    r_child = child + 1;

    //we'll set the child to index of greater than right and left children
    if ((r_child > n ) && (_group[r_child] >= _group[child])) {
        child = r_child;
    }
    //find the correct spot
    if (tmp <= _group [child]) {
        break;
    }

    //make sure the smaller child is beneath the parent
    _group[currPos] = _group[child];

    //shift the tree down
    currPos = child;
    child = left_child(currPos);
}

//put tmp where it belongs
_group[currPos] = tmp;
 }

正如我之前所说,最小堆部分正常工作。我理解我该怎么做 - 删除根k次似乎很容易,但之后我会返回数组中的索引... 0?这几乎是有效的 - 它不值得用k = n或k = 1.如果第k个最小的元素在任何帮助中将非常感激!

2 个答案:

答案 0 :(得分:7)

对用户有意义的唯一数组索引是零,这是最小元素。因此,在删除k元素后,k'最小元素将为零。

可能你应该销毁堆并返回值,而不是要求用户关心堆本身......但我不知道赋值的细节。

请注意,C ++标准库具有以下算法:make_heappop_heapnth_element

答案 1 :(得分:-2)

我没有提供详细的答案,只是说明了在最小堆有序树中获取k个最小元素的关键点。该方法使用跳过列表。

  • 首先形成树节点的跳过列表,其中只有一个元素对应于堆根节点。第一个最小元素就是该节点上存储的值。
  • 现在删除该节点,并将其子节点插入正确的位置,以保持值的顺序。此步骤需要O(logk)时间。 第二个最小值就是该跳过列表中第一个节点的值。

重复上述步骤,直到获得所有k个最小元素。总时间复杂度为log(2)+log(3)+log(4)+... log(k) = O(k.logk)。形成堆需要时间n,因此总体时间复杂度为O(n+klogk)

还有另一种方法不生成堆Quickselect,该堆的平均时间复杂度为O(n),但最差的情况是O(n^2)

两种方法之间的显着区别是,第一种方法使所有k个元素的最小值达到第k个最小值,而quickSelect仅给出第k个最小值的元素。 在内存方面,前一种方法使用了O(n)的额外空间,而quickSelect使用了O(1)