并查集-树状结构
思想:用集合中的一个元素代表集合
操作
- 合并(Union): 把两个不相交的集合合并为一个集合
- 查询: 查询两个元素是否在同一个集合中
冗余连接
分析:如果两个节点有相同的根,则连接这两个节点会导致环的出现,所以我们必须删除这条边。
class Solution {
public int[] findRedundantConnection(int[][] edges) {
int[] pre = new int[edges.length * 2 + 1];
Arrays.fill(pre, -1); //初始化所有的为单独的根节点
int[] res = {-1, -1};
for(int i = 0; i < edges.length; i++){
//每进来一条边,就查找这两个节点的根节点,如果是一样的,那就不能要这对边,否则就增加这对边
int u = edges[i][0];
int v = edges[i][1];
int x = find(u, pre);
int y = find(v, pre);
//不同的话进行合并操作
if(x != y){
pre[y] = x;
}
else{//表示这条边有相同的根节点,如果保留下来的话,就会出现环,所以要去掉这条边。
return edges[i];
}
}
return res;
}
public int find(int v, int[] pre){
while(pre[v] != -1){
v = pre[v];
}
return v;
}
}
最小生成树问题
Kruskal
最小生成树:就是一个图的极小连通子图,它包含原图的所有顶点,并且所有的边的权值之和尽可能小。图中的最小生成树也不是唯一的,同一个图有可能对应多个最小生成树。
存储方式:数组即可, 存储父节点的下标。
采用并查集的思想,多了一个对边进行排序的过程。
- 新建图G, G中拥有原图中相同的节点,但是没有边
- 将原图中所有边按照权值从小到达排序
- 从权值最小的边开始,如果这条边连接的两个节点不在一个连通分量里(也就是不形成环),则添加这条边到图G中
- 重复3, 直到图G中所有的节点都在同一个连通分量中。
0 | 1 | 2 | 3 | 4 |
-1 | -1 | -1 | -1 | -1 |
找到权值最小的边(2,4), 不在同一连通分量中,将4的父节点置为2 2 | ||||
找到权值最小的边(0,2), 不在同一连通分量中,将2的父节点置为0 | ||||
找到权值最小的边(0,1), 不在同一连通分量中,将1的父节点置为0 | ||||
找到权值最小的边(1,3), 不在同一连通分量中,将3的父节点置为1 | ||||
-1 | 0 | 0 | 1 | 2 |
Prim算法
以图的顶点为基础
- 从一个初始顶点开始,寻找触达其他顶点权值最小的边,并把该顶点加入到已触达顶点的集合中。
- 当全部顶点都加入到集合时,算法的工作就完成了。
- Prim算法的本质。是基于贪心算法
- V表示节点集合,E表示边集合
- V1表示最小生成树所包含的节点,V2表示未包含节点
- 初始时V1为空,V2=V
- 当V2为空,V1=V时算法结束
- 随机选择一个节点v加入到V1,并从V2中删除v
- 选择边权最小的<u,v>,其中 将v从V2移动到V1
- 重复2步骤直到V2为空。