[数据结构]图krusakl算法实现

打印 上一主题 下一主题

主题 1777|帖子 1777|积分 5331


Kruskal算法

我们要在连通图中去找生成树
连通图:在无向图中,若从顶点v1到顶点v2有路径,则称顶点v1与顶点v2是连通的。如果图中恣意一对顶点都是连通的,则称此图为连通图
生成树:一个连通图的最小连通子图称作该图的生成树。有n个顶点的连通图的生成树有n个顶点和n-1条边。也就是用最少的边(n-1条边)连通起来。
最小生成树:构成生成树的这些边加起来权值最小,也就是最小的成本让这N个顶点连通,最小生成树不唯一。
连通图中的每一棵生成树,都是原图的一个极大无环子图,即:从此中删去任何一条边,生成树就不在连通;反之,在此中引入任何一条新边,都会形成一条回路。
若连通图由n个顶点构成,则其生成树必含n个顶点和n-1条边。因此构造最小生成树的准则有三条:

  • 只能利用图中的权值最小的边来构造最小生成树
  • 只能利用恰恰n-1条边来连接图中的n个顶点
  • 选用的n-1条边不能构成回路
构造最小生成树的方法:Kruskal算法和Prim算法。这两个算法都接纳了逐步求解的贪婪策略。
贪婪算法:是指在问题求解时,总是做出当前看起来最好的选择。也就是说贪婪算法做出的不是团体最优的的选择,而是某种意义上的局部最优解。贪婪算法不是对全部的问题都能得到团体最优解
Kruskal算法和Prim算法求出来的肯定是最优解吗?——不肯定

因此要选出最小的边,然后举行连接
在这里判定是否成环的关键是并查集
代码实现:
  1. W Kruskal(Self& minTree)
  2. {
  3.         minTree._vertexs = _vertexs;
  4.         minTree._indexMap = _indexMap;
  5.         minTree._matrix.resize(_vertexs.size());
  6.         for (auto& e : minTree._matrix)
  7.         {
  8.                 e.resize(_vertexs.size(), MAX_W);
  9.         }
  10.         // 先根据边的权值进行排序
  11.         priority_queue<Edge, vector<Edge>, greater<Edge>> pq;
  12.         for (size_t i = 0; i < _vertexs.size(); ++i)
  13.         {
  14.                 for (size_t j = 0; j < _vertexs.size(); ++j)
  15.                 {
  16.                         if (i < j && _matrix[i][j] != MAX_W)
  17.                         {
  18.                                 // pq.push(_matrix[i][j]); 不是这样
  19.                                 pq.push(Edge(i, j, _matrix[i][j]));
  20.                         }
  21.                 }
  22.         }
  23.         W total = W();
  24.         size_t i = 1; // 最初有一个顶点
  25.         // 从最小的边开始进行选择(贪心)
  26.         UnionFindSet ufs(_vertexs.size());
  27.         while (i < _vertexs.size() && !pq.empty())
  28.         {
  29.                 Edge min = pq.top();
  30.                 pq.pop();
  31.                 // 判断是否会构成一个回路,不会则添加到最小生成树中
  32.                 if (ufs.FindRoot(min._srci) != ufs.FindRoot(min._dsti))
  33.                 {
  34.                         cout << _vertexs[min._srci] << "-" << _vertexs[min._dsti] << ":" << _matrix[min._srci][min._dsti] << endl;
  35.                         minTree._AddEdge(min._srci, min._dsti, min._w);
  36.                         total += min._w;
  37.                         ufs.Union(min._srci, min._dsti);
  38.                         ++i;
  39.                 }
  40.         }
  41.         if (i == _vertexs.size())
  42.         {
  43.                 return total;
  44.         }
  45.         else
  46.         {
  47.                 return W();
  48.         }
  49. }
