为什么堆排序的空间复杂度为O(1)?

时间:2016-09-02 19:00:44

标签: algorithm sorting time-complexity heapsort

我不明白堆排序的空间复杂性是如何O(1)?虽然快速排序不使用任何额外的数组(即就地),但在最坏的情况下它的空间复杂度是O(n),在最好的情况下是O(lg n),因为在后端使用堆栈进行递归调用。我是对的吗?

堆排序也是如此。虽然它是就地的,但由于Build-Heap函数调用Max-Heapify函数,因此它的空间复杂度应该等于Max-Heapify,即O(lg n)。不是吗?此外,稍后在根节点上调用Max-Heapify函数n次,正如我所说的Max-Heapify()空间复杂度为O(lg n)。

因此,Heap排序的整体空间复杂度应为O(lg n)。但我在维基百科上发现它是O(1)。帮助我理解它。

3 个答案:

答案 0 :(得分:0)

Heapsort不占用任何空间,这取决于正在排序的数组的大小,只是数组本身的空间,以及一些变量。显然是O(1)。

Quicksort跟踪需要排序的一堆子数组。如果你聪明且任何两个子阵列将较大的子阵列放在堆栈上并立即对较小的子阵列进行排序,则需要O(log n)。

在实践中,它没有任何区别。

答案 1 :(得分:0)

空间复杂度是指算法使用的额外空间。 Heap Sort不使用任何额外的空间(在O(n)中),除了要排序的数组。因此它是O(1)

答案 2 :(得分:0)

有一些非递归版本的heapify(参见下面的示例)。对于快速排序,如果递归仅用于较小的分区,则循环返回以将较大的分区拆分为2(再次使用这两个分区中较小的分区上的递归,依此类推),则最大堆栈空间为O(log( n)),但最坏的情况时间仍为O(n ^ 2)。

使用非递归堆化的非递归堆排序的C ++示例:

typedef unsigned int uint32_t;

void HeapSort(uint32_t *, size_t);
void Heapify(uint32_t *, size_t);
void SiftDown(uint32_t *, size_t, size_t);

void HeapSort(uint32_t * a, size_t count)
{
size_t end;
    Heapify(a, count);      // create initial heap
    end = count-1;
    while(end > 0){
        // swap root (largest value) with end
        std::swap(a[0], a[end]);
        // reduce size of heap and
        // increase size of sorted array
        end--;
        // repair the reduced heap
        SiftDown(a, 0, end);
    }
}

// create initial heap: for root = (count-2)/2 -> 0
// parent = root, children = root*2+1, root*2+2
// swap so that all a[parent] > a[child]
void Heapify(uint32_t * a, size_t count)
{
size_t root;
    if(count < 2)
        return;
    // create sub-heaps of increasing size,
    // with root going from (count-2)/2 to 0
    root = (count - 2) / 2;
    while(1){
        SiftDown(a, root, count-1);
        if(root == 0)
            break;
        root--;
    }
}

// scan from root to end, swapping as needed to repair or create heap
void SiftDown(uint32_t * a, size_t root, size_t end){
size_t parent;
size_t child;
    // while at least two children
    for(parent = root; (child = parent * 2 + 2) <= end; ){
        // choose the larger child
        if(a[child-1] > a[child])
            child = child-1;
        // if child > parent then swap, parent = child
        if(a[child] > a[parent]){
            std::swap(a[child], a[parent]);
            parent = child;
        // else done with search for swaps
        } else {
            break;
        }
    }
    // check for final only child
    if((child = parent * 2 + 1) <= end)
        if(a[child] > a[parent])
            std::swap(a[child], a[parent]);
}