森林

森林是n>=0个互不相交的树的集合,如:二叉树删除一个根,就可以转换为森林。
如果T1,….Tn是一个森林,则对应于该森林的二叉树记为B(T1,…..,Tn),那么就有以下定义:
若n=0,森林就为空。
根为森林中第一颗树T1的根,左子树是B(T11,T12,…..,T1n),其中T11,T12,…..,T1n是T1根的所有子树,右子树是B(T2,…..,Tn)。
如:
这里写图片描述
这里写图片描述
因此森林的遍历操作跟二叉树的遍历操作一一对应。
假设有编号为0到9,要化为三个互不相交的集合,s1={0,6,7,8},s2={1,4,9},s3={2,3,5},那么可以将其转换森林方式存储,如图:
这里写图片描述
为了实现通过其根结点来判断一个元素在那个集合中以及实现两两互不相交的集合合并操作,对于每一个集合,都需保留一个指向代表这个集合的树的根结点的指针,这样就可以通过指向根结点的父链来找到元素所在的集合,并返回指向集合名字的指针,表示S1,S2,S3这种存储方式如图:
这里写图片描述
为了简化上面两种操作,将不适用集合的名字,而是用索引来表示集合名字,如:假设表name[]存放集合的名字,如果i是一个元素它在以j为根结点的树中,而且有一个指针,指向在集合名字表中的第k项,那么,集合的名字就是name[k]。
由于树中结点被编号为0到n-1,所以,可以用数组把结点的编号作为下标,这就意味着每一个结点只需要一个链接到其父结点域,即父结点的下标,而集合根结点的父亲为-1,S1,S2,S3数组存储方式表示如图:
这里写图片描述
为了防止产生退化树,在合并集合时,可以应用一个加权规则:如果树 i的结点树少于树j的结点数,则令树j是树i的父亲,否则,令树i是树j的父亲.
为了实现加权规则,需要知道每棵树的结点树,为此,在每棵树的根结点保留一个技术域,如果i是根结点,那么count[i]的值等于树中结点的个数,因为树中的所有结点(根结点除外)在父亲域都有一个非负数,所以,可以把结点的计数值作为负数保存在根结点的父亲域中。
查找元素i的根结点来判断在那个集合中的代码实现:

//返回该元素的根结点的索引
int find(int i)
{
    for(;parent[i]>=0;i=parent[i]);
    return i;
}

合并集合的代码实现:

//合并集合操作
// i,j为不同集合树的根结点的索引
 void union2(int i,int j)
 {
     //注意:初始化时parent[i]=-count[i],parent[j]=-count[j]
     //故parent[i],parent[j]是用结点个数的负数表示
     if(i!=j)
     {
         int temp=parent[i]+parent[j];
         // i的结点数比j小时
         if(parent[i]>parent[j])
         {
             parent[i]=j;
             parent[j]=temp;
        }
         // j的结点数比i小时
        else
        {
            parent[j]=i;
            parent[i]=temp;
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值