最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++并查集的原理與使用方法

 更新時間:2025年12月21日 14:52:53   作者:落羽的落羽  
并查集是一種樹型的數(shù)據(jù)結(jié)構(gòu),用于處理不相交集合的合并及查詢問題,下面這篇文章主要介紹了C++并查集原理與使用方法的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下

一、并查集的概念

在一些場景中,需要將n個不同元素劃分為一些不相交的集合。開始時,每個元素各成一個元素,然后按一定的規(guī)律將屬于同一組的元素合并。這個過程中需要反復(fù)用到查詢一個元素是否屬于某個集合的算法。適合用于這種場景的數(shù)據(jù)結(jié)構(gòu)是并查集(Union-Find Set)!

并查集的底層結(jié)構(gòu)本質(zhì)上是一片森林(多棵樹的集合)

比如,我現(xiàn)在有九個數(shù)據(jù)元素,給他們編號0~8:

按照某種需求,這些數(shù)據(jù)被分組合并為:

按照其他需求,這些樹可以繼續(xù)合并下去…

而這個森林,可以用一個數(shù)組記錄下來元素的關(guān)系!
我們可以規(guī)定并查集用數(shù)組下標(biāo)代表每個元素,數(shù)組內(nèi)容代表元素之間的關(guān)系:

  • 數(shù)組下標(biāo)代表元素編號
  • 如果數(shù)組內(nèi)容為負(fù)整數(shù),代表這個下標(biāo)是根,絕對值表示它這棵樹的元素個數(shù)
  • 如果數(shù)組內(nèi)容為非負(fù)整數(shù),代表這個下標(biāo)不是根,數(shù)組內(nèi)容是它的父親在數(shù)組中的下標(biāo)

比如,上面的森林例子,用并查集數(shù)組表示,就是:

如果元素的數(shù)據(jù)類型不能直接作為數(shù)組下標(biāo),只要在實(shí)現(xiàn)中用std::map之類的結(jié)構(gòu),建立元素到下標(biāo)的映射關(guān)系,就能解決了!

通過并查集的特點(diǎn),可以看出并查集一般能解決:

  • 查找元素屬于哪個集合:沿著數(shù)組一直找到元素為負(fù)數(shù),就是根
  • 查看兩個元素是否屬于一個集合:看看這兩個元素的根是否相同
  • 將兩個集合歸并為一個集合:假如要將下標(biāo)a的樹合并到下標(biāo)b的樹中,arr[b] += arr[a],arr[a] = b即可,即令1成為0的一個孩子
  • 統(tǒng)計集合的個數(shù):統(tǒng)計數(shù)組中元素為負(fù)數(shù)的個數(shù)

二、并查集的實(shí)現(xiàn)

#pragma once
#include<vector>
#include<iostream>
using namespace std;

class UnionFindSet
{
public:
	UnionFindSet(int size)
		:_set(size, -1) // 初始時每個數(shù)據(jù)各是一棵樹,元素均為-1
	{ }

	// 查找一個數(shù)據(jù)屬于哪個集合,找根元素的下標(biāo)
	int FindRoot(int i)
	{
		while (_set[i] >= 0)
		{
			i = _set[i];
		}
		return i;
	}

	// 合并兩個數(shù)據(jù)所在的集合
	void Union(int i1, int i2)
	{
		// 找這兩個數(shù)據(jù)的根下標(biāo)
		int root1 = FindRoot(i1);
		int root2 = FindRoot(i2);

		if (root1 != root2)
		{
			_set[root1] += _set[root2];
			_set[root2] = root1;
		}

		// 如果root1 == root2,說明這兩個數(shù)據(jù)本就在一個集合,不用合并

	}

	// 判斷兩個數(shù)據(jù)是否在同一個集合
	bool IsSameSet(int i1, int i2)
	{
		return FindRoot(i1) == FindRoot(i2);
	}

	// 統(tǒng)計集合個數(shù)
	int SetCount()
	{
		int ret = 0;
		for (int n : _set)
		{
			if (n < 0)
				ret++;
		}
		return ret;
	}

private:
	vector<int> _set;
};

測試:

三、算法題中的應(yīng)用

并查集的特點(diǎn)在某些算法題中很有用:

class Solution {
public:
    // 并查集, 統(tǒng)計集合數(shù)量
    int findCircleNum(vector<vector<int>>& isConnected) {
        vector<int> ufs(isConnected.size(), -1);
        auto findRoot = [&ufs](int i)
        {
            while(ufs[i] >= 0)
            {
                i = ufs[i];
            }
            return i;
        };
        auto Union = [&ufs, &findRoot](int i1, int i2)
        {
            int root1 = findRoot(i1);
            int root2 = findRoot(i2);
            if(root1 != root2)
            {
                ufs[root1] += ufs[root2];
                ufs[root2] = root1;
            }
        };
        auto SetCount = [&ufs]()
        {
            int ret = 0;
            for(int n : ufs)
            {
                if(n < 0)
                    ret++;
            }
            return ret;
        };

        for(int i = 0; i < isConnected.size(); i++)
        {
            for(int j = 0; j < isConnected[i].size(); j++)
            {
                if(isConnected[i][j] == 1)
                {
                    Union(i, j);
                }
            }
        }
        return SetCount();
    }
};
class Solution {
public:
    // 并查集,數(shù)組大小26
    // 遍歷一次把所有==的兩個字母放到一個集合,再遍歷一次看!=的兩個字符是否都在集合中出現(xiàn)過,出現(xiàn)過則false
    bool equationsPossible(vector<string>& equations) {
        vector<int> ufs(26, -1);
        auto findRoot = [&ufs](int i)
        {
            while(ufs[i] >= 0)
            {
                i = ufs[i];
            }
            return i;
        };
        auto Union = [&ufs, &findRoot](int i1, int i2)
        {
            int root1 = findRoot(i1);
            int root2 = findRoot(i2);
            if(root1 != root2)
            {
                ufs[root1] += ufs[root2];
                ufs[root2] = root1;
            }
        };

        for(string& s : equations)
        {
            if(s[1] == '=')
            {
                Union(s[0]-'a', s[3]-'a');
            }
        }
        
        for(string& s : equations)
        {
            if(s[1] == '!')
            {
                int root1 = findRoot(s[0]-'a');
                int root2 = findRoot(s[3]-'a');
                if(root1 == root2)
                {
                    return false;
                }
            }
        }

        return true;
    }
};

