Skip to content

Commit

Permalink
并查集
Browse files Browse the repository at this point in the history
  • Loading branch information
kvenLin committed Nov 20, 2018
1 parent 5610ba4 commit afd770a
Show file tree
Hide file tree
Showing 13 changed files with 455 additions and 1 deletion.
1 change: 1 addition & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ Set\<E>
* 完全二叉树: 把元素顺序排列成树的形状
* 区别于满二叉树:满二叉树是有多少层就确定了有多少个节点
* 最大堆: 根节点值大于等于其所有子节点的值
* 最小堆: 与最大堆相反,根节点小于等于其所有字节点的值
* 最小堆: 与最大堆相反,根节点小于等于其所有子节点的值
* 注意: **层次低的节点的值不一定大于层次高的节点的值**,所以节点大小与层次无关

![二叉堆性质](https://raw.githubusercontent.com/kvenLin/Data-Structure/master/images/选区_044.png)
Expand Down Expand Up @@ -380,6 +380,30 @@ Set\<E>
* [LeetCode-211题,添加与搜索单词-数据结构设计](https://github.com/kvenLin/Data-Structure/tree/master/211-LeetCode/src/WordDictionary.java)
* [LeetCode-677题,Trie实现键值映射](https://github.com/kvenLin/Data-Structure/tree/master/677-LeetCode/src/MapSum.java)

## 并查集 Union Find
### 主要接口实现
* 对于一组数据,主要支持两个动作:
* union(p,q) , 将这两个数据和这两个数据的集合连接起来
* isConnected(p,q) , 查询这两个数据是否属于同一个集合 ----> find(p) == find(q)
#### 并查集实现
* [Quick Find 数组结构实现并查集](https://github.com/kvenLin/Data-Structure/tree/master/UnionFind/src/UnionFind1.java)
* [Quick Union 树结构实现并查集](https://github.com/kvenLin/Data-Structure/tree/master/UnionFind/src/UnionFind2.java)
* [并查集基于size的优化,即元素少的向元素多的合并](https://github.com/kvenLin/Data-Structure/tree/master/UnionFind/src/UnionFind3.java)
* [并查集基于rank的优化,即深度低的向深度高的合并](https://github.com/kvenLin/Data-Structure/tree/master/UnionFind/src/UnionFind4.java)
* [并查集基于路径压缩的优化,即降低树的高度](https://github.com/kvenLin/Data-Structure/tree/master/UnionFind/src/UnionFind5.java)
* [并查集路径压缩,使用递归压缩至一层](https://github.com/kvenLin/Data-Structure/tree/master/UnionFind/src/UnionFind6.java)

并查集实现:

![并查集的图示](https://raw.githubusercontent.com/kvenLin/Data-Structure/master/images/选区_054.png)

路径压缩:

![并查集路径压缩的图示](https://raw.githubusercontent.com/kvenLin/Data-Structure/master/images/选区_055.png)


### 解决连接问题
* 网络中节点间的连接状态
* 网络是一个抽象的概念: 用户之间形成的网络


11 changes: 11 additions & 0 deletions UnionFind/UnionFind.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
50 changes: 50 additions & 0 deletions UnionFind/src/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import java.util.Random;

public class Main {

/**
* 测试并查集
* @param uf
* @param m
* @return
*/
private static double testUF(UF uf, int m){
int size = uf.getSize();
Random random = new Random();
long startTime = System.nanoTime();
for (int i = 0; i < m; i++) {
int a = random.nextInt(size);
int b = random.nextInt(size);
uf.unionElements(a,b);
}
for (int i = 0; i < m; i++) {
int a = random.nextInt(size);
int b = random.nextInt(size);
uf.isConnected(a,b);
}

long endTime = System.nanoTime();
return (endTime - startTime) / 1000000000.0;
}

public static void main(String[] args) {
//设置并查集的大小为10000
int size = 10000000;
//设置对并查集的操作为10000
int m = 10000000;
// double time1 = testUF(new UnionFind1(size), m);
// double time2 = testUF(new UnionFind2(size), m);
double time3 = testUF(new UnionFind3(size), m);
double time4 = testUF(new UnionFind4(size), m);
double time5 = testUF(new UnionFind5(size), m);
double time6 = testUF(new UnionFind6(size), m);


// System.out.println("UF1 need time :" + time1 + "s");
// System.out.println("UF2 need time :" + time2 + "s");
System.out.println("UF3 need time :" + time3 + "s");
System.out.println("UF3 need time :" + time4 + "s");
System.out.println("UF3 need time :" + time5 + "s");
System.out.println("UF3 need time :" + time6 + "s");
}
}
5 changes: 5 additions & 0 deletions UnionFind/src/UF.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
public interface UF {
int getSize();
boolean isConnected(int p, int q);
void unionElements(int p, int q);
}
51 changes: 51 additions & 0 deletions UnionFind/src/UnionFind1.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
public class UnionFind1 implements UF {

private int[] id;

public UnionFind1(int size){
id = new int[size];
for (int i = 0; i < id.length; i++) {
id[i] = i;
}
}

@Override
public int getSize() {
return id.length;
}

@Override
public boolean isConnected(int p, int q) {
if (find(p) == find(q)){
return true;
}
return false;
}

/**
* 合并元素p和元素q的集合
* @param p
* @param q
*/
@Override
public void unionElements(int p, int q) {
int pID = find(p);
int qID = find(q);
if (pID == qID){
return;
}
for (int i = 0; i < id.length; i++) {
if (id[i] == pID){
id[i] = qID;
}
}
}

//查询元素p对应的集合的编号
private int find(int p){
if (p < 0 || p > id.length){
throw new IllegalArgumentException("p is out of bound.");
}
return id[p];
}
}
53 changes: 53 additions & 0 deletions UnionFind/src/UnionFind2.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
public class UnionFind2 implements UF {
private int[] parent;


public UnionFind2(int size){
parent = new int[size];
for (int i = 0; i < size; i++) {
parent[i] = i;
}
}

@Override
public int getSize() {
return parent.length;
}

/**
* 查找过程,查找元素p所对应的集合编号即根节点
* O(h)复杂度,h为树的高度
* @param p
* @return
*/
private int find(int p){
if (p < 0 || p > parent.length){
throw new IllegalArgumentException("p is out of bound");
}
while (p != parent[p]){
p = parent[p];
}
return p;
}

@Override
public boolean isConnected(int p, int q) {
return find(p) == find(q);
}

/**
* 合并元素p和元素q所属的集合
* O(h)复杂度,h为树的高度
* @param p
* @param q
*/
@Override
public void unionElements(int p, int q) {
int pRoot = find(p);
int qRoot = find(q);
if (qRoot == pRoot){
return;
}
parent[pRoot] = parent[qRoot];
}
}
64 changes: 64 additions & 0 deletions UnionFind/src/UnionFind3.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
public class UnionFind3 implements UF {
private int[] parent;
private int[] sz;// sz[i] 表示以i为根的集合中元素的个数

public UnionFind3(int size){
parent = new int[size];
sz = new int[size];
for (int i = 0; i < size; i++) {
parent[i] = i;
//初始化时每个每个节点只有一个元素
sz[i] = 1;
}
}

@Override
public int getSize() {
return parent.length;
}

/**
* 查找过程,查找元素p所对应的集合编号即根节点
* O(h)复杂度,h为树的高度
* @param p
* @return
*/
private int find(int p){
if (p < 0 || p > parent.length){
throw new IllegalArgumentException("p is out of bound");
}
while (p != parent[p]){
p = parent[p];
}
return p;
}

@Override
public boolean isConnected(int p, int q) {
return find(p) == find(q);
}

/**
* 合并元素p和元素q所属的集合
* O(h)复杂度,h为树的高度
* @param p
* @param q
*/
@Override
public void unionElements(int p, int q) {
int pRoot = find(p);
int qRoot = find(q);
if (qRoot == pRoot){
return;
}
//让元素个数比较少的根节点去指向元素个数比较多的根节点
if (sz[pRoot] < sz[qRoot]){
parent[pRoot] = qRoot;
//更新一下qRoot这棵数的元素个数的值
sz[qRoot] += sz[pRoot];
}else {
parent[qRoot] = pRoot;
sz[pRoot] += sz[qRoot];
}
}
}
64 changes: 64 additions & 0 deletions UnionFind/src/UnionFind4.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
public class UnionFind4 implements UF {
private int[] parent;
private int[] rank;// rank[i] 表示以i为根的集合中元素的个数

public UnionFind4(int size){
parent = new int[size];
rank = new int[size];
for (int i = 0; i < size; i++) {
parent[i] = i;
//初始化时每个每个节点只有一个元素
rank[i] = 1;
}
}

@Override
public int getSize() {
return parent.length;
}

/**
* 查找过程,查找元素p所对应的集合编号即根节点
* O(h)复杂度,h为树的高度
* @param p
* @return
*/
private int find(int p){
if (p < 0 || p > parent.length){
throw new IllegalArgumentException("p is out of bound");
}
while (p != parent[p]){
p = parent[p];
}
return p;
}

@Override
public boolean isConnected(int p, int q) {
return find(p) == find(q);
}

/**
* 合并元素p和元素q所属的集合
* O(h)复杂度,h为树的高度
* @param p
* @param q
*/
@Override
public void unionElements(int p, int q) {
int pRoot = find(p);
int qRoot = find(q);
if (qRoot == pRoot){
return;
}
//让元素个数比较少的根节点去指向元素个数比较多的根节点
if (rank[pRoot] < rank[qRoot]){
parent[pRoot] = qRoot;
}else if (rank[pRoot] < rank[qRoot]){
parent[qRoot] = pRoot;
}else {
parent[qRoot] = pRoot;
rank[pRoot] += 1;
}
}
}
Loading

0 comments on commit afd770a

Please sign in to comment.