【发布时间】:2018-12-16 20:05:35
【问题描述】:
我有一组半百万的项目存储在数据库中,需要以下操作:
-
union(x, y)就像在 Union-Find 中一样 -
findAll(x)查找所有y使得find(x) == find(y) -
ununion(x, y)恢复以前的联合操作
这是一个实际问题,已知如下
- 分区通常很小(少于 100 个元素),但不能保证。
-
union操作的速度并不重要。 -
findAll必须快速并且需要在 SQL 中实现(没有递归/CONNECT BY)。 - 有时,我们发现某些
union实际上是错误的,需要撤消它,同时保留所有之前和之后的unions。这种操作很少见,所以速度无关紧要。 -
findAll没有必要立即看到其他操作所做的更改。一些后处理就可以了。
经典的 Union-Find 算法需要路径压缩(或变体)以提高效率,并且不允许删除边(即使没有路径压缩)。我知道Dynamic connectivity,但它似乎不适用于我的用例。
我想,我们不能使用它,因为findAll 的速度是最重要的。可能,我们应该将所有节点直接链接到根。
关于ununion,我唯一的想法是单独存储所有union操作,并在ununion上,从相应分区中删除所有链接并重做所有相关unions。
这听起来有点像……
在开始实施任何东西之前,我想问一下是否有更智能的算法?
【问题讨论】:
-
从你需要的3个操作中,不包括
find,显而易见的实现是让union(x,y)在x和y之间创建一条边,然后findAll(x)做一个BFS。您确定不想在 SQL 中进行任何类型的递归吗? -
@MattTimmermans 我正在使用没有 CONNECT BY 和 Hibernate 的 MySQL,所以我想,我真的不想递归。
标签: algorithm persistence union-find