[算法8]union find算法

最近在抽空看看coursera那个普林斯顿的算法课,有点意思,讲的很清楚。


第一讲是关于并查集的,描述了如何快速判断若干个点组成的集合中,某对点是否连接。


算法没有什么难度,但是存储父节点这个思想很值得学习。之后的再优化就很出色了,记录一下。


以下内容我记录在了自己的note里面。文字内容大概是:

union find:
问题:判断若干个点组成的集合中,某对点是否连接。


判断是否连接:

连接的等价:
reflexive,p和p本身是相连的;
symmetric,p和q相连则q和p相连;
transitive,p和q相连,q和r相连,则p和r相连。

connected components:
最大的组成集,集合内的每一个都是相连的而集合间互不相连。如此,判断p和q是否相连变成了判断p和q是否在同一个集合里。

而union(a,b)这个命令就是将有这a和b两个点的集合相合并。

创建数据集:

根据object的总数N设定一个类,将每两个点之间的相连关系输入其中,判断,如果两个点是不是在同一个set中,如果在,则跳过,否则将有这两个object的集合union,最终形成一个完整的类。


Quick find:
用索引array表示数据所属的类别,find这个行为只用查这个array的值是否相同。

union这个方法需要将一个set的类别值全都改为另一个set的值。

first:
将0~9的值赋予0~9的index。

merge时间复杂度过高,N^2

Quick union:
提高速度的方法。这个方法不是储存该id的类别,而是存该类别所在的树形结构中的父节点id。

这样查找两个点是否在同一set中的时候,只要判断是否能走向相同的root就可以,而merge的时候,只用做一次变换,将原有的根节点连接到另一个根节点上。

union的过程,查找一个id的parentid,如果不是自己(代表不是根节点),接着向上查,找到根节点再将根节点的parentid改成merge的另一个节点的root即可。

这种的find时间复杂度高N,而且如果树太高,容易造成计算root的速度太慢的问题。
Quick union改进方法
with weight
记录树的长度,在merge的时候比较树的size,让小的树改变parent id为大的树的root
左树比右树大
这样find的速度和树的深度成正比,树的深度复杂度为lgN(lg=log2)
2. with path compression
每次求root的时候,将每个子节点的父节点指向上一级节点。这样,复杂度可以提到线性的

union find的应用:
MATLAB中的bwlabel()算法
物理中的percolation,top到bottom可以用概率为p出现的白块连接

价值点:
判断top和bottom是否有相连接的点,与其遍历每一种可能,可以选择将top的所有的点连接到一个父节点,bottom连接到一个父节点,判断这两个父节点是否相连。

bear in mind, scientific thinking


python的demo:

#coding:UTF-8
'''
Created on 2014年7月21日

@author: hao
'''
import time
class quickFind():
    '''
    array中的值是所属的类别
    '''
    def __init__(self, dimension = 10):
        self.idList = range(dimension)
    
    def find(self, aPoint, bPoint):
        if self.idList[aPoint]==self.idList[bPoint]:
            return 'connected'
        else:
            return 'isolated'
    
    def union(self, aPoint, bPoint):
        if self.idList[aPoint]!=self.idList[bPoint]:
            preIndex = self.idList[bPoint]
            for i in range(len(self.idList)):
                if self.idList[i]==preIndex:
                    self.idList[i] = self.idList[aPoint]


class quickUnion():
    '''
    array 记录 节点id
    '''
    def __init__(self, dimension = 10):
        self.idList = range(dimension)
    
    def find(self, aPoint, bPoint):
        aRoot = aPoint
        while(True):
            if aRoot == self.idList[aRoot]:
                break
            aRoot = self.idList[aRoot]
        bRoot = bPoint
        while(True):
            if bRoot == self.idList[bRoot]:
                break
            bRoot = self.idList[bRoot]
        if aRoot == bRoot:
            return 'connected'
        else:
            return 'isolated'
    
    def union(self, aPoint, bPoint):
        aRoot = aPoint
        while(True):
            if aRoot == self.idList[aRoot]:
                break
            aRoot = self.idList[aRoot]
        bRoot = bPoint
        while(True):
            if bRoot == self.idList[bRoot]:
                break
            bRoot = self.idList[bRoot]
        if bRoot != aRoot:
            self.idList[bRoot] = aRoot
    
