日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

并查集(加权规则、折叠规则)

發布時間:2024/4/17 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 并查集(加权规则、折叠规则) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.基本知識概念

等價類與并查集。如果用符號“=”表示集合上的等價關系,那么對于該集合中的任意對象x,y,z,下列性質成立 :
自反性:x=x(即等于自身)
對稱性:若x=y,則y=x
傳遞性:若x=y且y=z,則x=z
一個集合S中的所有對象可以通過等價關系劃分為若干個互不相交的子集S1,S2,S3,…,它們的并集就是S,這些子集即為等價類。
確定等價類的方法:
第一步:讀入并儲存所有的等價對(i,j);
第二步:標記和輸出所有的等價類。

2.解決步驟分析:

假定給定集合:S={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
及以下等價對:
①0=4
②3=1
③6=10
④8=9
⑤7=4
⑥6=8
⑦3=5
⑧2=11
⑨11=0
我們以等式左邊的值為根,最后一棵樹是一個等價類,如果兩個結點的根節點相同,就是在一個等價類。
如下解決過程:

如下圖,黑色的為單個等價類,其他顏色相同的為一個等價類,我們以等號左邊的作為根:

處理完⑤-⑧后的結果 :

處理完⑨后的結果 :

3.解決代碼:

3.1正常普通解決代碼:

class UFsets { private:int* parent;unsigned int size; public:UFsets(unsigned int sz){size = sz;parent = (int*)malloc(sizeof(int) * sz);for (int i = 0; i < size; i++){parent[i] = -1;}}~UFsets(){free(parent);}bool Union(int a, int b){bool res = false;int ra = FindParent(a);int rb = FindParent(b);if (ra != rb){parent[ra] += parent[rb];parent[rb] = ra;res = true;}return res;}int FindParent(int ra){while (parent[ra] >= 0){ra = parent[ra];}return ra;}void Print(int ri){printf("%3d ", ri);for (int i = 0; i < size; i++){if (parent[i] == ri){Print(i);}}}void PrintSet(){int s = 0;for (int i = 0; i < size; i++){if (parent[i] < 0){printf("第 %d 集合\n", ++s);Print(i);printf("\n");}}} };int main() {UFsets set(12);set.Union(0, 4);set.Union(3, 1);set.Union(6, 10);set.Union(8, 9);set.Union(7, 4);set.Union(6, 8);set.Union(3, 5);set.Union(2, 11);set.Union(11, 0);return 0; }

調試查看parent值發現和我們分析時最后的數組結果一樣(我統一以等價左邊的值作為根):

用類的PrintSet()打印各個等價類結果:

4.加權規則和折疊規則

但是Find和Union的操作性能不好。假設最初n個元素構成n棵樹組成的森林,parent[i] = -1。做處理Union(n-2,n-1),Union(n-3,n-1),Union(n-4,n-1)…Union(0,n-1)后,將產生如下圖所示的退化的樹:

執行一次Union操作需時間O(1),n-1此是O(n)。若再執行Find(0),Find(1),…,Find(n-1),若被搜索的元素為i,完成Find(i)操作為O(i),完成n次搜索是O(n^2)。
所以在這里提出了加權規則和折疊規則。

4.1加權規則

先判斷兩個集合中的結點個數,如果以i為根的樹中的結點個數少于以j為根的樹中的結點個數,即parent[i] > parent[j],則讓j成為i的雙親,否則,讓i成為j的雙親。以下即為加權規則代碼嗎,將以下代碼添加到class UFsets中即可。

bool WeightedUnion(int a, int b)//加權規則{bool res = false;int ra = FindParent(a);int rb = FindParent(b);if (ra != rb){if (parent[ra] > parent[rb])//說明parent[rb]結點更多,讓rb成為根節點{parent[rb] += parent[ra];parent[ra] = rb;}else//讓ra成為根節點{parent[ra] += parent[rb];parent[rb] = ra;}res = true;}return res;}

4.2折疊規則

如果j是從i到根的路徑上的一個結點,并且parent[j] ≠ root,則把parent[i]置于root,意思是讓i的雙親直接為root。
如下即為從i結點向上壓縮路徑,將代碼添加到class UFsets中即可 :

//折疊規則壓縮路徑void Coollapsingfind(int i){int j = i;while (parent[j] >= 0)//尋找樹的根節點{j = parent[j];}while (i != j){int tmp = parent[i];parent[i] = j;i = tmp;}}

以下為折疊壓縮后的結果:

總結

以上是生活随笔為你收集整理的并查集(加权规则、折叠规则)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。