kruskal是每次挑选最小的边,是一个边优先的算法,那么实现这个算法我们得先实现优先级队列
每次挑选最小的边,若边两端的点不在一个集合,就说明这是最小生成树的一条边
故我们还需要实现并查集
来看代码
图的定义:
class Edge;
class Node {
public:
int val;
int in;
int out;
vector<Node*> nexts;
vector<Edge*> edges;
Node(int v) :val(v), in(0), out(0) {}
};
class Edge {
public:
int weight;//该边或弧的权重
Node* from;//弧尾
Node* to;//弧头
Edge(int v):weight(v),from(NULL),to(NULL){}
};
class Graph {
public:
vector<Node*> Nodes;
vector<Edge*> edges;
};
并查集的实现:
template<class T>
class Element {
public:
T val;
Element(T v):val(v){}
};
template<class T>
class UnionFindSet {
private:
unordered_map<T, Element<T>*> elementMap;
unordered_map<Element<T>*, Element<T>*> fartherMap;
unordered_map<Element<T>*, int> sizeMap;
vector<Element<T>*> help;
public:
UnionFindSet(vector<T> num) {
for (T val : num) {
Element<T>* e = new Element<T>(val);
elementMap[val] = e;
fartherMap[e] = e;
sizeMap[e] = 1;
}
}
Element<T>* Findhead(Element<T>* e) {
while (e != fartherMap[e]) {
help.push_back(e);
e = fartherMap[e];
}
for (Element<T>* val : help) {
fartherMap[val] = e;
}
help.clear();
return e;
}
void Union(T v1,T v2){
Element<T>* aF = elementMap[v1];
Element<T>* bF = elementMap[v2];
if (aF != bF) {
Element<T>* small = sizeMap[aF] <= sizeMap[bF] ? aF : bF;
Element<T>* big = small == aF ? bF : aF;
fartherMap[small] = big;
sizeMap[big] = sizeMap[big] + sizeMap[small];
sizeMap.erase(small);
}
}
bool isSameSet(T v1, T v2) {
if (elementMap.count(v1) != 0 && elementMap.count(v2) != 0) {
return Findhead(elementMap[v1]) == Findhead(elementMap[v2]);
}
return false;
}
};
优先级队列的实现:
namespace comp {
template<class T>
class less {
public:
bool operator()(const T& o1,const T& o2) {
return o1 < o2;
}
};
template<class T>
class greator {
public:
bool operator()(const T& o1,const T& o2) {
return o1 > o2;
}
};
}
template<class T,class comparator = comp::less<T>>
class PriorQueue {
private:
T* heaparr;
int heapsize;
comparator com;
int maxsize;
public:
PriorQueue(int s){
heapsize = 0;
heaparr = new T[s];
maxsize = s;
}
void swap(int index1, int index2) {
T temp = heaparr[index1];
heaparr[index1] = heaparr[index2];
heaparr[index2] = temp;
}
void heapInsert(int index){
int parent = (index - 1) / 2;
while (com(heaparr[index], heaparr[parent])) {
swap(index, parent);
index = parent;
}
}
void heapify(int index) {
int child = index * 2 + 1;
while (child < heapsize) {
int m = child + 1 < heapsize && com(heaparr[child], heaparr[child + 1]) ? child : child + 1;
m = com(heaparr[index], heaparr[m]) ? index : m;
if (index == m) {
return;
}
swap(index, m);
index = m;
child = index * 2 + 1;
}
}
int size() {
return heapsize;
}
bool empty() {
return heapsize == 0;
}
bool push(T val) {
if (heapsize == maxsize) {
return false;
}
heaparr[heapsize] = val;
heapInsert(heapsize++);
return true;
}
T pop() {
if (heapsize == 0) {
abort();
}
T res = heaparr[0];
heaparr[0] = heaparr[--heapsize];
heapify(0);
return res;
}
};
最后是kruskal算法的实现:
vector<Edge*> Kruskal(Graph* G){
vector<Edge*> res;
PriorQueue<Edge*, com> p((int)G->edges.size());
UnionFindSet<Node*> unionSet(G->Nodes);
for (Edge* edge : G->edges) {
p.push(edge);
}
while (!p.empty()) {
Edge* edge = p.pop();
Node* from = edge->from;
Node* to = edge->to;
if (!unionSet.isSameSet(from, to)) {
res.push_back(edge);
unionSet.Union(from, to);
}
}
return res;
}
prim算法的实现:
vector<Edge*> Prim(Graph* G) {
vector<Edge*> res;
if (G == NULL) {
return res;
}
set<Node*> visited;
PriorQueue<Edge*, com> queue((int)G->edges.size());
for (Node* node : G->Nodes) {
if (visited.count(node) == 0) {
visited.insert(node);
for (Edge* edge : node->edges) {
queue.push(edge);
}
while (!queue.empty()) {
Edge* edge = queue.pop();
Node* to = edge->to;
if (visited.count(to) == 0) {
res.push_back(edge);
visited.insert(to);
for (Edge* next : to->edges) {
queue.push(next);
}
}
}
}
}
return res;
}