Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 以O(K*log(K))打印给定堆中最大的K个元素?_Algorithm_Search_Tree_Heap_Big O - Fatal编程技术网

Algorithm 以O(K*log(K))打印给定堆中最大的K个元素?

Algorithm 以O(K*log(K))打印给定堆中最大的K个元素?,algorithm,search,tree,heap,big-o,Algorithm,Search,Tree,Heap,Big O,鉴于以下问题,我不能完全确定我当前的解决方案: 问题: 给定存储在数组a中的n元素的最大堆,是否可以在O(K*log(K))中打印所有最大的K元素 我的回答: 是的,这是因为搜索元素需要O(log(K)),因此需要这样做 对于K元素需要O(K*log(K))运行时间。事实上,提取max元素太容易了,提取max元素是O(log(N))其中N是堆的大小。和N≠K 我要补充的是,搜索随机元素是O(N),而不是O(Log(N)),但在这种情况下,我们要提取最大值。在大小为N的堆中搜索元素不是O(K)。首

鉴于以下问题,我不能完全确定我当前的解决方案:

问题:

给定存储在数组
a
中的
n
元素的最大堆,是否可以在
O(K*log(K))
中打印所有最大的
K
元素

我的回答

是的,这是因为搜索元素需要
O(log(K))
,因此需要这样做


对于
K
元素需要
O(K*log(K))
运行时间。

事实上,提取max元素太容易了,提取max元素是
O(log(N))
其中
N
是堆的大小。和
N≠K


我要补充的是,搜索随机元素是
O(N)
,而不是
O(Log(N))
,但在这种情况下,我们要提取最大值。

在大小为N的堆中搜索元素不是O(K)。首先,查找一个元素的时间复杂度取决于您试图提取的元素数(即K所代表的元素数)是没有意义的。此外,没有在堆中搜索这样的事情——除非您在O(N)中计算每个元素搜索的标准外观

然而,根据设计,在堆中查找最大的元素是O(1)(我显然假设它是一个最大的堆,因此最大的元素位于堆的顶部),从大小为N的堆中删除最大的元素是O(log(N))(用一个叶元素替换它,并使该叶渗透回堆中)

因此,从堆中提取K个元素并返回未提取元素的堆需要O(K·log(N))时间

如果以非破坏性方式从堆中提取K个元素,会发生什么?您可以通过保持一堆堆来实现这一点(其中堆的值是其最大元素的值)。最初,这个堆只包含一个元素(原始堆)。要提取下一个最大元素,请提取顶部堆,提取其顶部元素(即最大值),然后将两个子堆重新插入到堆中


这会在每次移除时(移除一个,添加两个)将堆的堆增加一个,这意味着它永远不会容纳超过K个元素,因此移除一个,添加两个将需要O(log(K))。重复此操作,您将得到一个实际的O(K·log(K))算法,该算法返回前K个元素,但无法返回未提取元素的堆。

这在最大堆中是可能的,因为您只打印树中的元素,而不提取它们

首先确定位于根节点的最大元素。形成一个指向节点的指针,并将其添加到一个空的“最大值”列表中。然后,对于每个
k
值,在循环中执行以下步骤

  • 从列表中弹出最大元素,取O(1)
  • 打印其值,取O(1)
  • 将此最大元素的每个子元素插入列表。插入时保持排序,需要O(日志(列表大小))时间。这个列表的最大大小是分支大小*k,因为我们执行了k次循环。因此,该步骤需要O(log(k))时间

总的来说,运行时间是O(klog(k)),正如所希望的那样。

我发现其他答案令人困惑,所以我决定用一个实际的堆示例来解释它。
It is a simple and elegant algorithm to get first k elements of a max heap in k log(k) time.

steps:-

1.construct another max heap name it auxiliary heap
2.add root element of main heap to auxiliary heap
3.pop out the element from auxiliary heap and add it's 2 children to the heap
4.do step 2 and 3 till k elements have been popped out from auxiliary heap. Add the popped element's children to the auxiliary heap.
假设原始堆的大小为N,并且您希望找到第k个最大的元素, 此解决方案需要O(klogk)时间和O(k)空间

想要找到第五大元素。k=5 注意:在新堆中,需要存储指向原始堆的指针。 这意味着,您不会移除或更改原始堆。原始堆是只读的。因此,您永远不必执行任何需要O(logN)时间的操作

设x'为原始堆中值x的指针

第一次迭代:将根节点的指针放入新堆

步骤1:将指针添加到节点10

 10'
 New Heap, size = 1, root = 10', root->left = 5, root right->3
打印第一大元素=10

第二次迭代:引用原始堆并将其两个子堆插入新堆。(存储指向它们的指针,而不是值本身)。您希望存储指针的原因是,您可以稍后从原始堆以O(1)形式访问它们以搜索其子对象,而不是以O(N)形式搜索该值在原始堆中的位置

步骤2a:从原始堆中查找新堆根节点的左子级。 将左子级(在本例中为5')的指针添加到新堆中

  10' 
 /
5'
New Heap, size = 2, root = 10', root->left = 5, root right->3
  5'
 / \
3'  4'
New Heap, size = 3, root = 5', root->left = 4, root right->1
     3'
    / \
   1'  2'
New Heap, size = 3, root = 3', root->left = 2, root right->0
步骤2b:从原始堆中查找新堆根节点的正确子级。 将左子级(在本例中为3')的指针添加到新堆

  10' 
 / \
5'  3'
New Heap, size = 3, root = 10', root->left = 5, root right->3
    5'
   / \
  3'  4'
 /
1'
New Heap, size = 4, root = 5', root->left = 4, root right->1
步骤2c:从新堆中删除根节点。 (将最大节点与最右边的左节点交换,删除根节点并向下冒泡当前根节点以维护堆属性)

打印第二大元素=5

步骤3a:从原始堆中查找新堆根节点的左子级。 将左子级(在本例中为4')的指针添加到新堆

  10' 
 /
5'
New Heap, size = 2, root = 10', root->left = 5, root right->3
  5'
 / \
3'  4'
New Heap, size = 3, root = 5', root->left = 4, root right->1
     3'
    / \
   1'  2'
New Heap, size = 3, root = 3', root->left = 2, root right->0
步骤3b:从原始堆中查找新堆根节点的正确子级。 将左子级(在本例中为1')的指针添加到新堆

  10' 
 / \
5'  3'
New Heap, size = 3, root = 10', root->left = 5, root right->3
    5'
   / \
  3'  4'
 /
1'
New Heap, size = 4, root = 5', root->left = 4, root right->1
步骤3c:从新堆中删除根节点。 (将新堆的最大节点(5')与其原始堆(1')的最右边的剩余节点从新堆交换,移除根节点并向下冒泡当前根以维护堆属性)

打印第三大元素=4

步骤4a和步骤4b不执行任何操作,因为在本例中,根节点没有来自原始堆的任何子节点

步骤4c:从新堆中删除根节点。 (将最大节点与最右边的左节点交换,移除根节点并向下冒泡当前根节点,以在新堆中维护堆属性)

打印第四大元素=3

步骤5a:从原始堆中查找新堆根节点的左子级。 将左子级(在本例中为2')的指针添加到新的he
     3'    Swap        0'  Remove & Bubble      2'
    / \     =>        / \         =>           / \
   1'  2'            1'  2'                   1'  0'
  /                 /
 0'                3'
New Heap, size = 3, root = 2', root->left = NULL, root->right = NULL