Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/37.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 是否有一个堆或类似堆的结构可以与指针一起工作,换句话说,节点不在数组中?_Algorithm_Heap_Doubly Linked List - Fatal编程技术网

Algorithm 是否有一个堆或类似堆的结构可以与指针一起工作,换句话说,节点不在数组中?

Algorithm 是否有一个堆或类似堆的结构可以与指针一起工作,换句话说,节点不在数组中?,algorithm,heap,doubly-linked-list,Algorithm,Heap,Doubly Linked List,我现在有一个按降序排列的对象的双链接列表。(列表是侵入性的——对象中的指针。)我有一组非常有限的操作: 添加具有最高可能密钥的节点 删除具有最高可能密钥的节点(不管是哪一个) 删除键为0的节点(无论是哪一个) 具有最高当前密钥的节点的增量密钥(无论是哪一个) 键大于0的任何给定节点的减量键 操作1-4将是恒定时间,但操作5是O(n),其中n=具有相同键值的节点数。这是因为这些节点在递增时,必须移动到具有相同键值的同级节点之后,并放置在该范围之后。并且发现重新插入的位置将是O(n) 我认为heap

我现在有一个按降序排列的对象的双链接列表。(列表是侵入性的——对象中的指针。)我有一组非常有限的操作:

  • 添加具有最高可能密钥的节点
  • 删除具有最高可能密钥的节点(不管是哪一个)
  • 删除键为0的节点(无论是哪一个)
  • 具有最高当前密钥的节点的增量密钥(无论是哪一个)
  • 键大于0的任何给定节点的减量键
  • 操作1-4将是恒定时间,但操作5是O(n),其中n=具有相同键值的节点数。这是因为这些节点在递增时,必须移动到具有相同键值的同级节点之后,并放置在该范围之后。并且发现重新插入的位置将是O(n)

    我认为heap(heapsort heap,而不是malloc heap)是一种解决方案,其中最坏的情况是O(logn)(其中n=节点数)。然而,根据我的回忆和谷歌的发现,它似乎总是以数组的形式实现,而不是以二叉树的形式实现。因此:


    问题:是否有一种堆实现以二叉树的方式使用指针,而不是数组的方式,来维护典型数组实现的O()?

    一种常见的方法是使用基于数组的堆,但是:

    • 在堆中存储指向节点的指针
    • 在每个节点中,将其索引存储在堆中;及
    • 无论何时交换堆中的元素,都会更新相应节点中的索引
    这保留了所有堆操作的复杂性,每个节点大约需要1.5个指针和1个整数。(额外的.5是因为可扩展阵列的实现方式)


    或者,您可以将节点链接到一个带有指针的树中。但是,为了支持所需的操作,每个节点需要3个指针(父节点、左节点、右节点)

    这两种方法都可以很好地工作,但是阵列实现更简单、更快,并且使用的内存更少

    预计到达时间:


    不过,我应该指出,如果使用指针,那么可以使用不同类型的堆。斐波那契堆将允许您在摊余常数时间内减少节点的值。不过,这有点复杂,而且在实践中很慢:

    不幸的是,书面问题的答案并不是书面问题标题的答案

    解决方案1:摊销O(1)数据结构

    找到了一个解决方案,其中包括所有必需操作的摊销O(1)实现

    它只是一个双链表的双链表。“主”双链接列表节点称为父节点,每个键值最多有一个父节点。父节点保留具有相同键值的子节点的双链接列表。每个子级还指向其父级

  • 添加具有最高可能值的节点:如果没有列表头或其值不是最大值,请将新节点添加到主链接列表头。否则,将其添加到头部节点的子列表的尾部

  • 删除可能具有最高值的(任何)节点:如果有多个具有最高值的项目,则删除哪一个并不重要。因此,如果头部父项有子项,则从子项列表中删除尾部子项。否则,请从主列表中删除父级

  • 删除值为0的(任意)节点:相同的操作

  • 当前值最高的(任意)节点的增量值:如果多个节点具有相同的键值,我们可以选择任意一个,因此选择头部父节点的尾部子节点。将其从子列表中删除。如果增加它的值超过了最大值,那么就完成了。否则它就是一个新的头部节点。如果没有子级,则在适当的位置增加头部父级,如果超过最大值,则将其移除

  • 任何大于0的节点的递减值:如果该节点是子节点,请从子列表中删除,然后添加到父节点的后续子列表或作为父节点之后的新节点。没有子项的父项:如果主列表中的后续项仍然具有较小的键,则完成。否则,将其删除并添加为继任者的尾部子项。有孩子的父母:相同,但要让领班的孩子代替这是O(n),其中n=给定大小的节点数,因为必须更改所有子节点的父指针。但是,如果选择递减的节点作为给定大小的所有节点的父节点的几率为1/n,则摊销为O(1)

  • 主要的缺点是逻辑上每个节点有7个不同的指针。如果是父角色,我们需要上一个和下一个父角色,以及头和尾子角色。如果是子角色,我们需要上一个和下一个子角色,以及父角色。这些指针可以合并为4和3指针的两个交替子结构,这样可以节省存储空间,但不会节省CPU时间(可能需要将未使用的指针归零以保持清洁)。更新它们不会很快

    解决方案2:草率就足够了

    另一种方法就是草率行事。该应用程序从查找分数较高的节点中获益,但它们绝对处于完美的顺序并不重要。因此,我们可以接受一种解决方案,而不是通过O(n)操作将节点从链的一端潜在地移动到另一端,这种解决方案可以执行O(1)操作,尽管有时并不完美

    这可能是目前实施的一种双重链接列表。它可以支持除O(1)中的减量以外的所有操作。它可以处理O(1)中唯一键值的递减。只有非唯一键值的递减才会变为O(n),因为我们需要跳过具有上一个键值的剩余节点,以找到具有相同或hi的第一个节点