目次
1. 概要
##2 つの一般的な実装アイデアがあります
ホームページ Java &#&チュートリアル Javaでのunion-findの分析例

Javaでのunion-findの分析例

Apr 27, 2023 pm 07:46 PM
java

1. 概要

Union-find: 結合されていないセットのマージやクエリの問題を解決するために使用されるツリー データ構造。例: n 個の村があり、2 つの村を接続する 2 つの村の間に接続道路があるかどうかをクエリします。

2 つのコア:

検索: 要素が配置されているセットを検索します

マージ (ユニオン): 2 つの要素のセットを 1 つのセットにマージします

##2. 実装

##2 つの一般的な実装アイデアがあります

#クイック検索

時間計算量の計算: O(1)
  • 和集合時間計算量: O(n)
  • Quick Union

Find の時間計算量: O(logn) O(a(n))a(n)
  • に最適化可能

    マージの時間計算量 (Union): O(logn) は O(a(n) )) a(n)
  • 配列を使用して次のように最適化できます。ツリー構造を実装します。配列の添え字が要素で、配列に格納されている値が親ノードの値です
  • 抽象クラスの作成 Union FindJavaでのunion-findの分析例

    public abstract class UnionFind {
     
    	 int[] parents;
    	/**
    	 * 初始化并查集
    	 * @param capacity
    	 */
    	public UnionFind(int capacity){
    		
    		if(capacity < 0) {
    			throw new IllegalArgumentException("capacity must be >=0");
    		}
            //初始时每一个元素父节点(根结点)是自己
    		parents = new int[capacity];
    		for(int i = 0; i < parents.length;i++) {
    			parents[i] = i;
    		}
    	}
    	
       /**
         *  检查v1 v2 是否属于同一个集合
         */
    	public boolean isSame(int v1,int v2) {
    		return find(v1) == find(v2);
    	}
     
        /**
         *  查找v所属的集合 (根节点)
         */
    	public  abstract int find(int v);
     
    	/**
         *  合并v1 v2 所属的集合
         */
    	public abstract void union(int v1, int v2);
    	
    		
    	// 范围检查
    	public   void rangeCheck(int v)  {
    		if(v<0 || v > parents.length)
    			throw new IllegalArgumentException("v is out of capacity");
    	}
    }
    ログイン後にコピー

    2.1 クイック検索の実装

    クイック検索を使用してユニオン検索を実装すると、ツリーの最大高さは 2 になり、各ノードの高さは になります。親ノードはルート ノードです。

    public class UnionFind_QF extends UnionFind {
    	public UnionFind_QF(int capacity) {
    		super(capacity);
    		
    	}
     
      // 查
    @Override
    	public  int  find(int v) {
    		rangeCheck(v);
    		return parents[v];
    	}
     
     // 并 将v1所在集合并到v2所在集合上
    @Override
    public void union(int v1, int v2) {
        // 查找v1 v2 的父(根)节点
    	int p1= find(v1);
    	int p2 = find(v2);
    	if(p1 == p2) return;
      
        //将所有以v1的根节点为根节点的元素全部并到v2所在集合上 即父节点改为v2的父节点
    	for(int i = 0; i< parents.length; i++) {
    		if(parents[i] == p1) {
    			parents[i] = p2;
    		}
    	}
    	
      }
    }
    ログイン後にコピー

    2.2 迅速なユニオンの実装Javaでのunion-findの分析例

    public class UnionFind_QU extends UnionFind {
     
    	public UnionFind_QU(int capacity) {
    		super(capacity);
    		
    	}
     
    	//查某一个元素的根节点
    	@Override
    	public int find(int v) {
       //检查下标是否越界
    		rangeCheck(v);
       
      // 一直循环查找节点的根节点
    		while (v != parents[v]) {
    			v = parents[v];
    		}
    		return v;
    	}
     
    //V1 并到 v2 中
    	@Override
    	public void union(int v1, int v2) {
    	
    		int p1 = find(v1);
    		int p2 = find(v2);
    		if(p1 == p2) return;
          //将v1 根节点 的 父节点 修改为 v2的根结点 完成合并
    		parents[p1] = p2;
    	}
    }
    ログイン後にコピー

    3. 最適化Javaでのunion-findの分析例

    ユニオン検索は高速ユニオンによって実装されることが多いですが、高速です。ユニオンはツリーの不均衡を引き起こすことがあります。

    最適化のアイデアには 2 つあります: ランクの最適化とサイズの最適化 Javaでのunion-findの分析例

    3.1 サイズベースの最適化

    コアアイデア: 少数の要素を含むツリーが多数の要素を含むツリーに接ぎ木される

    public class UniondFind_QU_S extends UnionFind{
     
       // 创建sizes 数组记录 以元素(下标)为根结点的元素(节点)个数
    	private int[] sizes;
     
    	public UniondFind_QU_S(int capacity) {
    		super(capacity);
     
    		sizes = new int[capacity];
     
       //初始都为 1
    		for(int i = 0;i < sizes.length;i++) {
    			sizes[i] = 1;
    			}
    		
    	}
     
    	@Override
    	public int find(int v) {
     
    		rangeCheck(v);
     
    		while (v != parents[v]) {
    			v = parents[v];
    		}
    		return v;
    	}
     
    	@Override
    	public void union(int v1, int v2) {
    	
    		int p1 = find(v1);
    		int p2 = find(v2);
    		if(p1 == p2) return;
     
    		//如果以p1为根结点的元素个数 小于 以p2为根结点的元素个数 p1并到p2上,并且更新p2为根结点的元素个数
    	if(sizes[p1] < sizes[p2]) {
    		    parents[p1] = p2;
    		    sizes[p2] += sizes[p1];
    		
     // 反之 则p2 并到 p1 上,更新p1为根结点的元素个数
    	}else {
    			parents[p2] = p1;
    			sizes[p1] += sizes[p2];
    		}
    	}
    }
    ログイン後にコピー

    サイズベースの最適化はツリーの不均衡にもつながる可能性がある

    3.2 ランクの最適化に基づく

    コアアイデア: 背の低い木を高い木に接ぎ木する

    public class UnionFind_QU_R extends UnionFind_QU {
       // 创建rank数组  ranks[i] 代表以i为根节点的树的高度
     private int[] ranks;
     
    	public UnionFind_QU_R(int capacity) {
    		super(capacity);
     
    		ranks = new int[capacity];
     
    		for(int i = 0;i < ranks.length;i++) {
    			ranks[i] = 1;
    		}
     
    	}
        
    	public void union(int v1, int v2) {
     
    		int p1 = find(v1);
    		int p2 = find(v2);
    		if(p1 == p2) return;
        
        // p1 并到 p2 上 p2为根 树的高度不变
    		if(ranks[p1] < ranks[p2]) {
    			parents[p1] = p2;
    			
      // p2 并到 p1 上 p1为根 树的高度不变
    		} else if(ranks[p1] > ranks[p2]) {
    			parents[p2] = p1;
     
    		}else {
        // 高度相同 p1 并到 p2上,p2为根 树的高度+1
    			parents[p1] = p2;
    			ranks[p2] += 1;
    		}
    	}
    }
    ログイン後にコピー

    ランクの最適化に基づいて、ユニオンの数が増加するにつれて、ツリーの高さはますます高くなり、結果として動作が遅くなります

    最適化を続けるには、パスの圧縮、パスの分割、およびパスの半分化という 3 つのアイデアがあります。

    3.2.1 パスの圧縮 (パスの圧縮)

    すべてのノードを検索するときに使用します。ルート ノードへのパスがポイントされるため、ツリーの高さが減ります。

    /**
     *  Quick Union -基于rank的优化  -路径压缩
     *
     */
    public class UnionFind_QU_R_PC extends UnionFind_QU_R {
     
    	public UnionFind_QU_R_PC(int capacity) {
    		super(capacity);
    		
    	}
     
    	@Override
    	public int find(int v) {
    		rangeCheck(v);
     
    		if(parents[v] != v) {
     
            //递归 使得从当前v 到根节点 之间的 所有节点的 父节点都改为根节点
    			parents[v] = find(parents[v]);
    		}
    		return parents[v];
    	}
    }
    ログイン後にコピー

    ツリーの高さは減らすことができますが、実装コストが若干高くなります Javaでのunion-findの分析例

    3.2 .2 パスの分割

    パス上のすべてのノードがその親ノードを指すようにします

    /**
     *  Quick Union -基于rank的优化  -路径分裂
     *
     */
    public class UnionFind_QU_R_PS extends UnionFind_QU_R {
     
    	public UnionFind_QU_R_PS(int capacity) {
    		super(capacity);
    		
    	}
     
    	@Override
    	public int find(int v) {
    		rangeCheck(v);
    		while(v != parents[v]) {
     
    			int p = parents[v];
    			parents[v] = parents[parents[v]];
    			v = p;
    		}
    		return v;
    	}
    }
    ログイン後にコピー

    3.2.3 パスを半分にします (パスの半分化) Javaでのunion-findの分析例

    パス上の他のすべてのノードがその親ノードを指すようにします。

    /**
     *  Quick Union -基于rank的优化  -路径减半
     *
     */
    public class UnionFind_QU_R_PH extends UnionFind_QU_R {
     
    	public UnionFind_QU_R_PH(int capacity) {
    		super(capacity);
    		
    	}
    	
    	
        public int find(int v) {
        	rangeCheck(v);
     
    		while(v != parents[v]) {
    			parents[v] = parents[parents[v]];
    			v = parents[v];
    		}
    		return v;
    	}	 
     }
    ログイン後にコピー

    クイック ユニオンを使用して、ランクに基づいてパスの分割またはパスの半分化を最適化しますJavaでのunion-findの分析例

    各操作の償却時間計算量が O(a(n)), a(n) であることが保証できます。

    以上がJavaでのunion-findの分析例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

    ホットAIツール

    Undresser.AI Undress

    Undresser.AI Undress

    リアルなヌード写真を作成する AI 搭載アプリ

    AI Clothes Remover

    AI Clothes Remover

    写真から衣服を削除するオンライン AI ツール。

    Undress AI Tool

    Undress AI Tool

    脱衣画像を無料で

    Clothoff.io

    Clothoff.io

    AI衣類リムーバー

    AI Hentai Generator

    AI Hentai Generator

    AIヘンタイを無料で生成します。

    ホットツール

    メモ帳++7.3.1

    メモ帳++7.3.1

    使いやすく無料のコードエディター

    SublimeText3 中国語版

    SublimeText3 中国語版

    中国語版、とても使いやすい

    ゼンドスタジオ 13.0.1

    ゼンドスタジオ 13.0.1

    強力な PHP 統合開発環境

    ドリームウィーバー CS6

    ドリームウィーバー CS6

    ビジュアル Web 開発ツール

    SublimeText3 Mac版

    SublimeText3 Mac版

    神レベルのコード編集ソフト(SublimeText3)

    Javaの平方根 Javaの平方根 Aug 30, 2024 pm 04:26 PM

    Java の平方根のガイド。ここでは、Java で平方根がどのように機能するかを、例とそのコード実装をそれぞれ示して説明します。

    Javaの完全数 Javaの完全数 Aug 30, 2024 pm 04:28 PM

    Java における完全数のガイド。ここでは、定義、Java で完全数を確認する方法、コード実装の例について説明します。

    Java の乱数ジェネレーター Java の乱数ジェネレーター Aug 30, 2024 pm 04:27 PM

    Java の乱数ジェネレーターのガイド。ここでは、Java の関数について例を挙げて説明し、2 つの異なるジェネレーターについて例を挙げて説明します。

    ジャワのウェカ ジャワのウェカ Aug 30, 2024 pm 04:28 PM

    Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

    Javaのアームストロング数 Javaのアームストロング数 Aug 30, 2024 pm 04:26 PM

    Java のアームストロング番号に関するガイド。ここでは、Java でのアームストロング数の概要とコードの一部について説明します。

    Javaのスミス番号 Javaのスミス番号 Aug 30, 2024 pm 04:28 PM

    Java のスミス番号のガイド。ここでは定義、Java でスミス番号を確認する方法について説明します。コード実装の例。

    Java Springのインタビューの質問 Java Springのインタビューの質問 Aug 30, 2024 pm 04:29 PM

    この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

    Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

    Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

    See all articles