Algorithm 联合查找算法如何与“联合查找”一起使用;“真正的”;数据
在普林斯顿算法课程开始时,介绍了动态连通性问题(快速查找、快速联合)。下面是对它的描述: 输入是一个整数对序列,其中每个整数 表示某种类型的对象,我们将解释对pq 正如“p与q相连”的意思一样,我们假设“p与q相连”是 等价关系,这意味着它是Algorithm 联合查找算法如何与“联合查找”一起使用;“真正的”;数据,algorithm,set,Algorithm,Set,在普林斯顿算法课程开始时,介绍了动态连通性问题(快速查找、快速联合)。下面是对它的描述: 输入是一个整数对序列,其中每个整数 表示某种类型的对象,我们将解释对pq 正如“p与q相连”的意思一样,我们假设“p与q相连”是 等价关系,这意味着它是 反身:p是 连接到p 对称:如果p连接到q,那么q是 连接到p 传递的:如果p与q相连,q是 连接到r,则p连接到r 它有一个简单的实现,叫做快速查找: 一种方法是保持p和q连通的不变量 当且仅当id[p]等于id[q]。换句话说,所有站点都在一个 组
- 反身:p是 连接到p
- 对称:如果p连接到q,那么q是 连接到p
- 传递的:如果p与q相连,q是 连接到r,则p连接到r
快速查找:
一种方法是保持p和q连通的不变量
当且仅当id[p]等于id[q]。换句话说,所有站点都在一个
组件在id[]中必须具有相同的值。调用此方法
快速查找,因为find(p)只返回id[p],它会立即
表示连接的(p,q)仅减少到测试id[p]==id[q]
当且仅当p和q在同一个分量中时返回true…To
将这两个组件组合成一个,我们必须使所有id[]
两组站点对应的条目具有相同的值,如图所示
在右边的例子中
我的问题是如何将其用于真实对象?它适用于整数,但如果我需要知道对象A
是否连接到对象B
,而不是3
连接到5
,该怎么办?我能想到的一个解决方案是拥有一个对象数组,其中数组中每个对象的索引对应于用于连接的数组的索引。例如:
1 2 3 4 5
[ { } { } {A} { } {B} ] <---- real data
1 2 3 4 5
[ 1 2 3 4 3 ] <---- connections (3 and 5 have the same group id 3)
12345
[{}{{}{}{{}{{B}]Short安瑟:是的
更详细的回答:您必须将真实对象映射到整数。
映射的方法之一是对两种类型的对象使用相同的表(如您所说)
大多数编程语言都有内置映射。例如C语言有“字典”类,C++有“map”类。
您也可以编写自己的映射。您的建议肯定会奏效,但当对象列表以某种方式发生变化(例如,以不同方式排序)时,可能会成为一件麻烦事
通过使用所提到的id
属性(或任何其他名称)扩展对象,可以实现所提到的quick find
方法
例如,如果您有这些对象(使用Python语法):
a={“num”:1,“code”:“test”};
b={“num”:15,“code”:“house”};
c={“num”:9,“code”:“garden”};
d={“num”:4,“code”:“flower”};
e={“num”:24,“code”:“cat”};
然后将id
属性添加到这些对象中(这种扩展的语法在许多语言中都不同):
a[“id”]=1#使用附加属性扩展对象。
b[“id”]=2
c[“id”]=3
d[“id”]=4
e[“id”]=3
然后创建一个函数,告诉您两个对象是否连接,如快速查找所述:
def已连接(x,y):
返回x[“id”]==y[“id”];
在这种情况下,以下测试的结果为真:
print(连接(c,e));#真的
备选方案:保持连接分离
如果不想通过添加id
属性来改变原始对象,可以创建单独的贴图。某些语言可以为每个对象提供唯一的标识符。例如,在Python中,可以使用内置的id()
函数检索该标识符。如果不可用,您将使用对象的唯一属性,该属性在示例数据中为num
属性。因此,在Python中:
conn = {}
conn[id(a)] = 1
conn[id(b)] = 2
conn[id(c)] = 3
conn[id(d)] = 4
conn[id(e)] = 3
def are_connected(x, y):
return conn[id(x)] == conn[id(y)];
print (are_connected(c, e)); # True
快速联合算法
在这种方法中,您不会(总是)为连接的对象存储相同的id,而是让它们指向同一组连接对象中的另一个(子对象到父对象),树的根指向自身
如果需要测试两个对象是否连接,则可以找到它们各自连接的两个根(通过它们的祖先遍历到树的顶部),并查看它们是否共享该根
使用稍有不同的样本数据,并使用id
属性,它将如下所示:
a c
| / \
b d e
/
f
a={“num”:1,“code”:“test”};
b={“num”:15,“code”:“house”};
c={“num”:9,“code”:“garden”};
d={“num”:4,“code”:“flower”};
e={“num”:24,“code”:“cat”};
f={“num”:88,“code”:“dog”};
然后将id
属性添加到这些对象中(这种扩展的语法在许多语言中都不同):
a[“id”]=a#它是根,所以是自引用
b[“id”]=a#与a相同的组
c[“id”]=c#不同树的根
d[“id”]=c#与c同一组
e[“id”]=c#与c同一组
f[“id”]=d#与c是同一组,但是d的子级
这可以这样表示:
a c
| / \
b d e
/
f
告诉您两个对象是否连接的函数现在如下所示:
a c
| / \
b d e
/
f
def已连接(x,y):
而x[“id”]!=x:#而不是根
x=x[“id”]#在树上向上走
而y[“id”]!=y:#y也一样
y=y[“id”]#在树上向上走
返回x==y;#如果根相同:则连接原始对象
请注意,您也可以将其编写为递归函数
在这种情况下,以下测试的结果为真:
print(是否连接(e,f))#真的
然后将id属性添加到这些对象中-谢谢,如何跟踪集合并加入它们?可以使用quick find
实现并更新集合中所有对象的id
,但这是低效的,因为它具有O(n)
运行时复杂性。更好的实现加权快速联合
,它与