数据结构之并查集(Java版本)

/**
 * 数据结构学习之并查集之数组并查集
 * @author Sking
 */
package 并查集;

public class ArrayUnionFind {
	static int[] equivClass;//元素数组,有效索引从1开始
	static int n; //并查集大小

	/**
	 * 根据指定的数组初始容量初始化并查集
	 * @param numberOfElements 数组初始容量
	 */
	static void initialize(int numberOfElements) {
		n = numberOfElements;
		equivClass = new int[n + 1];
		//先单独成类,再通过Union算法不断合并
		for (int e = 1; e <= n; e++)
			equivClass[e] = e;
	}

	/**
	 * 将两指定“类”合并
	 * @param classA “类1”
	 * @param classB “类2”
	 */
	public static void union(int classA, int classB) {
		for (int k = 1; k <= n; k++)
			if (equivClass[k] == classB)
				equivClass[k] = classA;
	}
	
	
	/**
	 * 返回指定元素所属的”类“
	 * @param theElement 指定元素
	 * @return 指定元素的”类“
	 */
	public static int find(int theElement) {
		return equivClass[theElement];
	}

}


 

/**
 * 数据结构学习之并查集之链表并查集
 * @author Sking
 */
package 并查集;

public class LinkedListUnionFind {
	/**
	 * 链表并查集的节点类型
	 * @author Sking
	 */
	protected class EquivNode {
		/*
		  * node[e].equivClass既是find(e)返回的值,又是指向等价
		  * 类node[e].equivClass的链中的第一个结点的指针。
		  * node[e].size只有当e是链上的第一个结点时才被定义。表
		  * 示一个类中的结点个数。
		  */
		int equivClass;//类别标记
		int size;//类的节点个数
		int next;

		/**
		 * 指定类别和元素个数的构造函数
		 * @param theClass 类别
		 * @param theSize 元素个数
		 */
		EquivNode(int theClass, int theSize) {
			equivClass = theClass;
			size = theSize;
		}
	}
	
	private static EquivNode[] node;//节点数组
	private static int n;//并查集大小
	
	/**
	 * 初始化并查集
	 * @param numberOfElements 并查集容量
	 */
	public  void initialize(int numberOfElements) {
		n = numberOfElements;
		node = new EquivNode[n + 1];
		//初始化,单独成类,类的元素个数均为1
		for (int e = 1; e <= n; e++)
			node[e] = new EquivNode(e, 1);
	}
	/**
	 * 合并两个指定”类“
	 * @param classA ”类1“
	 * @param classB ”类2“
	 */
	public  static void union(int classA, int classB) {
		 //总是将具有较少元素的类链接到较多元素类对应的链中
		if (node[classA].size > node[classB].size) {
			int t = classA;
			classA = classB;
			classB = t;
		}
		int k;
		for (k = classA; node[k].next != 0; k = node[k].next)
			node[k].equivClass = classB;
		node[k].equivClass = classB;
		node[classB].size += node[classA].size;
		node[k].next = node[classB].next;
		node[classB].next = classA;
	}

	/**
	 * 查找指定元素所属的类
	 * @param theElement 指定元素
	 * @return 指定元素所属的类
	 */
	public static int find(int theElement) {
		return node[theElement].equivClass;
	}

}


 

/*
 * 用树结构实现并查集
 * 树节点含有两个域parent,root
 * parent域用于指示该元素所链接的父节点,根parent域为0.
 * root域用于指示这个类中的根,只有根结点的root为true。
 * 根结点对应的数组索被记为这个类的类标记。通过从待查询
 * 元素结点开始,沿着父链接走到根结点,则根结点的数组索引
 * 就是要返回的类标记。
 */
package 并查集;
/*
 * 并查集
 */
public class TreeUnionFind {
	private static class Node{
		int parent;
		boolean root;
		private Node(){
			parent=1;
			root=true;
		}
	}
	Node[] node;
	public TreeUnionFind(int n){
		node=new Node[n+1];
		for(int e=0;e<=n;e++)
			node[e]=new Node();
	}
	public int find(int e){
		while(!node[e].root)e=node[e].parent;
		return e;
	}
	//A,B表示已经存在的类标记
	public void union(int A,int B){
		node[A].parent+=node[B].parent;
		node[B].root=false;
		node[B].parent=A;
	}

}


 

/*
 * 改进的并查集,支持压缩路径
 */
package 并查集;
public class TreeUnionFind2 {
	private static class Node {
		int parent;
		boolean root;

		private Node() {
			parent = 1;
			root = true;
		}
	}

	Node[] node;

	public TreeUnionFind2(int n) {
		node = new Node[n + 1];
		for (int e = 0; e <= n; e++)
			node[e] = new Node();
	}
    /*在查找类别的同时进行路径压缩
     * 进行路径压缩可以减少查找的时间
     */
	public int find(int e) {
		int current = e, p, gp;
		if (node[current].root)
			return current;
		p = node[current].parent;
		if (node[p].root)
			return p;
		gp = node[p].parent;
		while (true) {
			node[current].parent = gp;
			if (node[gp].root)
				return gp;
			current = p;
			p = gp;
			gp = node[p].parent;
		}
	}

	public void union(int i, int j) {
		if (node[i].parent < node[j].parent) {
			node[j].parent += node[i].parent;
			node[i].root = false;
			node[i].parent = j;
		} else {
			node[i].parent += node[j].parent;
			node[j].root = false;
			node[j].parent = i;
		}
	}

}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值