打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
贪心算法(Greedy Algorithm)之最小生成树 克鲁斯卡尔算法(Kruskal's algorithm)

克鲁斯卡尔算法(Kruskal's algorithm)是两个经典的最小生成树算法的较为简单理解的一个。这里面充分体现了贪心算法的精髓。大致的流程可以用一个图来表示。这里的图的选择借用了Wikipedia上的那个。非常清晰且直观。

首先第一步,我们有一张图,有若干点和边

如下图所示:

第一步我们要做的事情就是将所有的边的长度排序,用排序的结果作为我们选择边的依据。这里再次体现了贪心算法的思想。资源排序,对局部最优的资源进行选择。

排序完成后,我们率先选择了边AD。 这样我们的图就变成了

第二步,在剩下的变中寻找。我们找到了CE。这里边的权重也是5

依次类推我们找到了6,7,7。完成之后,图变成了这个样子。

下一步就是关键了。下面选择那条边呢? BC或者EF吗?都不是,尽管现在长度为8的边是最小的未选择的边。但是现在他们已经连通了(对于BC可以通过CE,EB来连接,类似的EF可以通过EB, BA, AD, DF来接连)。所以我们不需要选择他们。类似的BD也已经连通了(这里的连通线用红色表示了)。所以最后就剩下EG和FG了。当然我们选择了EG。 最后成功的图就是下图:

到这里所有的边点都已经连通了,一个最小生成树构建完成。

如果要简要得描述这个算法的话就是,首先边的权重排序。(从小到大)循环的判断是否需要选择这里的边。判断的依据则是边的两个顶点是否已经连通,如果连通则继续下一条。不连通就选择使其连通。这个流程还是非常清晰明了。

但是在实现的时候,困难的地方在于如何描述2个点已然连通? 这里用到了并查集做辅助,至于并查集可以到这里去看看。

这里贴出并查集的代码和Kruscal的C++实现:

  1. /*
  2. *
  3. * Disjoint_Set_Forest.h -- an implementation for disjoint set data structure
  4. *
  5. * Created by Ge Chunyuan on 04/09/2009.
  6. *
  7. * version: 0.1
  8. */
  9. #pragma once
  10. #ifndef _DISJOINT_SET_H_
  11. #define _DISJOINT_SET_H_
  12. #include <vector>
  13. template <typename T> class DisjointSet
  14. {
  15. public:
  16. DisjointSet();
  17. ~DisjointSet();
  18. void makeSet ( const std::vector<T>& s );
  19. bool findSet ( const T& s, T& parent);
  20. void Union ( const T& s1, const T& s2 );
  21. protected:
  22. struct Node
  23. {
  24. int rank;
  25. T data;
  26. Node* parent;
  27. };
  28. int m_nElementCnt;
  29. int m_nSetCnt;
  30. std::vector<Node*> m_Nodes;
  31. };
  32. template< class T> DisjointSet<T>::DisjointSet()
  33. {
  34. m_nElementCnt = 0;
  35. m_nSetCnt = 0;
  36. }
  37. template< class T> DisjointSet<T>::~DisjointSet()
  38. {
  39. for (int i=0;i<m_nElementCnt;i++)
  40. delete m_Nodes[i];
  41. }
  42. template< class T> void DisjointSet<T>::makeSet( const std::vector<T>& s )
  43. {
  44. m_nElementCnt += (int)s.size();
  45. m_nSetCnt += (int)s.size();
  46. std::vector<T>::const_iterator it = s.begin();
  47. for (;it != s.end(); ++ it)
  48. {
  49. Node* pNode = new Node;
  50. pNode->data = *it;
  51. pNode->parent = NULL;
  52. pNode->rank = 0;
  53. m_Nodes.push_back(pNode);
  54. }
  55. }
  56. template< class T> bool DisjointSet<T>::findSet( const T& s, T& parent)
  57. {
  58. Node* curNode = NULL;
  59. bool find =false;
  60. for (int i=0;i<(int)m_Nodes.size();i++)
  61. {
  62. curNode = m_Nodes[i];
  63. if (curNode->data == s)
  64. {
  65. find = true;
  66. break;
  67. }
  68. }
  69. if (!find) return false;
  70. // find the root
  71. Node* pRoot = curNode;
  72. while (pRoot->parent != NULL)
  73. {
  74. pRoot = pRoot->parent;
  75. }
  76. // update all curNode's parent to root
  77. while (curNode != pRoot)
  78. {
  79. Node* pNext = curNode->parent;
  80. curNode->parent = pRoot;
  81. curNode = pNext;
  82. }
  83. parent = pRoot->data;
  84. return true;
  85. }
  86. template< class T> void DisjointSet<T>::Union( const T& s1, const T& s2 )
  87. {
  88. Node* pNode1 = NULL;
  89. Node* pNode2 = NULL;
  90. int find = 0;
  91. for (int i=0;i<(int)m_Nodes.size();++i)
  92. {
  93. if (m_Nodes[i]->data == s1 || m_Nodes[i]->data == s2 )
  94. {
  95. find ++;
  96. if (m_Nodes[i]->data == s1)
  97. pNode1 = m_Nodes[i];
  98. else
  99. pNode2 = m_Nodes[i];
  100. }
  101. }
  102. // not found
  103. if ( find != 2) return ;
  104. if (pNode1->rank > pNode2->rank)
  105. pNode2->parent = pNode1;
  106. else if (pNode1->rank < pNode2->rank)
  107. pNode1->parent = pNode2;
  108. else
  109. {
  110. pNode2->parent = pNode1;
  111. ++ pNode1->rank;
  112. }
  113. --m_nSetCnt;
  114. }
  115. #endif //_DISJOINT_SET_H_

  1. // Kruscal_Algorithm.cpp : Defines the entry point for the console application.
  2. //
  3. #include "stdafx.h"
  4. #include <string>
  5. #include <vector>
  6. #include <algorithm>
  7. #include <iostream>
  8. #include "Disjoint_Set_Forest.h"
  9. struct Vertex
  10. {
  11. Vertex () { }
  12. Vertex (std::string n)
  13. {
  14. name = n;
  15. }
  16. bool operator==(const Vertex& rhs)
  17. {
  18. return name == rhs.name;
  19. }
  20. bool operator!=(const Vertex& rhs)
  21. {
  22. return name != rhs.name;
  23. }
  24. std::string name;
  25. };
  26. struct Edge
  27. {
  28. Edge () {}
  29. Edge (Vertex v1, Vertex v2, int w)
  30. {
  31. this->v1 = v1;
  32. this->v2 = v2;
  33. this->w = w;
  34. }
  35. Vertex v1;
  36. Vertex v2;
  37. int w;
  38. };
  39. struct EdgeSort
  40. {
  41. bool operator()(const Edge& e1, const Edge& e2)
  42. {
  43. return e1.w<e2.w;
  44. }
  45. };
  46. struct PrintEdge
  47. {
  48. void operator() (Edge e)
  49. {
  50. std::cout<< "edge start from "<<e.v1.name <<" to "<<e.v2.name << " with length = "<<e.w <<std::endl;;
  51. }
  52. };
  53. class Graph
  54. {
  55. public:
  56. void appendVertex ( const Vertex& v1)
  57. {
  58. m_vertexs.push_back(v1);
  59. }
  60. void appendEdge ( const Vertex& v1, const Vertex& v2, int w)
  61. {
  62. m_edges.push_back( Edge(v1,v2,w) );
  63. }
  64. void minimumSpanningKruskal ()
  65. {
  66. std::vector<Edge> result;
  67. std::sort (m_edges.begin(), m_edges.end(), EdgeSort());
  68. DisjointSet<Vertex> dv;
  69. dv.makeSet(m_vertexs);
  70. std::vector<Edge>::iterator it = m_edges.begin();
  71. for (;it!= m_edges.end();++it)
  72. {
  73. Vertex p1;
  74. Vertex p2;
  75. bool b1 = dv.findSet(it->v1, p1 );
  76. bool b2 = dv.findSet(it->v2, p2 );
  77. if ( b1&& b2 && (p1 != p2))
  78. {
  79. dv.Union(p1, p2);
  80. result.push_back(*it);
  81. }
  82. }
  83. for_each(result.begin(), result.end(), PrintEdge());
  84. }
  85. protected:
  86. std::vector<Vertex> m_vertexs;
  87. std::vector<Edge> m_edges;
  88. };
  89. int _tmain(int argc, _TCHAR* argv[])
  90. {
  91. Graph gr;
  92. Vertex a("A");
  93. Vertex b("B");
  94. Vertex c("C");
  95. Vertex d("D");
  96. Vertex e("E");
  97. Vertex f("F");
  98. Vertex g("G");
  99. gr.appendVertex(a);
  100. gr.appendVertex(b);
  101. gr.appendVertex(c);
  102. gr.appendVertex(d);
  103. gr.appendVertex(e);
  104. gr.appendVertex(f);
  105. gr.appendVertex(g);
  106. gr.appendEdge(a,b,7);
  107. gr.appendEdge(a,d,5);
  108. gr.appendEdge(b,c,8);
  109. gr.appendEdge(b,d,9);
  110. gr.appendEdge(b,e,7);
  111. gr.appendEdge(c,e,5);
  112. gr.appendEdge(d,e,15);
  113. gr.appendEdge(d,f,6);
  114. gr.appendEdge(e,f,8);
  115. gr.appendEdge(e,g,9);
  116. gr.appendEdge(f,g,11);
  117. gr.minimumSpanningKruskal();
  118. system("pause");
  119. return 0;
  120. }  
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
标准模板库(STL)使用入门(下)
从零开始学习OpenGL ES之四 – 光效
非线性优化库G20实战套路
igraph Reference Manual
贴花编辑器实现细节
C语言面试题
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服