我不明白堆排序的空间复杂度是怎样的O(1)?虽然快速排序不使用任何额外的数组(即就地),但在最坏情况下其空间复杂度为O(n),在最佳情况下为O(lg n),因为在递归调用的后端使用堆栈。我说得对吗?
堆排序也是如此。虽然,它是就地的,但是由于Build-Heap函数调用Max-Heapify函数,所以它的空间复杂度应该等于Max-Heapify,即O(lg n)。不是吗?此外,稍后在根节点调用Max-Heapify函数n次,正如我所说的Max-Heapify()空间复杂度为O(lg n)。
所以,堆排序的整体空间复杂度应该是O(lg n)。但是我在维基百科上找到了它O(1)。帮助我理解它。
heapify有非递归版本(参见下面的示例)。对于快速排序,如果递归仅用于较小的分区,则循环返回以将较大的分区拆分为2(再次在这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]);
}
空间复杂性是指算法使用的额外空间。堆排序不使用任何额外空间(在O(n)中),除了数组进行排序。因此它是O(1)
堆排序不占用任何取决于正在排序的数组大小的空间,只占用数组本身的空间和少数变量。显然是O(1)。
快速排序跟踪需要排序的子数组堆栈。如果您很聪明,并且在任何两个子数组中,将较大的一个子数组放在堆栈上,并立即对较小的一个子数组进行排序,则需要O(log n)。
实际上,这没有任何区别。
问题内容: 从TimeComplexity文档中可以看出,Python的类型是使用数组实现的。 因此,如果正在使用数组并且进行了一些附加操作,最终您将不得不重新分配空间并将所有信息复制到新空间。 毕竟,这是O(1)最坏的情况吗? 问题答案: 如果查看链接文档中的脚注,您会发现它们包含一个警告: 这些操作依赖于“最坏情况摊销”的“摊销”部分。根据容器的历史记录,各个动作可能会花费惊人的时间。 使用摊
算法相对较新,所以如果我遗漏了一些显而易见的东西,请原谅! 我知道深度优先搜索的空间复杂度通常表示为O(h),其中h是树的高度,而广度优先搜索的复杂度是O(n),其中n是树中节点的数量。 我理解解释(例如在这个答案中https://stackoverflow.com/a/9844323/10083571)也就是说,在BFS中最坏的情况下,所有节点都在一个级别上,这意味着我们必须在遍历它们之前将所有
问题内容: 我打算对StringBuilders中的最后一个字符进行很多删除。使用的解决方案对我来说很好。但是,由于这些删除将处于循环中,因此我需要知道其复杂性。 据我了解,该操作只是减少了StringBuilder对象的一些私有属性,并且不对字符本身执行任何复制/克隆/复制操作,因此它的时间为O(1),应该可以快速运行。 我对吗? 问题答案: 从文档中: 设置字符序列的长度。序列更改为新的字符序
让我们以合并排序的实现为例 a) 这种合并排序的时间复杂度是。并行化(1)和(2)会带来实际收益吗?从理论上讲,在对它们进行并行化之后,似乎最终也会出现。但实际上我们能得到什么好处吗? b) 这种合并排序的空间复杂度是。但是,如果我选择使用链表执行就地合并排序(不确定是否可以合理地使用数组),空间复杂性是否会变得,因为您必须考虑递归堆栈帧大小?既然它不能超过64,我们能把当作常数吗?我可能在几个地
问题内容: 我刚刚开始学习数据结构,并且在进行数组插入时想知道为什么数组插入的时间复杂度为O(n)而不是O(n + 1)? 在最佳情况下,当插入在最后时,时间复杂度为O(1)。我想我们正在考虑1插入元素,因为这里没有元素被移动。在最坏的情况下,假设我们必须移动n个元素然后插入新元素,那么时间时间复杂度是否应该为O(n + 1)?n用于移动元素,1用于插入。 非常感谢您的帮助。 问题答案: O(n)