1、并查集(动态连通问题适用)
时间复杂度为N^2的算法:
#include"Class.h"
const int N = 10;
int main()
{
Class c(N);
int p, q;
for (int i = 0;i < N;++i)
{
cin >> p >> q;
if (c.connect(p, q))continue;
c.Union(p, q);
}
c.printff();
cin.get();
cin.get();
return 0;
}
#pragma once
#include<iostream>
using namespace std;
class Class
{
int count;
int size;
int* id;
public:
Class(int N);
bool connect(int p, int q);
void printff();
~Class() { delete[] id; };
private:
int find(int p);
void Union(int p, int q);
};
#include "Class.h"
Class::Class(int N)
{
id = new int[N];
size = N;
count = N;
for (int i = 0;i < N;++i)
id[i] = i;
}
int Class::find(int p)
{
return id[p];
}
void Class::Union(int p, int q)
{
int P = find(p);
int Q = find(q);
if (P == Q)return;
for (int i = 0;i < size;++i)
{
if (id[i] == P)
{
id[i] = Q;
}
}
count--;
}
bool Class::connect(int p, int q)
{
return id[p] == id[q];
}
void Class::printff()
{
for (int i = 0;i < size;++i)
cout << id[i] << " ";
cout <<"\n"<< count;
}
上述并查集算法的时间复杂度为平方级别的,处理数据较为多时,时间消耗较多,所以经过优化后的代码如下:
quick-union:
#include "Class.h"
Class::Class(int N)
{
id = new int[N];
size = N;
count = N;
for (int i = 0;i < N;++i)
id[i] = i;
}
int Class::find(int p)
{
while (p != id[p])p = id[p];
return p;
}
void Class::Union(int p, int q)
{
int P = find(p);
int Q = find(q);
if (P == Q)return;
id[P] = Q;
count--;
}
bool Class::connect(int p, int q)
{
return id[p] == id[q];
}
void Class::printff()
{
for (int i = 0;i < size;++i)
cout << id[i] << " ";
cout <<"\n"<< count;
}
加权quick-union:
#include "Class.h"
Class::Class(int N)
{
id = new int[N];
node_num = new int[N];
size = N;
count = N;
for (int i = 0;i < N;++i)
{
id[i] = i;
node_num[i] = 1;
}
}
int Class::find(int p)
{
while (p != id[p])p = id[p];
return p;
}
void Class::Union(int p, int q)
{
int P = find(p);
int Q = find(q);
if (P == Q)return;
if (node_num[P] < node_num[Q]) { id[P] = Q;node_num[Q] += node_num[P]; }
else { id[Q] = P;node_num[P] += node_num[Q]; };
count--;
}
bool Class::connect(int p, int q)
{
return id[p] == id[q];
}
void Class::printff()
{
for (int i = 0;i < size;++i)
cout << id[i] << " ";
cout <<"\n"<< count;
}
最优化的算法是将树扁平化处理,即在 find方法中添加一个循环,将经过的路径全部直接链接到根节点,称为路径压缩的加权quick-union算法,但是并非所有操作都能在常数时间内完成,最坏的情况可能不是常数级别的!其它的几种优化算法一概如此!在用例比较明确的情况下,大部分时间复杂度为常数级别;