Sorting 为什么堆排序的空间复杂度为O(1)?
我知道快速排序和合并排序都需要Sorting 为什么堆排序的空间复杂度为O(1)?,sorting,complexity-theory,time-complexity,Sorting,Complexity Theory,Time Complexity,我知道快速排序和合并排序都需要O(n)辅助空间用于构建的临时子数组,就地快速排序需要O(log n)辅助空间用于递归堆栈帧。但是对于堆排序,它似乎还有一个最坏的情况,即O(n)辅助空间来构建临时堆,即使节点只是指向实际元素的指针 我遇到了这样一个问题: 由于堆构建在要排序的数组中,因此只需要0(1)个额外的空间 但我认为这意味着原始数组必须已经实现为某种树?如果原始数组只是一个向量,那么堆的内存似乎仍然需要分配。这里的酷技巧是,因为堆是一个完整的二叉树,您可以只使用一个普通数组,对于项i,它的父
O(n)
辅助空间用于构建的临时子数组,就地快速排序需要O(log n)
辅助空间用于递归堆栈帧。但是对于堆排序,它似乎还有一个最坏的情况,即O(n)
辅助空间来构建临时堆,即使节点只是指向实际元素的指针
我遇到了这样一个问题:
由于堆构建在要排序的数组中,因此只需要0(1)个额外的空间
但我认为这意味着原始数组必须已经实现为某种树?如果原始数组只是一个向量,那么堆的内存似乎仍然需要分配。这里的酷技巧是,因为堆是一个完整的二叉树,您可以只使用一个普通数组,对于项i,它的父项是项
i/2
数组中的数据可以就地重新排列到堆中。这个算法实际上非常简单,但我在这里不赘述
对于堆排序,您可以安排数据,使其在适当的位置形成一个堆,最小的元素在后面(std::make_heap
)。然后将数组中的最后一个项(堆中最小的项)与数组中的第一个项(较大的数字)交换,然后将该大元素向下移动堆,直到它位于新的正确位置,堆再次成为新的最小堆,剩余的最小元素位于数组的最后一个元素中。(std::pop_heap
)
}
i/p存储在数组中,该数组被传递给堆排序算法-
堆排序(A)。数组A被解释为树,并在构建后从中取出MAX-HEAP和
将最后一个元素与根交换,每次将堆的大小减小一,然后对其调用MAX-HEAPIFY(A,1)
这是我们仅在该数组(A)内执行的所有操作,该数组作为i/p to算法给出。执行此操作时,我们没有使用任何额外空间。。
所以空间复杂度-O(1)。堆排序是一种就地算法;它不需要任何额外的空间。元素在每次递归期间仅在同一数组内重新排列
它提供了一种感觉,即正在形成一个二进制堆或树,但在实际场景中,没有形成任何树或堆。@MooingDuck我同意你的看法。虽然知道答案的人马上就会明白。@RikayanBandyopadhyay:“在你理解递归之前,你必须先理解递归”谢谢你,这也很有帮助。这根本没有回答问题。很好。它是一个很酷的属性,允许我们在数组内部构建一个堆来进行排序。我想补充一点,堆可以被认为是一个完整的二叉树,其中除最后一个可能之外的所有级别都被填充,节点尽可能地位于左侧。完整的二叉树表示该树在所有级别上都已完全填充。感谢您的解释和示例!出色的回答和形象化。保存的!如果它不在合适的位置,就不能快速排序。你也可以在适当的地方合并。用恒定的辅助空间进行快速排序是可能的,但是它变得很奇怪,以至于很多程序员都怀疑它是否仍然是一个快速排序。
data: 1 4 7 2 5 8 9 3 6 0
make_heap: [8 7 9 3 4 5 6 2 1 0] <- this is a min-heap, smallest on right
pop_heap(1): [0 7 9 3 4 5 6 2 1 8] <- swap first and last elements
pop_heap(2): 0 [7 9 3 4 8 6 2 5 1] <- shuffle the 8 down the heap
pop_heap(1): 0 1 [9 3 4 8 6 2 5 7] <- swap first and last elements
pop_heap(2): 0 1 [9 7 4 8 6 3 5 2] <- shuffle the 7 down the heap
etc
make_heap
0
2 1
3 4 5 6
8 7 9
pop_heap
8 1 1
2 1 2 8 2 5
3 4 5 6 -> 3 4 5 6 -> 3 4 8 6
7 9 7 9 7 9
HEAP-SORT(A)
{
BUILD-MAX-HEAP(A)
if(i= A.length down to 2)
exchange A[i] with A[1]
A.heapSize = A.heapSize-1
MAX-HEAPIFY(A,1)