模仿算法导论P366 和 P 367 简单实现的一个Kruskal算法和prim算法。
图的模型使用的是无向图,仅标注两点和之间的权重,prim算法处理起来还是邻接矩阵方便。
Kruskal算法的基本原理:利用贪心思想,依次选择权重最小的边插入不相交集合中,不是一个森林的则合并,可得最小生成树。
时间复杂度:O(ElgV) E:边的数量 V:节点数量 使用的数据结构 ‘不相交集合‘在P329页。
P368 prim算法的简单实现:
prim算法:同样利用贪心思想,集合A中保存最小生成树的点。 每次寻找除集合A外的结点且和集合A中某个点相连的轻量边,加入A。
时间复杂度: 利用二叉最小优先队列,同上。
代码过程:
1.建立一个包含自身节点变量、父节点变量、父节点和自己之间的权重的结构。
2.选择首节点,令其结构中权重为0,父节点为空,值为自己的节点变量。
其他节点的父节点为空,值为自己的节点变量,权重为无穷大。
3.针对权重建立起始最小堆。
3.循环这个队列:首先取出堆顶,然后找这个堆顶节点的邻接点,邻接点若不在A中在堆中且权重大于堆顶结点到它的权重,修改该节点的权重和父亲,重新建造堆。 往复循环。
4.输出结果。
Kruskal:
#include <bits/stdc++.h>
//#include <unordered_map>
using namespace std;
class solution
{
typedef struct treeset
{
char key;
int rank;
treeset* parent;
treeset (char x):key(x),rank(0), parent(NULL){};
}treeset;
treeset* make_set (char x)
{
treeset* ts = new treeset (x);
ts->parent = ts;
return ts;
}
treeset* find_set (treeset* x)
{
if (x->parent!=x)
{
x->parent = find_set (x->parent);
}
return x->parent;
}
void link (treeset* x, treeset* y)
{
if (x->rank>y->rank)
{
y->parent = x;
}
else
{
x->parent = y;
if (x->rank==y->rank)
{
y->rank += 1;
}
}
}
void ubion (treeset* x, treeset* y)
{
link (find_set(x), find_set(y));
}
public:
vector<pair<pair<char, char>, int>> jihe (vector<pair<pair<char, char>, int>>& pro)
{
vector<pair<pair<char, char>, int>> tem; //A
map<char, treeset*> mm;
for (char i = 'a'; i < 'j'; i++)
{
mm[i] = make_set (i);
}
std::sort (pro.begin (), pro.end (), [](pair<pair<char, char>, int>& x, pair<pair<char, char>, int>& y)->bool { return x.second< y.second; });
int a = 1;
for (size_t i = 0; i < pro.size(); i++)
{
if (find_set(mm[pro[i].first.first]) != find_set (mm[pro[i].first.second]))
{
tem.push_back (pro[i]);
ubion (mm[pro[i].first.first], mm[pro[i].first.second]);
}
}
return tem;
}
};
prim算法:
template<class T1>
class solution
{
typedef struct jiebian
{
jiebian* m_parent;
int m_key;
T1 m_self;
jiebian (T1 self) :m_key(INT_MAX),m_self(self),m_parent(nullptr){};
jiebian (T1 self,int key) :m_key (key), m_self (self), m_parent (nullptr) {};
}jiebian;
void make_min_heap (deque<jiebian*>& d)
{
int len = d.size ();
for (int i = len / 2; i >=0; --i)
{
this->make_min_heapfy (d, i);
}
}
void make_min_heapfy (deque<jiebian*>& d,int n )
{
int l = (n+1) * 2 - 1;
int r = (n + 1) * 2;
int minest = n;
int heapsize = d.size ();
minest = l < int(d.size ()) && d[l]->m_key < d[n]->m_key ? l : n;
minest = r < int(d.size ()) && d[r]->m_key < d[minest]->m_key ? r : minest;
while (minest != n)
{
swap (d[n], d[minest]); //注意变量之间的关系
n = minest;
l = 2 * minest + 1;
r = 2 * (minest + 1);
minest = l < heapsize && d[l]->m_key < d[n]->m_key ? l : minest;
minest = r < heapsize && d[r]->m_key < d[minest]->m_key ? r : minest;
}
}
void insert(deque<jiebian*>& d, jiebian* key) ////
{
d.emplace_back (key);
decrease_key (d, d.size () - 1);
}
jiebian* minimum (deque<jiebian*>& A)
{
return A[0];
}
jiebian* exart_min (deque<jiebian*>& A)
{
if (A.size()<1)
{
cout << "error" << endl;
}
jiebian* min1 = A.front();
A[0] = A[A.size () - 1];
A.pop_back ();
make_min_heapfy (A, 0);
return min1;
}
void decrease_key (deque<jiebian*>& A,int n)
{
while (n>=0 && A[(n+1)/2-1]>A[n])
{
swap (A[(n + 1) / 2 - 1], A[n]);
n = (n + 1) / 2 - 1;
}
}
public:
void prim (vector<pair<pair<char, char>, int>>& pro)
{
deque<jiebian*> duilie;
map<char, jiebian*> yinshe;
jiebian* jb1 = new jiebian ('a',0);
duilie.emplace_back (jb1);
yinshe['a'] = jb1;
for (char i = 'b'; i < 'j'; i++)
{
jiebian* jb = new jiebian (i);
yinshe[i] = jb;
duilie.emplace_back (jb);
}
this->make_min_heap(duilie);
while (!duilie.empty())
{
jiebian* u = this->exart_min (duilie);
for (size_t i = 0; i < pro.size(); i++)
{
auto v = yinshe[pro[i].first.second];
auto v1 = yinshe[pro[i].first.first];
if (pro[i].first.first==u->m_self&& find(duilie.begin(),duilie.end(),v)!=duilie.end()) // && v->m_keypro[i].second && pro[i].second< yinshe[pro[i].first.second]->m_key
{
if (v->m_key > pro[i].second)
{
v->m_key = pro[i].second;
v->m_parent = u;
}
}
if (pro[i].first.second == u->m_self && find (duilie.begin (), duilie.end (), v1) != duilie.end ()) // && v->m_keypro[i].second && pro[i].second< yinshe[pro[i].first.second]->m_key
{
if (v1->m_key > pro[i].second)
{
v1->m_key = pro[i].second;
v1->m_parent = u;
}
}
}
make_min_heap (duilie);
}
vector<pair<char, jiebian*>> cc1(yinshe.begin(),yinshe.end());
std::sort (cc1.begin (), cc1.end (), [](pair<char, jiebian*>& x, pair<char, jiebian*>& y)->bool { return x.second->m_key < y.second->m_key; });
for (size_t i = 0; i <cc1.size(); i++)
{
if (cc1[i].second->m_parent!=nullptr)
{
cout << cc1[i].second->m_parent->m_self << ' ' << cc1[i].second->m_self <<' '<< cc1[i].second->m_key << endl;;
}
}
return;
}
};
测试主函数:
int main ()
{
vector<pair<pair<char,char>,int>> pro
{
{{'a','b'},4},
{{'a','h'},5},
{{'b','c'},3},
{{'b','h'},11},
{{'c','f'},2},
{{'c','i'},4},
{{'i','g'},7},
{{'i','h'},6},
{{'g','h'},12},
{{'g','f'},2},
{{'c','d'},6},
{{'d','f'},11},
{{'d','e'},9},
{{'e','f'},10}
};
solution<char> sl;
cout << "prim 算法输出:" << endl;
sl.prim (pro);
cout << "kruskal 算法输出:"<<endl;
solution1 sl1;
auto cc = sl1.jihe (pro);
for (auto& i : cc)
{
cout << i.first.first << ' ' << i.first.second << ' ' << i.second << endl;
}
}
本文深入探讨了图论中的两种最小生成树算法——Kruskal算法与Prim算法。Kruskal算法通过贪心策略,按边的权重从小到大选择不形成环的边,构造最小生成树。Prim算法则从任意一点开始,逐步将未加入的最轻边纳入,最终形成最小生成树。文章提供了详细的算法实现与代码示例。
1万+

被折叠的 条评论
为什么被折叠?



