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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

高级数据结构与算法 | 并查集(Union-Find)

發布時間:2024/4/11 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 高级数据结构与算法 | 并查集(Union-Find) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 并查集的原理
  • 并查集的實現
  • 例題


并查集的原理

在一些應用問題中,需要將n個不同的元素劃分成一些不相交的集合開始時,每個元素自成一個
單元素集合,然后按一定的規律將歸于同一組元素的集合合并
。在此過程中要反復用到查詢某一
個元素歸屬于那個集合的運算
。適合于描述這類問題的抽象數據類型稱為并查集(union-find
set)。

并查集底層通常常用數組存儲,并且存在以下特性

  • 數組的下標對應集合中元素的編號
  • 數組中如果為負數,負號代表根,數字代表該集合中元素個數
  • 數組中如果為非負數,代表該元素雙親在數組中的下標
  • 這里舉一個例子,假設今年秋季大一開學時班級共有10名學生,上海3人,海南4人,廣東3人。這些學生都是剛進入校園,彼此都不認識,一開始每一個學生都是一個獨立的小團體,現在用下標來為學生們編號,順序按照上面的所在地。

    因為來自同一個地方的學生他們從小的風俗習慣都十分接近,并且也有共同話題,所以很快他們就形成了自己的小團體


    緊接著,因為來自上海的2號同學和來自海南的5號同學是同一個宿舍的,所以他也很快融入了2號的朋友圈,并且把自己的朋友也介紹給2號,所以此時上海和海南的朋友圈集合開始交集


    通過這個結構,可以確認此時存在著兩個集合,集合上海-海南共有7人,集合背景共有3人。

    通過這種并查集的結構,可以用來解決以下問題

  • 查找元素屬于哪個集合
  • 查看兩個元素是否屬于同一個集合
  • 將兩個集合歸并成一個集合
  • 集合的個數

  • 并查集的實現

    class UnionFindSet { public://初始化時將所有元素置為-1,表示每一個都是獨立的集合UnionFindSet(size_t size): _ufs(size, -1),_rank(size, 1){}//找到某一個集合的根int FindRoot(int index){//根節點的值為負數,如果不為負則說明不是根節點,繼續找while (_ufs[index] >= 0){//因為每個節點存儲自己父節點的下標,所以往上繼續查找index = _ufs[index];}return index;}//將兩個集合并集bool Union(int x1, int x2){int root1 = FindRoot(x1);int root2 = FindRoot(x2);//本來就是一個集合,不需要合并if (root1 == root2){return false;}/*優化,讓小集合掛在大集合上,減少查詢次數if (_rank[root1] < _rank[root2 ]) {swap(root1 , root2);}_rank[root1] += _rank[root2];*///選擇root1作為根,將root2所在集合合并到root1中_ufs[root1] += _ufs[root2];//將另一個的父節點設置為root1_ufs[root2] = root1;return true;}//求集合的個數,即負節點的個數size_t count() const{size_t count = 0;for (auto it : _ufs){if (it < 0){count++;}}return count;}private:std::vector<int> _ufs;std::vector<int> _rank; //用于加速查找 };

    例題

    并查集一般可以解決以下問題

  • 查找元素屬于哪個集合
  • 查看兩個元素是否屬于同一個集合
  • 將兩個集合歸并成一個集合
  • 集合的個數
  • 例如leetcode-547.朋友圈就屬于上面的第四種問題,也就是我最開始舉例的那個問題

    class Solution { public:int findCircleNum(vector<vector<int>>& M) {UnionFindSet ufs(M.size());/*M[i][j] = x 代表著i同學和j同學之間的關系為x*/for(int i = 0; i < M.size(); i++){for(int j = 0; j < M[i].size(); j++){//如果為朋友,則將兩人并集if(M[i][j] == 1){ufs.Union(i, j);}}}return ufs.count();} };

    leetcode-990. 等式方程的可滿足性就屬于上面的第二類問題

    主要思路就是判斷不等集合是否與相等集合產生交集

    /*思路:兩次遍歷數據,第一次將所有相等集合并集。第二次查找相等集合中是否有數據存在于不等集合,如果有則說明產生互斥,返回false */ class Solution { public:bool equationsPossible(vector<string>& equations) {UnionFindSet ufs(26);for(const auto& str : equations){//將相等的數據放入集合中if(str[1] == '='){ufs.Union(str[0] - 'a', str[3] - 'a');}}for(const auto& str : equations){//判斷不等的兩端是否處于集合,如果有則說明產生互斥,不滿足條件,返回falseif(str[1] == '!'){if(ufs.FindRoot(str[0] - 'a') == ufs.FindRoot(str[3] - 'a')){return false;}}}return true;} };

    總結

    以上是生活随笔為你收集整理的高级数据结构与算法 | 并查集(Union-Find)的全部內容,希望文章能夠幫你解決所遇到的問題。

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