總結(jié)

到此這篇關(guān)于C++并查集的原理與使用方法的文章就介紹到這了,更多相關(guān)C++并查集原理與使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++ UML類圖的使用解讀

    C++ UML類圖的使用解讀

    這篇文章主要介紹了C++ UML類圖的使用,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • C/C++中文件的隨機(jī)讀寫詳解及其作用介紹

    C/C++中文件的隨機(jī)讀寫詳解及其作用介紹

    這篇文章主要介紹了C/C++中文件的隨機(jī)讀寫詳解及其作用,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • C語言?動態(tài)內(nèi)存管理全面解析

    C語言?動態(tài)內(nèi)存管理全面解析

    動態(tài)內(nèi)存是相對靜態(tài)內(nèi)存而言的。所謂動態(tài)和靜態(tài)就是指內(nèi)存的分配方式。動態(tài)內(nèi)存是指在堆上分配的內(nèi)存,而靜態(tài)內(nèi)存是指在棧上分配的內(nèi)存,本文帶你深入探究C語言中動態(tài)內(nèi)存的管理
    2022-02-02
  • Qt中配置Limereport的數(shù)據(jù)庫數(shù)據(jù)源的實(shí)現(xiàn)

    Qt中配置Limereport的數(shù)據(jù)庫數(shù)據(jù)源的實(shí)現(xiàn)

    本文介紹了在Qt中為Limereport配置數(shù)據(jù)庫數(shù)據(jù)源的方法,文章提供了MySQL、PostgreSQL等不同數(shù)據(jù)庫的連接示例,并詳細(xì)說明了數(shù)據(jù)綁定和參數(shù)設(shè)置,感興趣的可以了解一下
    2025-09-09
  • C語言 strftime 格式化顯示日期時間的實(shí)現(xiàn)

    C語言 strftime 格式化顯示日期時間的實(shí)現(xiàn)

    下面小編就為大家?guī)硪黄狢語言 strftime 格式化顯示日期時間的實(shí)現(xiàn)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • 詳解OpenMP的線程同步機(jī)制

    詳解OpenMP的線程同步機(jī)制

    在本篇文章當(dāng)中主要給大家介紹?OpenMP?當(dāng)中線程的同步和互斥機(jī)制,在?OpenMP?當(dāng)中主要有三種不同的線程之間的互斥方式。下面就來和大家來討論一下OpenMP當(dāng)中的互斥操作,需要的可以參考一下
    2023-01-01
  • 帶你了解C++中vector的用法

    帶你了解C++中vector的用法

    大家好,本篇文章主要講的是帶你了解C++中vector的用法,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • C++實(shí)現(xiàn)反轉(zhuǎn)鏈表的兩種方法

    C++實(shí)現(xiàn)反轉(zhuǎn)鏈表的兩種方法

    本文主要介紹了C++實(shí)現(xiàn)反轉(zhuǎn)鏈表的兩種方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • C++代碼和可執(zhí)行程序在x86和arm上的區(qū)別介紹

    C++代碼和可執(zhí)行程序在x86和arm上的區(qū)別介紹

    這篇文章主要介紹了C++代碼和可執(zhí)行程序在x86和arm上的區(qū)別,X86和ARM是占據(jù)CPU市場的兩大處理器,各有優(yōu)劣,本文給大家詳細(xì)介紹了兩者的區(qū)別,需要的朋友可以參考下
    2022-07-07
  • C++段錯誤(Segmentation fault)快速定位的解決方法

    C++段錯誤(Segmentation fault)快速定位的解決方法

    寫過C++的朋友都知道,有時候程序編譯通過,并不能代表程序就是對的,在linux下做開發(fā)時,經(jīng)常會遇到跑崩潰的情況,但是在終端只會報Segmentation fault,如果工程代碼量少,你還能重新debug一下慢慢找,本文給大家介紹了C++段錯誤的快速定位,需要的朋友可以參考下
    2024-07-07

最新評論

稻城县| 洮南市| 花垣县| 栾城县| 通榆县| 西贡区| 镇坪县| 芦山县| 柳河县| 天门市| 正蓝旗| 兰溪市| 阿图什市| 甘肃省| 山阴县| 嵊州市| 太仓市| 来安县| 南宁市| 玉门市| 三穗县| 陆川县| 交城县| 永安市| 韶山市| 张掖市| 洮南市| 辉县市| 金山区| 福安市| 神农架林区| 周宁县| 齐河县| 焦作市| 朝阳区| 大兴区| 宜丰县| 麦盖提县| 津南区| 宿松县| 阳山县|