查并集
查并集算法用于查找一个有向图是否有环
具体解释见一灯大神
主要的思想是:
两个函数:
- find根节点
- 合并某两个节点
输入一个图,建立一个vector parent, vector rank
遍历这个图,对他的边进行遍历,对与某边的两个节点找其1.根节点,2.合并某两个节点
如果合并两个节点返回0,说明他们有公共根节点,同时这两个节点又是连接的,此时图有环
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <iostream>
using namespace std;
#define VERTICES 6
void initialise(vector<int> &parent, vector<int> &rank)
{
int i;
for (i = 0; i < VERTICES; i++)
{
parent[i] = -1;
rank[i] = 0;
}
}
// 找x的根节点
int find_root(int x, const vector<int> &parent)
{
int x_root = x;
while (parent[x_root] != -1)
{
x_root = parent[x_root];
}
return x_root;
}
// 1-union successfully, 0-faled
int union_vertices(int x, int y, vector<int> &parent, vector<int> &rank)
{
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;
if (rank[x_root] > rank[y_root])
{
parent[y_root] = x_root;
}
else if (rank[y_root] > rank[x_root])
{
parent[x_root] = y_root;
}
else if (rank[y_root] == rank[x_root])
{
parent[x_root] = y_root;
rank[y_root]++;
}
return 1;
}
}
int main()
{
vector<int> parent(VERTICES, 0);
vector<int> rank(VERTICES, 0); // 记录节点的高度,在合并节点的时候,节点多的作为父树
int edges[6][2] = {
{0, 1}, {1, 2}, {1, 3}, {2, 4}, {3, 4}, {2, 5}};
initialise(parent, rank);
int i;
for (i = 0; i < 6; i++)
{
int x = edges[i][0];
int y = edges[i][1];
if (union_vertices(x, y, parent, rank) == 0)
{
cout << "Cycle detected!" << endl;
}
}
cout << "No cycles found." << endl;
return 0;
}
具体应用到:
主要思路:
把二维矩阵三位同学的关联关系画成三个节点的形式,如果两个节点相连的话,将两个节点所在的树连接起来:
1.找节点A、B的根节点 find_root
若a_root==b_root,说明有环,不用合并了
否则需要合并,那么两个分量合二为一,则总的连通分量要减1
2. 连接两个节点的根节点union_vertices
class Solution {
public:
int findCircleNum(vector<vector<int>>& M) {
int size=M.size();
initialise(size);
for(int i=0;i<size;i++){
for(int j=0; j<i;j++){
if(M.at(i).at(j)==1){
union_vertices(i,j);
}
}
}
return count;
}
void initialise(int size){
parent.clear();
rank.clear();
parent.reserve(size);
rank.reserve(size);
for(int i=0;i<size;i++){
parent.push_back(-1);
rank.push_back(0);
}
count=size;
}
int find_root(int x){
int x_root=x;
while(parent[x_root]!=-1){
x_root=parent[x_root];
}
return x_root;
}
void union_vertices(int x, int y){
int x_root = find_root(x);
int y_root=find_root(y);
if(x_root==y_root){
return;
}
else
{
// 不能直接赋值,应该是小树的父节点是大树
// 将两棵树合并为一棵
//parent[x_root] = y_root;
if (rank[x_root] > rank[y_root])
{
parent[y_root] = x_root;
}
else if (rank[y_root] > rank[x_root])
{
parent[x_root] = y_root;
}
else if (rank[y_root] == rank[x_root])
{
parent[x_root] = y_root;
rank[y_root]++;
}
// 两个分量合二为一
count--;
return;
}
}
private:
vector<int> parent;
vector<int> rank;
int count;
};