一种有效的数据结构,用于按 ID 访问和查找加权随机项

An efficient data structure for access by ID and finding the weighted random item

本文关键字:访问 ID 查找 随机 加权 用于 一种 有效 数据结构      更新时间:2023-10-16

您能否帮助我处理允许对以下内容进行O(logN)(或至少O(sqrtN)(操作的数据结构:

  1. 插入具有ID(int64_t(和health(double(的项目
  2. ID删除项目
  3. 查找按health随机加权的项目

首选语言是 C++ 或 C。加权随机是指以下内容:

考虑totalHealth=Sum(health[0], health[1], ..., health[N-1]).我需要一个快速(如上所述(操作,相当于:

  1. 计算const double atHealth = rand_uint64_t()*totalHealth/numeric_limits<uint64_t>::max();
  2. 遍历i=0 to N-1以找到第一个i,以便Sum(health[0], health[1], ..., health[i]) >= atHealth

约束:health[i] > 0rand_uint64_t()返回一个在0numeric_limits<uint64_t>::max()之间均匀分布的整数值。

到目前为止,我尝试的是一种C++unordered_map,它允许通过ID快速(Θ(1)(插入和通过ID删除,但是操作#3在N中仍然是线性的,如我上面的伪代码中所述。

非常感谢您的帮助!

我想不出使用现有 STL 容器的方法,但如果您愿意编写自己的二叉树,我可以想到一种方法。诀窍是每个节点都保持其左侧所有节点的总运行状况(它不需要担心其右侧的节点,如下所示(。然后,如果您按 ID 顺序遍历树,您还可以按 ID 顺序计算log(n)时间内的"累积运行状况"。因此,树按 ID 和累积运行状况排序,您可以按 ID 或"累积运行状况"log(n)时间进行查找。例如,考虑一个非常简单的树,如下所示:

ID: 8
h: 10
chl: 15
+-------|--------+
|                |
ID: 4          ID: 10
h: 15          h: 7
chl: 0         chl: 0

在上面的h中是节点的运行状况,chl是其左侧所有节点的累积运行状况。因此,上述所有节点的总运行状况为 15 + 10 + 7 = 32(我假设您单独维护该计数,尽管您也可以正确跟踪节点的累积运行状况,并且您不需要(。让我们看3个案例:

  1. 您计算atHealth < 15.然后在第一个节点,您可以看到您的值小于chl因此您知道需要向左走,最终到达正确的叶子。
  2. 你计算一个atHealth >= 15 < 25所以你知道它是> 15,所以你不会在根部左走,你所在的节点的运行状况为 10 和 10 + 15 意味着该节点的累积运行状况在 15 到 25 之间,所以你很好。
  3. 您计算atHealth >= 25。每次访问节点并向右移动时,您都必须添加您所在节点的chlh,以便在您走树时继续计算累积运行状况,这样您就知道您从10 + 25 = 25开始,当您向右走时,您会将其添加到之后遇到的任何节点的hchl中。因此,您可以快速发现右侧的节点是正确的。

插入新节点时,在遍历树时,每个父节点的总运行状况递增;删除节点时,从树上走回总运行状况。因此,插入和删除仍然是O(log(n)),按 ID 查找也是按 ID 或按atHealthlog(n)的。

如果你想保持一个平衡的树,事情显然会变得更加复杂,但它仍然是可行的。