问题描述:图的动态连通性问题,要求能够添加连接,判断一对对象是否相连等
quick find
解决思路:若给出的两个对象连通,则使两者的ID值置为相同,判断是否连通时也只用判断值是否相同即可。
代码实现:
class quick_find
{
private:
int count;//The count of connected component
public:
//p_ID is a pointer to ID_array
//initialize the ID of p_ID
void init_id(int *p_ID, int n)
{
count = n;
int i;
for(i = 0; i < n; i++){
p_ID[i] = i;
}
}
//find the root of p_ID[i]
int find(int *p_ID, int i)
{
return p_ID[i];
}
//the function of connected
bool connected(int *p_ID, int x, int y)
{
if(find(p_ID, x) == find(p_ID, y))
return true;
else
return false;
}
//the function of union
void union_num(int *p_ID, int n, int x, int y)
{
int ID_x = find(p_ID, x);
int ID_y = find(p_ID, y);
if(connected(p_ID, x, y) == false)
{
for(int i = 0; i < n; i++)
{
if(p_ID[i] == ID_x)
{
p_ID[i] = ID_y;
}
}
count--;
}
}
//cout the cnt
void display()
{
cout << "Final count is " << count << endl;
}
};
检验一下:
int main()
{
int *p_ID;
quick_find f;
cout << "Please enter the count of numbers: (test_data is 10)"<<endl;
int n;
cin >> n;
p_ID = new int [n];
f.init_id(p_ID, n);
for(int i = 0; i < n; i++)
{
cout << p_ID[i] << " ";
}
cout << endl;
f.union_num(p_ID, n, 4, 3);
f.union_num(p_ID, n, 3, 8);
f.union_num(p_ID, n, 6, 5);
f.union_num(p_ID, n, 9, 4);
f.union_num(p_ID, n, 2, 1);
f.union_num(p_ID, n, 8, 9);
f.union_num(p_ID, n, 5, 0);
f.union_num(p_ID, n, 7, 2);
f.union_num(p_ID, n, 6, 1);
f.union_num(p_ID, n, 1, 0);
f.union_num(p_ID, n, 6, 7);
for(int i = 0; i < n; i++){
cout << p_ID[i] << " ";
}
cout << endl;
f.display();
system("pause");
return 0;
}
quick union
解决思路:由于在quick find中,每次连通时都要遍历整个数组修改它的值,这样是非常浪费时间的,为了提升速度,我们在连接时将其ID值设置为另一个元素,形成链接,在进行下一次连接时,寻找其链接的根再连起来,节省时间。
class quick_union
{
private:
int count;//the count of connected components
public:
//initialize the ID_array
void init_id(int *p_ID, int n)
{
count = n;
int i;
for(i = 0; i< n; i++)
{
p_ID[i] = i;
}
}
//find the root of num
int find(int *p_ID, int num)
{
while(p_ID[num] != num)
num = p_ID[num];//key point
return num;
}
//judge if two components are connected
bool connected(int *p_ID, int x, int y)
{
if(find(p_ID, x) == find(p_ID, y))
return true;
else
return false;
}
//connect two components
void union_id(int *p_ID, int x, int y)
{
int root_x;
int root_y;
root_x = find(p_ID, x);
root_y = find(p_ID, y);
if(connected(p_ID, x, y) == false)
{
p_ID[root_x] = root_y;
count--;
}
}
//cout the count of connected components
void display()
{
cout << "Final count is " << count << endl;
}
};
写主函数实现一下:
int main()
{
int *p_ID;
quick_union f;
cout << "Please enter the count of numbers: "<<endl;
int n;
cin >> n;
p_ID = new int [n];
f.init_id(p_ID, n);
for(int i = 0; i < n; i++)
{
cout << p_ID[i] << " ";
}
cout << endl;
f.union_id(p_ID, 4 ,3);
f.union_id(p_ID ,3, 8);
f.union_id(p_ID, 6, 5);
f.union_id(p_ID, 9, 4);
f.union_id(p_ID, 2 ,1);
f.union_id(p_ID ,8, 9);
f.union_id(p_ID, 5, 0);
f.union_id(p_ID, 7, 2);
f.union_id(p_ID, 6, 1);
f.union_id(p_ID, 1, 0);
f.union_id(p_ID, 6, 7);
for(int i = 0; i < n; i++){
cout << p_ID[i] << " ";
}
cout << endl;
f.display();
system("pause");
return 0;
}
union find
解决思路:这时出现了新的问题,quick union有一种很坏的情况,就是将一棵大树和小树相连时,若不经过判断,最后会形成一颗“变态”的树,因此引入加权算法,简单的添加一个size数组记录树中的节点数,一比较就知道哪个小比较好连啦。
class weighted_quick_union
{
private:
//size array is used to record the size of connected components
int *size;
//the count of connected components
int count;
public:
//initialize the ID_array and size array
void init(int *p_ID, int n)
{
count = n;
size = new int [n];
for (int i = 0; i < n; i++)
{
p_ID[i] = i;
size[i] = 1;
}
}
//find the root of numbers
int find(int *p_ID, int num)
{
while(p_ID[num] != num)
num = p_ID[num];//key point
return num;
}
//connect two numbers' root
void union_num(int *p_ID, int x, int y)
{
int root_x = find(p_ID, x);
int root_y = find(p_ID, y);
if(connected(p_ID, x, y) == false)
{
if(size[root_x] < size[root_y])
{
p_ID[root_x] = root_y;
size[root_y] += size[root_x];
}
else
{
p_ID[root_y] = root_x;
size[root_x] += size[root_y];
}
count = count - 1;
}
}
//judge two numbers
bool connected(int *p_ID, int x, int y)
{
int root_x = find(p_ID, x);
int root_y = find(p_ID, y);
if(root_x == root_y)
return true;
else
return false;
}
//cout the count of connected components
void display()
{
cout << count << endl;
}
};
实现一下:
int main()
{
int n;
int *p_ID;
weighted_quick_union f;
cout << "Please enter the count of the numbers: ";
cin >> n;
p_ID = new int [n];
f.init(p_ID, n);
for(int i = 0; i < n; i++)
{
cout << p_ID[i] << " ";
}
cout << endl;
f.union_num(p_ID, 4, 3);
f.union_num(p_ID, 3, 8);
f.union_num(p_ID, 6, 5);
f.union_num(p_ID, 9, 4);
f.union_num(p_ID, 2, 1);
f.union_num(p_ID, 5, 0);
f.union_num(p_ID, 7, 2);
f.union_num(p_ID, 6, 1);
for(int i =0; i < n; i++)
{
cout << p_ID[i] << " ";
}
cout << endl;
f.display();
system("pause");
return 0;
}