Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/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 要将链表升级为优先级堆,但需要按值删除_Algorithm_Data Structures_Heap_Priority Queue_Binary Heap - Fatal编程技术网

Algorithm 要将链表升级为优先级堆,但需要按值删除

Algorithm 要将链表升级为优先级堆,但需要按值删除,algorithm,data-structures,heap,priority-queue,binary-heap,Algorithm,Data Structures,Heap,Priority Queue,Binary Heap,我的数据结构需要三个操作: 在排序中的任意位置插入元素 查找并删除最小元素 (很少)通过插入时返回的某个键删除元素 现有代码是一个单链表,并进行线性搜索以查找插入点。O(n) 查找和删除最小的元素非常简单:拔下并处理头部链接。O(1) insert返回指向链接的指针,delete调用获取该指针。如果它是一个双链接列表,该链接可以简单地删除。O(1)。唉,这个列表是单链接的,并且这个列表被搜索这个地址的节点,所以它是O(n)。此搜索代价高昂,但在某些情况下,它确实允许检测到两次删除节点的尝试:

我的数据结构需要三个操作:

  • 在排序中的任意位置插入元素
  • 查找并删除最小元素
  • (很少)通过插入时返回的某个键删除元素
现有代码是一个单链表,并进行线性搜索以查找插入点。O(n)

查找和删除最小的元素非常简单:拔下并处理头部链接。O(1)

insert返回指向链接的指针,delete调用获取该指针。如果它是一个双链接列表,该链接可以简单地删除。O(1)。唉,这个列表是单链接的,并且这个列表被搜索这个地址的节点,所以它是O(n)。此搜索代价高昂,但在某些情况下,它确实允许检测到两次删除节点的尝试:尝试删除不在列表中的节点将找不到它,因此除了在日志中生成警告之外,不会执行任何操作。另一方面,这些节点存储在后进先出内存池中,因此可能会被重用,因此意外地重新删除一个节点可能会删除其他节点。)

好的,对于堆,插入是O(logn)。删除的最小值为O(日志n)。两者都很简单

但按键删除怎么办?如果我把堆放在一个数组中,它基本上是一个线性搜索,O(n)。我在堆中移动元素以保持heap属性(根据需要上下冒泡),因此我不能只使用节点的地址。另外,除非您接受固定的最大大小,否则您需要重新分配通常移动它的阵列

我认为堆可能是指向实际节点的指针数组,这些节点位于其他地方。每个节点都有它的数组索引,当我在堆中移动指向节点的指针时,我会用它的新数组索引更新节点。因此,删除节点的请求可以为我提供该节点。我在堆中使用节点存储的索引,并删除该指针,因此现在记录(N)。这似乎要复杂得多

考虑到单独分配非移动节点并保持其数组索引字段的更新所带来的额外开销,听起来可能不仅仅是偶尔的线性搜索次数。OTOH,将节点与数组堆分开的一个优点是交换指针比交换整个节点(在我的例子中可能是32字节或更多)更快

有更简单的想法吗?

好的。 您可以在内存中保存:

  • 您的数据结构包含动态分配的有效负载和优先级。结构(指针)的地址是
    删除键
  • 保留和维护二进制堆,包含指向这些数据结构的
    指针。但是,heapify元素根据优先级,包含在结构中,通过指针
因此,您的算法:

  • 插入:创建数据结构,部署指向堆的指针,重新平衡堆:Log(N)

  • 删除最后一个:从堆中获取最后一个元素,删除struct,从堆中删除最后一个元素,重新平衡堆:Log(N)

  • 删除随机元素:获取元素的指针,按指针获取优先级,按优先级在堆中搜索此元素:Log(n)。删除结构,从堆中删除指针。重新平衡堆-再次记录(N)


数据节点在排队时分配,在出列时解除分配,并且不移动。当您对数据排队时,返回值是该节点的地址,尽管为了保持API干净,返回值的类型是不透明的

堆是指向这些节点的指针堆

数据节点有一个无符号int,它保存指向它们的指针的当前数组偏移量

当我们移动指针时(由于诸如insert或delete之类的堆操作),我们会更新它的节点索引。例如,如果我们确定我们的密钥优先级高于我们的父级,我们会将父级移动到当前位置,如下所示:

apnode[i] = apnode[iParent];
apnode[i]->iOffset = i;
使用任意键插入数据,使用最高优先级键删除节点,工作正常。两者都是O(logn)

新的操作是删除尚未达到最高优先级的节点,包括将不透明键转换回指针,取消引用以获取相应指针的当前偏移量,然后删除该偏移量。因此,到达delete的指针是一个非常快的O(1)。此时,删除它通常是O(logn)

支持此随机删除的额外开销相当于设置该偏移量。这只是一行代码,但另一方面,与没有此功能的指针堆相比,它大大增加了所接触的缓存线集。另一方面,堆作为指针堆可能比实际将数组元素作为节点本身要快得多


几乎完全脱离主题,但对于阅读以下内容的人非常有用:

所有教科书似乎都按如下方式呈现堆操作:将项目添加到堆的末尾,然后进行交换以将其向下堆到它所属的位置。不过,每一笔掉期交易都有三条指令。更有效的是,把堆的指针作为新数据的候选目的地(CD),而不是在那里写。
然后,将新数据的键与父项进行比较。如果新数据的优先级较低或相等,请将其写入CD并完成。否则,只需将父对象复制到CD,父对象的地址就成为新CD。重复一遍。这将实际数据移动量减少了2/3。

我认为,您可以使用普通的树结构,每个节点包含3个指针:(up、rson、lson)。由于此类节点不会在内存中移动,因此可以使用直接指针作为“插入时返回的某个键”来删除节点。如果您想关心树的平衡,只需实现rb-tree左右。这当然是个好主意。我必须关心树的平衡,所以我需要一棵红黑相间的树。我有一个代码,它比STL的-g和-O2都快,所以可以使用它,modifyi