C++ 用于快速插入和删除的堆O(日志n)

C++ 用于快速插入和删除的堆O(日志n),c++,c,algorithm,search,C++,C,Algorithm,Search,我试图找到一种算法,该算法具有以下几个特性: 使用阵列作为存储(缓存友好) 仅存储无符号整数 没有关联的值 插入和删除第i项的顺序应为O(对数n)时间 保持结构稳定,以便在遍历时删除元素 单个项目的顺序和查找不重要,也不重要 对于这类问题有很多解决方案。 一种非常常见的是红/黑树木。我不喜欢用树来解决这个问题,因为我必须使用动态内存和其他东西(比如存储我不需要的指针和相关值) 我考虑的另一个选择是使用二进制堆。它设计用于快速删除最小/最大元素,因此适用于优先级队列。在我的例子中,我需要一些允

我试图找到一种算法,该算法具有以下几个特性:

  • 使用阵列作为存储(缓存友好)
  • 仅存储无符号整数
  • 没有关联的值
  • 插入和删除第i项的顺序应为O(对数n)时间
  • 保持结构稳定,以便在遍历时删除元素
  • 单个项目的顺序和查找不重要,也不重要
对于这类问题有很多解决方案。 一种非常常见的是红/黑树木。我不喜欢用树来解决这个问题,因为我必须使用动态内存和其他东西(比如存储我不需要的指针和相关值)

我考虑的另一个选择是使用二进制堆。它设计用于快速删除最小/最大元素,因此适用于优先级队列。在我的例子中,我需要一些允许删除堆中任意项的扩展版本。 是否可以在日志(n)时间内进行删除。有人在网上提到,如果你在数组中有位置,情况就是这样。然而,我找不到证据证明这是正确的。 另一个是删除过程中的稳定性。
如果答案是否定的,您有什么建议?

是的,可以在堆中的随机元素上执行O(lg n)时间的删除

怎么做?假设这是您的堆:

                   4
                 /   \
                10   20
               /  \  ...
              30  40  ...
             /  \   ......
            50  60
假设你想移除10个,然后(因为这是一个最小的堆)你得到10个最小的孩子并放到他的位置上,然后你从10个最小的孩子(30)开始重新开始,并把30个最小的孩子带上来(50)

如果正确构建了堆,则在该方法运行时将保留这些属性

事实上,这只是一个不从根开始的Heapify

        4                    4                    4 
      /   \                /   \                /   \
   [10]   20              30   20              30   20
   /  \   ...    =>      /  \   ...    =>     /  \   ...
  30  40   ...        [30]  40   ...         50  40   ...
 /  \    ......       /  \     ......       /  \    ......
50  60               50  60              [50]  60

是的,可以在堆中的随机元素上执行O(lgn)时间的删除

怎么做?假设这是您的堆:

                   4
                 /   \
                10   20
               /  \  ...
              30  40  ...
             /  \   ......
            50  60
假设你想移除10个,然后(因为这是一个最小的堆)你得到10个最小的孩子并放到他的位置上,然后你从10个最小的孩子(30)开始重新开始,并把30个最小的孩子带上来(50)

如果正确构建了堆,则在该方法运行时将保留这些属性

事实上,这只是一个不从根开始的Heapify

        4                    4                    4 
      /   \                /   \                /   \
   [10]   20              30   20              30   20
   /  \   ...    =>      /  \   ...    =>     /  \   ...
  30  40   ...        [30]  40   ...         50  40   ...
 /  \    ......       /  \     ......       /  \    ......
50  60               50  60              [50]  60

如果我正确理解了这个问题,那么您就不需要能够按值查找项目,也不必关心它们的顺序

如果是这样的话,那么你应该从一开始就把它们放在一个数组中。如果你必须在中间删除一个项目,那么只需将它与项目和结束进行交换,然后从那里删除它。


在遍历数组时也很容易做到这一点。当你删除一个项目时,你只是不增加位置,因为下一个要访问的项目被替换到了你删除的项目的位置。

如果我正确理解了这个问题,那么你就不需要能够按值查找项目,你也不在乎它们的顺序是什么

如果是这样的话,那么你应该从一开始就把它们放在一个数组中。如果你必须在中间删除一个项目,那么只需将它与项目和结束进行交换,然后从那里删除它。


在遍历数组时也很容易做到这一点。当你删除一个项目时,你只是不增加位置,因为下一个要访问的项目被交换到了你删除的项目的位置。

作为负面证据:使用数组如果你删除第n个元素,你要么以某种方式跟踪间隙(不好),要么折叠空间。折叠空间是顺序(n-i)操作,对于O(n)的随机删除,该操作趋向于顺序(n/2)。有一些red/back方法使用第二个索引数组,可能是O(logn)?“保持结构稳定,以便在遍历时可以删除元素。”用法是,在遍历期间(可能使用迭代器),可以选择要删除的项。然后遍历可以继续删除项,而无需从头开始。这是一个很好的工具,可能不需要,但取决于结构和选择的算法。下面是如何做::谢谢,删除K元素的日志证明(n)是很好的。我将看一看其余的html文件。作为负面证据:如果删除第n个元素,则使用数组,您必须以某种方式跟踪间隙(不好)或折叠空间。折叠空间是顺序(n-i)操作,对于O(n)的随机删除,该操作趋向于顺序(n/2)。有一些red/back方法使用第二个索引数组,可能是O(logn)?“保持结构稳定,以便在遍历时可以删除元素。”用法是,在遍历期间(可能使用迭代器),可以选择要删除的项。然后遍历可以继续删除项,而无需从头开始。这是一个很好的工具,可能不需要,但取决于结构和选择的算法。下面是如何做::谢谢,删除K元素的日志证明(n)是很好的。我将查看其余的html文件。正确,但请注意,它会对数组进行重新排序,因此迭代不稳定,并且关于给定元素的索引的任何信息都无效。正确,但请注意,它会对数组进行重新排序,因此,迭代是不稳定的,关于给定元素的索引的任何信息都是无效的。对于我需要的策略之一,这是一个完美的解决方案。谢谢它是O(1)。我不认为它是如此简单:-)对于我需要的政策之一,这是一个完美的解决方案。谢谢它是O(1)。我没想到会这么简单:-)