复制代码
完整代码:
  1. namespace matrix // 领接矩阵存储
  2. {
  3.         template <class V, class W, W MAX_W = INT_MAX, bool Direction = false> // Vertex, Weight, Direction表示有向图还是无向图
  4.         class Graph
  5.         {
  6.                 typedef Graph<V, W, MAX_W, Direction> Self; // 表示子图
  7.         public:
  8.                 Graph()
  9.                 {}
  10.                 Graph(const V* vertex, size_t n)
  11.                 {
  12.                         _vertexs.reserve(n);
  13.                         for (size_t i = 0; i < n; ++i)
  14.                         {
  15.                                 _vertexs.push_back(vertex[i]);
  16.                                 _indexMap[vertex[i]] = i; // map<V, int>second存的是对应的编号
  17.                         }
  18.                         _matrix.resize(n);
  19.                         for (int i = 0; i < n; ++i)
  20.                         {
  21.                                 _matrix[i].resize(n, MAX_W);
  22.                         }
  23.                 }
  24.                
  25.                 size_t GetVertexIndex(const V& v)
  26.                 {
  27.                         auto ret = _indexMap.find(v);
  28.                         if (ret != _indexMap.end())
  29.                         {
  30.                                 return ret->second;
  31.                         }
  32.                         else
  33.                         {
  34.                                 assert(false);
  35.                                 return -1;
  36.                         }
  37.                 }
  38.                 void AddEdge(const V& src, const V& dst, const W& w)
  39.                 {
  40.                         size_t srci = GetVertexIndex(src);
  41.                         size_t dsti = GetVertexIndex(dst);
  42.                         _AddEdge(srci, dsti, w);
  43.                 }
  44.                
  45.                 void _AddEdge(size_t srci, size_t dsti, const W& w)
  46.                 {
  47.                         _matrix[srci][dsti] = w;
  48.                         if (Direction == false)
  49.                         {
  50.                                 _matrix[dsti][srci] = w;
  51.                         }
  52.                 }
  53.                 void Print()
  54.                 {
  55.                         // 顶点
  56.                         for (size_t i = 0; i < _vertexs.size(); ++i)
  57.                         {
  58.                                 cout << "[" << i << "]" << "->" << _vertexs[i] << endl;
  59.                         }
  60.                         cout << endl;
  61.                         // 矩阵
  62.                         // 横下标
  63.                         cout << "  ";
  64.                         for (size_t i = 0; i < _vertexs.size(); ++i)
  65.                         {
  66.                                 //cout << i << " ";
  67.                                 printf("%4d", i);
  68.                         }
  69.                         cout << endl;
  70.                         for (size_t i = 0; i < _matrix.size(); ++i)
  71.                         {
  72.                                 cout << i << " "; // 竖下标
  73.                                 for (size_t j = 0; j < _matrix[i].size(); ++j)
  74.                                 {
  75.                                         //cout << _matrix[i][j] << " ";
  76.                                         if (_matrix[i][j] == MAX_W)
  77.                                         {
  78.                                                 //cout << "* ";
  79.                                                 printf("%4c", '*');
  80.                                         }
  81.                                         else
  82.                                         {
  83.                                                 //cout << _matrix[i][j] << " ";
  84.                                                 printf("%4d", _matrix[i][j]);
  85.                                         }
  86.                                 }
  87.                                 cout << endl;
  88.                         }
  89.                         cout << endl;
  90.                 }
  91.                 void BFS(const V& src)
  92.                 {
  93.                         size_t srci = GetVertexIndex(src);
  94.                         // 队列和标记数组
  95.                         queue<int> q;
  96.                         vector<bool> visited(_vertexs.size(), false); // 标记数组
  97.                         int levelSize = 1; // 保证一层 一层的打印
  98.                         q.push(srci);
  99.                         visited[srci] = true;
  100.                         size_t n = _vertexs.size();
  101.                         while (!q.empty())
  102.                         {
  103.                                 for (int i = 0; i < levelSize; ++i)
  104.                                 {
  105.                                         int front = q.front();
  106.                                         q.pop();
  107.                                         cout << front << ":" << _vertexs[front] << " ";
  108.                                         // 把front顶点的邻接顶点入队列
  109.                                         for (size_t i = 0; i < n; ++i)
  110.                                         {
  111.                                                 if (_matrix[front][i] != MAX_W) // 不是无穷大就是相连的
  112.                                                 {
  113.                                                         if (visited[i] == false)
  114.                                                         {
  115.                                                                 q.push(i);
  116.                                                                 visited[i] = true;
  117.                                                         }
  118.                                                 }
  119.                                         }
  120.                                 }
  121.                                 cout << endl;
  122.                                 levelSize = q.size(); // 下一层的数据个数
  123.                         }
  124.                         cout << endl;
  125.                 }
  126.                 void _DFS(size_t srci, vector<bool> visited)
  127.                 {
  128.                         cout << srci << ":" << _vertexs[srci] << endl;
  129.                         visited[srci] = true;
  130.                         // 找srci相邻的没有访问过的点,深度遍历
  131.                         for (size_t i = 0; i < _vertexs.size(); ++i)
  132.                         {
  133.                                 if (_matrix[srci][i] != MAX_W && visited[i] = false)
  134.                                 {
  135.                                         _DFS(i, visited);
  136.                                 }
  137.                         }
  138.                 }
  139.                 void DFS(const V& src)
  140.                 {
  141.                         size_t srci = GetVertexIndex(src);
  142.                         vector<bool> visited(_vertexs.size(), false);
  143.                         _DFS(srci, visited);
  144.                 }
  145.                 struct Edge
  146.                 {
  147.                         size_t _srci;
  148.                         size_t _dsti;
  149.                         W _w;
  150.                         Edge(size_t srci, size_t dsti, const W& w)
  151.                                 : _srci(srci)
  152.                                 , _dsti(dsti)
  153.                                 , _w(w)
  154.                         {}
  155.                         bool operator>(const Edge& e) const
  156.                         {
  157.                                 return _w > e._w;
  158.                         }
  159.                 };
  160.                 W Kruskal(Self& minTree)
  161.                 {
  162.                         minTree._vertexs = _vertexs;
  163.                         minTree._indexMap = _indexMap;
  164.                         minTree._matrix.resize(_vertexs.size());
  165.                         for (auto& e : minTree._matrix)
  166.                         {
  167.                                 e.resize(_vertexs.size(), MAX_W);
  168.                         }
  169.                         // 先根据边的权值进行排序
  170.                         priority_queue<Edge, vector<Edge>, greater<Edge>> pq;
  171.                         for (size_t i = 0; i < _vertexs.size(); ++i)
  172.                         {
  173.                                 for (size_t j = 0; j < _vertexs.size(); ++j)
  174.                                 {
  175.                                         if (i < j && _matrix[i][j] != MAX_W)
  176.                                         {
  177.                                                 // pq.push(_matrix[i][j]); 不是这样
  178.                                                 pq.push(Edge(i, j, _matrix[i][j]));
  179.                                         }
  180.                                 }
  181.                         }
  182.                         W total = W();
  183.                         size_t i = 1; // 最初有一个顶点
  184.                         // 从最小的边开始进行选择(贪心)
  185.                         UnionFindSet ufs(_vertexs.size());
  186.                         while (i < _vertexs.size() && !pq.empty())
  187.                         {
  188.                                 Edge min = pq.top();
  189.                                 pq.pop();
  190.                                 // 判断是否会构成一个回路,不会则添加到最小生成树中
  191.                                 if (ufs.FindRoot(min._srci) != ufs.FindRoot(min._dsti))
  192.                                 {
  193.                                         cout << _vertexs[min._srci] << "-" << _vertexs[min._dsti] << ":" << _matrix[min._srci][min._dsti] << endl;
  194.                                         minTree._AddEdge(min._srci, min._dsti, min._w);
  195.                                         total += min._w;
  196.                                         ufs.Union(min._srci, min._dsti);
  197.                                         ++i;
  198.                                 }
  199.                         }
  200.                         if (i == _vertexs.size())
  201.                         {
  202.                                 return total;
  203.                         }
  204.                         else
  205.                         {
  206.                                 return W();
  207.                         }
  208.                 }
  209.         private:
  210.                 vector<V> _vertexs; // 顶点集合
  211.                 map<V, int> _indexMap; // 顶点映射下标
  212.                 vector<vector<W>> _matrix;// 存储边的关系
  213.         };
  214.         void TestGraph()
  215.         {
  216.                 Graph<char, int, INT_MAX, true> g("0123", 4);
  217.                 g.AddEdge('0', '1', 1);
  218.                 g.AddEdge('0', '3', 4);
  219.                 g.AddEdge('1', '3', 2);
  220.                 g.AddEdge('1', '2', 9);
  221.                 g.AddEdge('2', '3', 8);
  222.                 g.AddEdge('2', '1', 5);
  223.                 g.AddEdge('2', '0', 3);
  224.                 g.AddEdge('3', '2', 6);
  225.                 g.Print();
  226.         }
  227.         void TestBDFS()
  228.         {
  229.                 string a[] = { "张三", "李四", "王五", "赵六", "周七" };
  230.                 Graph<string, int> g1(a, sizeof(a) / sizeof(string));
  231.                 g1.AddEdge("张三", "李四", 100);
  232.                 g1.AddEdge("张三", "王五", 200);
  233.                 g1.AddEdge("王五", "赵六", 30);
  234.                 g1.AddEdge("王五", "周七", 30);
  235.                 g1.Print();
  236.                 g1.BFS("张三");
  237.         }
  238.         void TestGraphMinTree()
  239.         {
  240.                 const char* str = "abcdefghi";
  241.                 Graph<char, int> g(str, strlen(str));
  242.                 g.AddEdge('a', 'b', 4);
  243.                 g.AddEdge('a', 'h', 8);
  244.                 //g.AddEdge('a', 'h', 9);
  245.                 g.AddEdge('b', 'c', 8);
  246.                 g.AddEdge('b', 'h', 11);
  247.                 g.AddEdge('c', 'i', 2);
  248.                 g.AddEdge('c', 'f', 4);
  249.                 g.AddEdge('c', 'd', 7);
  250.                 g.AddEdge('d', 'f', 14);
  251.                 g.AddEdge('d', 'e', 9);
  252.                 g.AddEdge('e', 'f', 10);
  253.                 g.AddEdge('f', 'g', 2);
  254.                 g.AddEdge('g', 'h', 1);
  255.                 g.AddEdge('g', 'i', 6);
  256.                 g.AddEdge('h', 'i', 7);
  257.                 Graph<char, int> kminTree;
  258.                 cout << "Kruskal:" << g.Kruskal(kminTree) << endl;
  259.                 //kminTree.Print();
  260.                 /*Graph<char, int> pminTree;
  261.                 cout << "Prim:" << g.Prim(pminTree, 'a') << endl;
  262.                 pminTree.Print();*/
  263.         }
  264. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

魏晓东

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表