class quickUnionwithWeight():
    '''
    compare the depth of the tree
    '''
    def __init__(self, dimension = 10):
        self.idList = range(dimension)
        
    def find(self, aPoint, bPoint):
        aRoot = aPoint
        while(True):
            if aRoot == self.idList[aRoot]:
                break
            aRoot = self.idList[aRoot]
        bRoot = bPoint
        while(True):
            if bRoot == self.idList[bRoot]:
                break
            bRoot = self.idList[bRoot]
        if aRoot == bRoot:
            return 'connected'
        else:
            return 'isolated'
    
    def union(self, aPoint, bPoint):
        aRoot = aPoint
        aDepth = 0
        while(True):
            if aRoot == self.idList[aRoot]:
                break
            aRoot = self.idList[aRoot]
            aDepth+=1
        bRoot = bPoint
        bDepth = 0
        while(True):
            if bRoot == self.idList[bRoot]:
                break
            bRoot = self.idList[bRoot]
            bDepth+=1
        if bRoot != aRoot:
            if bDepth>=aDepth:
                self.idList[aRoot] = bRoot
            else:
                self.idList[bRoot] = aRoot
    
    
class quickUnionwithWeightwithPathCompression():
    '''
    compare the depth of the tree
    '''
    def __init__(self, dimension = 10):
        self.idList = range(dimension)
        
    def find(self, aPoint, bPoint):
        aRoot = aPoint
        while(True):
            if aRoot == self.idList[aRoot]:
                break
            aRoot = self.idList[aRoot]
        bRoot = bPoint
        while(True):
            if bRoot == self.idList[bRoot]:
                break
            bRoot = self.idList[bRoot]
        if aRoot == bRoot:
            return 'connected'
        else:
            return 'isolated'
    
    def union(self, aPoint, bPoint):
        aRoot = aPoint
        aPreRoot = 0
        aDepth = 0
        while(True):
            if aRoot == self.idList[aRoot]:
                break
            aPreRoot = aRoot
            aRoot = self.idList[aRoot]
            self.idList[aPreRoot] = aRoot
            aDepth+=1
            
        bRoot = bPoint
        bPreRoot = 0
        bDepth = 0
        while(True):
            if bRoot == self.idList[bRoot]:
                break
            bPreRoot = bRoot
            bRoot = self.idList[bRoot]
            self.idList[bPreRoot] = bRoot
            bDepth+=1
        if bRoot != aRoot:
            if bDepth>=aDepth:
                self.idList[aRoot] = bRoot
            else:
                self.idList[bRoot] = aRoot
      
  
    
if __name__=='__main__':
    a=time.time()
    test = quickFind(100000)
    test.union(1,2)
    test.union(1,3)
    print test.find(2,3)
    print time.time()-a
    
    a=time.time()
    test = quickUnion(100000)
    test.union(1,2)
    test.union(1,3)
    print test.find(2,3)
    print time.time()-a
    
    a=time.time()
    test = quickUnionwithWeight(100000)
    test.union(1,2)
    test.union(1,3)
    print test.find(2,3)
    print time.time()-a
    
    a=time.time()
    test = quickUnionwithWeightwithPathCompression(100000)
    test.union(1,2)
    test.union(1,3)
    print test.find(2,3)
    print time.time()-a


结果是:

connected

0.0421710014343

connected

0.00213694572449

connected

0.00201916694641

connected

0.00193977355957


可以看出算法确实有一定的优化。







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值