森林

森林是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;
        }
    }
}
發佈了119 篇原創文章 · 獲贊 10 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章