C++ 快速bucket实现

C++ 快速bucket实现,c++,algorithm,stl,graph-theory,C++,Algorithm,Stl,Graph Theory,在graph类中,我需要处理具有整数值(通常为1-1000)的节点。在每一步中,我都想从图中删除一个节点及其所有邻居。我还希望总是从最小值的节点开始。我花了很长时间思考如何以尽可能快的方式完成这项工作,并决定执行以下操作: 该图使用邻接列表存储 有一个巨大的数组std::vector bucket[1000]按其值存储节点 最低非空桶的索引始终存储并保持跟踪 我可以通过选取索引的一个随机元素或如果bucket已经为空,则增加索引来快速找到最小值的节点 从bucket中删除所选节点显然可以在O(

在graph类中,我需要处理具有整数值(通常为1-1000)的节点。在每一步中,我都想从图中删除一个节点及其所有邻居。我还希望总是从最小值的节点开始。我花了很长时间思考如何以尽可能快的方式完成这项工作,并决定执行以下操作:

  • 该图使用邻接列表存储
  • 有一个巨大的数组
    std::vector bucket[1000]
    按其值存储节点
  • 最低非空桶的索引始终存储并保持跟踪
  • 我可以通过选取索引的一个随机元素或如果bucket已经为空,则增加索引来快速找到最小值的节点
  • 从bucket中删除所选节点显然可以在O(1)中完成,问题是要删除邻居,我需要首先搜索bucket[value of neighbor]中的所有邻居节点,这并不是很快
有没有更有效的方法


我考虑使用类似于
std::list bucket[1000]
的方法,为每个节点分配一个指向其“list元素”的指针,这样我就可以在O(1)中从列表中删除该节点。这在stl列表中是可能的吗?显然,这可以通过我可以手动实现的普通双链接列表来实现吗?

我最近用Bucket实现了一个优先级队列,做了类似的事情

我所做的是使用一个散列表(无序映射),这样,你不需要存储1000个空向量,你仍然可以得到O(1)个随机访问(一般情况下,不保证)。现在,如果您只需要存储/创建这个graph类一次,这可能并不重要。在我的例子中,我需要每秒数十次/数百次地创建优先级队列,并且使用哈希映射产生了巨大的差异(因为我只在实际拥有该优先级的元素时创建无序的_集,所以不需要初始化1000个空哈希集)。哈希集和映射在C++11中是新的,但在std::tr1中已经有一段时间了,或者您可以使用Boost库

我能看到您和我的用例之间的唯一区别是,您还需要能够删除相邻节点。我假设每个节点都包含指向其邻居的指针列表。如果是这样的话,删除邻居应该采取
k*O(1)
k
邻居的数量(同样,通常是O(1),不保证,最坏的情况是无序映射/集合中的O(n))。您只需检查每个相邻节点,获取其优先级,这将为您提供到哈希映射中的正确索引。然后在优先级映射到的哈希集中找到指针,这个搜索通常是O(1),删除元素通常也是O(1)


总而言之,我认为您已经非常清楚该做什么了,但是我相信使用哈希映射/集将使您的代码速度大大提高(当然,这取决于确切的用法)。对我来说,使用
无序映射
实现的速度比
向量
实现的速度提高了大约50倍。

以下是我要做的。节点结构:

struct Node {
    std::vector<Node*>::const_iterator first_neighbor;
    std::vector<Node*>::const_iterator last_neighbor;
    int value;
    bool deleted;
};
struct节点{
std::vector::const\u迭代器第一个\u邻居;
std::vector::const_迭代器last_neighbor;
int值;
删除bool;
};
连接邻接列表并将它们放在单个
std::vector
中,以降低内存管理的开销。我使用的是软删除,所以更新速度并不重要

按值将指向节点的指针排序到另一个带有。将所有节点标记为未删除

按排序顺序遍历节点。如果正在考虑的节点已被删除,请转到下一个节点。否则,将其标记为已删除,并遍历其邻居并将其标记为已删除


如果您的节点连续存储在内存中,那么您可以省略
最后一个邻居
,代价是在结构的末尾增加一个哨兵节点,因为节点的
最后一个邻居
是下一个节点的
第一个邻居

在普通C数组中使用STL容器感觉很奇怪。是的,这个评论是离题的。从向量和列表中删除元素的相对速度是
k*O(n)
k*O(1)
n
k
k
的值也很重要。如果
n
平均值为“小”,则向量可能非常快。输出是什么?一个近似的最小权重支配集?@BoPersson我认为K对于列表来说很小,你只需要调整两个指针来“跳过”链接中的某个元素list@rapmusic这在这里并不重要,但你是对的。谢谢你,这看起来很有希望。我将尝试此方法,并将其与我当前的解决方案进行比较:-)。这也是一种很好的方法,问题是(我必须承认我在问题中忽略了这一点)有时我想更改删除中某些节点的值,而不必重新排序列表。当将所有节点存储到地图中时,这可能更容易。我有点想知道,因为每个节点对标准贪婪算法的吸引力取决于它剩下多少个邻居。如果值只能增加,我会使用一级单调优先级队列(基本上是一个侵入性双链表向量)。否则,我将使用侵入式优先级队列。不幸的是,STL基本上无法提供侵入式数据结构(尽管您可能会看到Boost.intrusive)。谢谢,我肯定会这样做。如果您按照我在回答中解释的方式实现优先级队列设计,那么好的事情是,在O(1)(平均情况)中,几乎任何您可以想象的事情都是可能的,包括改变优先事项。