Geeks Union-Find Algorithm Union By Rank and Path Compression 图环算法

同样是查找一个图是否有环的算法,但是这个算法很牛逼,构造树的时候可以达到O(lgn)时间效率。n代表顶点数

原因是根据需要缩减了树的高度,也叫压缩路径(Path compression),名字很高深,不过其实不难理解,简单来说就是每次查找一个节点的时候,都把这一路径中的所有节点都赋予根节点作为路径。


原文没指出的地方:

也因为需要压缩,所以初始化的时候注意,不能如前面简单实用Union Find的算法那样初始化所有顶点的父母节点为-1,应该是初始化所有节点的父母节点为本身(自己繁殖自己?),然后就方便递归的时候一律可以返回这个跟节点了。 

当然其实初始化为-1也是可以的,不过需要额外代码处理一下,也不难。


最后可以参考原文:http://www.geeksforgeeks.org/union-find-algorithm-set-2-union-by-rank/


#pragma once
#include <iostream>

class UnionFindUnionByRank
{
	struct Edge
	{
		int src, des;
	};

	struct Graph
	{
		int V, E;
		Edge *edges;
		Graph(int v, int e) : V(v), E(e)
		{
			edges = new Edge[e];
		}
		~Graph()
		{
			if (edges) delete [] edges;
		}
	};

	struct subSet
	{
		int parent, rank;
	};

	int find(subSet *subs, int i)
	{
		//因为要压缩,所以不能使用-1作为根的标志了
		if (subs[i].parent != i)
		{
			//Union by rank: attach smaller rank tree to high rank tree. It is so simple, but very hard to create it totally by ourself, so it's good to stand on the shoulder of the giant.
			subs[i].parent = find(subs, subs[i].parent);
		}
		return subs[i].parent;//因为如果-1作为根标志,那么这里就要返回i,就达不到压缩的效果了,而是应该返回parent,一层一层递归回上一层。
	}

	void unionTwo(subSet *subs, int x, int y)
	{
		int xroot = find(subs, x);
		int yroot = find(subs, y);

		if (subs[xroot].rank < subs[yroot].rank)
		{
			subs[xroot].parent = yroot;
		}
		else if (subs[xroot].rank > subs[yroot].rank)
		{
			subs[yroot].parent = xroot;
		}
		else
		{
			//only need to increment its rank when ther are equal rank
			subs[yroot].parent = xroot;
			subs[xroot].rank++;
		}
	}

	bool isCycle(Graph *gra)
	{
		subSet *subs = new subSet[gra->V];
		for (int i = 0; i < gra->V; i++)
		{
			subs[i].parent = i;//parent不能初始化为-1
			subs[i].rank = 0;
		}

		for (int e = 0; e < gra->E; e++)
		{
			int x = find(subs, gra->edges[e].src);
			int y = find(subs, gra->edges[e].des);

			if (x == y) return true;

			unionTwo(subs, x, y);
		}

		return false;
	}
public:
	UnionFindUnionByRank()
	{
		int V = 3, E = 3;
		struct Graph* graph = new Graph(V, E);

		// add edge 0-1
		graph->edges[0].src = 0;
		graph->edges[0].des = 1;

		// add edge 1-2
		graph->edges[1].src = 1;
		graph->edges[1].des = 2;

		// add edge 0-2
		graph->edges[2].src = 0;
		graph->edges[2].des = 2;

		if (isCycle(graph))
			printf( "Union By Rank found graph contains cycle \n" );
		else
			printf( "Union By Rank found graph doesn't contain cycle \n" );
	}
};



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值