1.判断环:
参考博客
思路:
1.将用过的路径连起来成为一个集合,记录下来
2. 如果连通的两个边属于一个集合,那么这个并查集就形成了一个环
灯神参考视频
灯神代码:
如果删除2,4边
#include <cstdio>
#include <algorithm>
using namespace std;
#define VERTICES 6
void initialise(int parent[]){
int i;
for(i=0; i<VERTICES; i++){
parent[i] = -1;
}
}
int find_root(int x,int parent[]){
int x_root = x;
while(parent[x_root] != -1){
x_root = parent[x_root];
}
return x_root;
}
/* 1-union successfully,0-failed*/
int union_vertices(int x,int y,int parent[]){
int x_root = find_root(x,parent);
int y_root = find_root(y,parent);
if(x_root == y_root){
return 0;
}
else{
parent[x_root] = y_root;
return 1;
}
}
int main(){
int parent[VERTICES] = {0};
int edges[6][2] = {
{0,1},{1,2},{1,3},{2,4},{3,4},{2,5}// 可将2,4这条边删除测试代码是否正确 如果删除此边则不会出现环记得将6改为5
};
initialise(parent);
for(int i=0; i<6; i++){//循环条件如果删除边的话 需要将6改为5 因为删除掉了一个边
int x = edges[i][0];
int y = edges[i][1];
if(union_vertices(x, y, parent) == 0){
printf("Cycle detected!\n");
exit(0);
}
}
printf("No cycle found.\n");
return 0;
}
2.带秩优化:
代码实现:
用ranks [n]数组代表该父节点的秩也就是树高度
if(ranks[end] > ranks[start])
{
pre[start] = end;//将树高小的连接在树高大的树上
}
else if(ranks[end] < ranks[start])
{
pre[end] = start;
}
else
{
pre[start] = end;
ranks[end]++;
}
路径压缩:
为了进一步减短查找路径,可以使查找路径中的每一个节点都指向根结点,这就是路径压缩。
参考博客
代码实现:
//下面是采用递归路径压缩的方法查找元素,但是,递归压缩路径可能会造成溢出栈,会发生RE
int find(int x)
{
if(x == pre[x]) return x;
else return pre[x] = find(pre[x]);//在寻找根节点的时候开个数组记录根节点 使每一个子节点都指向根节点从 x结点搜索到祖先结点所经过的结点都指向该祖先结点
}
//下面我们说一下非递归方式进行的路径压缩:
int find(int x)
{
int k, j, r;
r = x;
while(r != parent[r]) //查找跟节点
r = parent[r]; //找到跟节点,用r记录下
k = x;
while(k != r) //非递归路径压缩操作
{
j = parent[k]; //用j暂存parent[k]的父节点
parent[k] = r; //parent[x]指向跟节点
k = j; //k移到父节点
}
return r; //返回根节点的值
}