数据结构面试之九——图的常见操作3之最小生成树

简介: 最小生成树——包含带权图中的全部顶点并不能形成环,且权值之和最小的图。求解最小生成树的方法包括:Prim算法和Kruskal算法。对于Prim算法思想:1)从源结点集中选定一个源结点(初始源节点集合中只有设定一个结点);2)从剩余结点中选择与源节点集有连接的且权值最小的边。将该源节点加入源节点集合中。然后迭代执行1),2)。

数据结构面试之九——图的常见操作3之最小生成树

题注:《面试宝典》有相关习题,但思路相对不清晰,排版有错误,作者对此参考相关书籍和自己观点进行了重写,供大家参考。


九、图的常见操作3之最小生成树


最小生成树——包含带权图中的全部顶点并不能形成环,且权值之和最小的图。


求解最小生成树的方法包括:Prim算法和Kruskal算法。


对于Prim算法思想:1)从源结点集中选定一个源结点(初始源节点集合中只有设定一个结点);2)从剩余结点中选择与源节点集有连接的且权值最小的边。将该源节点加入源节点集合中。然后迭代执行1),2)。


如下图的图结构,含有7个顶点,下图示为图的邻接矩阵存储结构。





Vertex 0


Vertex 1


Vertex 2


Vertex 3


Vertex 4


Vertex 5


Vertex 6


Vertex 0


0


6


5


2





Vertex 1


6


0




2



4


Vertex 2


5



0




7


5


Vertex 3


2




0


8




Vertex 4



2



8


0


10



Vertex 5




7



10


0



Vertex 6



4


5





0



模拟执行步骤如下:


前提:源节点集合VertexSet中初始只有设定的0(假定,可以任意取0à6中任意值)。起初初始的边结合EdgeSet为空。


步骤1:从与0相连的边集合中,选定权值最小的边,对应上图Vertex0行显然为2。所以选择的顶点为Vertex3。


VertexSet


EdgeSet


SumWeight


0,3


(0,3)


2



步骤2:从与{0,3}相连的边集合中,选定权值最小的边,如下图,显然权值为5。所以选择的顶点为Vertex2。



Vertex 0


Vertex 1


Vertex 2


Vertex 3


Vertex 4


Vertex 5


Vertex 6


Vertex 0


0


6


5√


×





















Vertex 3


×




0


8




























集合变为:


VertexSet


EdgeSet


SumWeight


0,3,2


(0,3)(0,2)


2+5




步骤3:从与{0,3,2}相连的边集合中,选定权值最小的边,如下图,显然权值为4。所以选择的顶点为Vertex6。



Vertex 0


Vertex 1


Vertex 2


Vertex 3


Vertex 4


Vertex 5


Vertex 6


Vertex 0


0


6


×


×













Vertex 2


×



0




7


5,√


Vertex 3


×




0


8




























集合变为:


VertexSet


EdgeSet


SumWeight


0,3,2,6


(0,3)(0,2)(2,6)


2+5+5



步骤4:从与{0,3,2,6}相连的边集合中,选定权值最小的边,如下图,显然权值为5。所以选择的顶点为Vertex1。



Vertex 0


Vertex 1


Vertex 2


Vertex 3


Vertex 4


Vertex 5


Vertex 6


Vertex 0


0


6


×


×













Vertex 2


×



0




7


×


Vertex 3


×




0


8




















Vertex 6



4√


×





0


集合变为:


VertexSet


EdgeSet


SumWeight


0,3,2,6,1


(0,3)(0,2)(2,6)(6,1)


2+5+5+4



步骤5:从与{0,3,2,6,1}相连的边集合中,选定权值最小的边,如下图,显然权值为2。所以选择的顶点为Vertex4。



Vertex 0


Vertex 1


Vertex 2


Vertex 3


Vertex 4


Vertex 5


Vertex 6


Vertex 0


0


6


×


×





Vertex 1


6


0




2√



×


Vertex 2


×



0




7


×


Vertex 3


×




0


8




















Vertex 6



×


×





0


集合变为:


VertexSet


EdgeSet


SumWeight


0,3,2,6,1,4


(0,3)(0,2)(2,6)(6,1)(1,4)


2+5+5+4+2



步骤6:从与{0,3,2,6,1,4}相连的边集合中,选定权值最小的边,如下图,显然权值为2。所以选择的顶点为Vertex4。



Vertex 0


Vertex 1


Vertex 2


Vertex 3


Vertex 4


Vertex 5


Vertex 6


Vertex 0


0


6


×


×





Vertex 1


6


0




×



×


Vertex 2


×



0




7√


×


Vertex 3


×




0


8




Vertex 4



×



8


0


10











Vertex 6



×


×





0


集合变为:


VertexSet


EdgeSet


SumWeight


0,3,2,6,1,4,5


(0,3)(0,2)(2,6)(6,1)(1,4)(2,5)


2+5+5+4+2+7



最后:遍历后的结果如下2图:即包含所有顶点,没有环路,且权值最小。



Vertex 0


Vertex 1


Vertex 2


Vertex 3


Vertex 4


Vertex 5


Vertex 6


Vertex 0


0


6


×


×





Vertex 1


6


0




×



×


Vertex 2


×



0




×


×


Vertex 3


×




0


8




Vertex 4



×



8


0


10



Vertex 5




×



10


0



Vertex 6



×


×





0



VertexSet


EdgeSet


SumWeight


0,3,2,6,1,4,5


(0,3)(0,2)(2,6)(6,1)(1,4)(2,5)


2+5+5+4+2+7=25


//inifinity 代表权值无穷大,即不可达。

int g_WeightMatrix[7][7] ={0,6,5,2,infinity,infinity,infinity,

                                                6,0,infinity,infinity,2,infinity,4,

                                                5,infinity,0,infinity,infinity,7,5,

                                                2,infinity,infinity,0,8,infinity,infinity,

                                                infinity,2,infinity,8,0,10,infinity,

                                                infinity,infinity,7,infinity,10,0,infinity,

                                                infinity,4,5,infinity,infinity,infinity,0};

template<class vType, int size>

class msTreeType : publicgraphType<vType, size>

{

public:

      voidcreateSpanningGraph();

      voidminimalSpanning(vType sVertex);

      voidprintTreeAndWeight();

protected:

      vTypesource;             //

      intweights[size][size];  //权重数组

      intedges[size];          //边的集合,edges[0]=5即代表0-5之间有边存在。

      intedgeWeights[size];    //存储从某顶点开始的权重.

};


1.创建权重图


创建权重图的时候,我们做了简化处理。只是将给定的权重数组赋值过来了。[此处稍作修改,便可以改为手动输入顶点及邻接边的关系]。图的存储形式:邻接矩阵存储!


template <class vType, int size>

voidmsTreeType<vType,size>::createSpanningGraph()

{

      gSize= size;

      source= 0;                   //记录初始点为0.

      for(int i = 0; i < size; i++)

      {

             for(int j =0; j < size; j++)

             {

                    weights[i][j]= g_WeightMatrix[i][j];

                    if(weights[i][j]!= 0 && weights[i][j] != infinity)

                    {

                           edges[i]= j;            //代表i--j之间的连线存在

                    //     cout << "edges[ " <<i << " ]=" << edges[i] << "\t";

                    }

                    cout<< weights[i][j] << "\t";

             }

             cout<< endl;

      }

}


2.最小生成树


1.巧妙的记录源结点、目标结点的方法(通过数组下标和结果值);2.还需要存储每次比较后的最小的权重值。


template <class vType, int size>

voidmsTreeType<vType,size>::minimalSpanning(vType sVertex)

{

      vType startVertex, endVertex;

      int minWeight;

      source = sVertex;

//代表mstree的结点结合中是否存在点. mstv[5] =true,代表结点5在集合中已经存在。

//=false,则代表不存在.

      bool mstv[size];

//初始化 0代表到自身, infinity代表不可达.

      for(int j = 0; j < gSize; j++)

      {

             mstv[j]= false;

             edges[j]= source;

             edgeWeights[j]= weights[source][j];

      }

      mstv[source]= true;

      edgeWeights[source]= 0;       //初始设定

      for(int i = 0; i < gSize-1; i++)

      {

             minWeight= infinity;  

//从所有顶点中寻找权重最小且未被标识的顶点,v记录该顶点,minWeight记录权重值。

             for(int j = 0; j < gSize; j++)

             {

                    if(mstv[j])//mstv中已经存在的点j

                    {

                           for(intk=0; k < gSize; k++)

                           {

                                  //寻找由已经存在的结点中到剩余结点权值最小的边。

                                  if(!mstv[k]&& weights[j][k] < minWeight)

                                  {

                                         endVertex= k;    //目的

                                         startVertex= j;  //源

                                         minWeight= weights[j][k]; //最小权重

                                  }

                           }//endfor k

                    }//endif(mstv[j])

             }//endfor j

             mstv[endVertex]= true;

             edges[endVertex]= startVertex;

             edgeWeights[endVertex]= minWeight;

      }//endfor

}

3.打印小生成树


template <class vType, int size>

voidmsTreeType<vType,size>::printTreeAndWeight()

{

      inttreeWeight = 0;

      minimalSpanning(source);

   

      cout<< "Source vertex: " << source << endl;

      cout<< "Edges\t\tWeight" << endl;

      for(int j = 0; j < gSize; j++)

      {

             if(edgeWeights[j]!= 0)

             {

                    treeWeight= treeWeight + edgeWeights[j];

                    cout<< "(" << j << ", " <<edges[j]  << ")\t\t"<< edgeWeights[j] << endl;

             }

      }

      cout<< endl;

      cout<< "Tree Weight: " << treeWeight << endl;

}


相关文章
|
3月前
|
存储 安全 Java
Java 集合面试题从数据结构到 HashMap 源码剖析详解及长尾考点梳理
本文深入解析Java集合框架,涵盖基础概念、常见集合类型及HashMap的底层数据结构与源码实现。从Collection、Map到Iterator接口,逐一剖析其特性与应用场景。重点解读HashMap在JDK1.7与1.8中的数据结构演变,包括数组+链表+红黑树优化,以及put方法和扩容机制的实现细节。结合订单管理与用户权限管理等实际案例,展示集合框架的应用价值,助你全面掌握相关知识,轻松应对面试与开发需求。
185 3
【Java集合类面试二十六】、介绍一下ArrayList的数据结构?
ArrayList是基于可动态扩展的数组实现的,支持快速随机访问,但在插入和删除操作时可能需要数组复制而性能较差。
|
8月前
|
算法 C++
【C++数据结构——图】最小生成树(头歌实践教学平台习题) 【合集】
【数据结构——图】最小生成树(头歌实践教学平台习题)目录 任务描述 相关知识 测试说明 我的通关代码: 测试结果:【合集】任务描述 本关任务:编写一个程序求图的最小生成树。相关知识 为了完成本关任务,你需要掌握:1.建立邻接矩阵,2.Prim算法。建立邻接矩阵 上述带权无向图对应的二维数组,根据它建立邻接矩阵,如图1建立下列邻接矩阵。注意:INF表示无穷大,表示整数:32767 intA[MAXV][MAXV];Prim算法 普里姆(Prim)算法是一种构造性算法,从候选边中挑
101 10
|
11月前
|
算法 前端开发 Java
数据结构与算法学习四:单链表面试题,新浪、腾讯【有难度】、百度面试题
这篇文章总结了单链表的常见面试题,并提供了详细的问题分析、思路分析以及Java代码实现,包括求单链表中有效节点的个数、查找单链表中的倒数第k个节点、单链表的反转以及从尾到头打印单链表等题目。
120 1
数据结构与算法学习四:单链表面试题,新浪、腾讯【有难度】、百度面试题
|
10月前
|
存储 NoSQL Redis
Redis常见面试题:ZSet底层数据结构,SDS、压缩列表ZipList、跳表SkipList
String类型底层数据结构,List类型全面解析,ZSet底层数据结构;简单动态字符串SDS、压缩列表ZipList、哈希表、跳表SkipList、整数数组IntSet
|
算法 Python
逆袭之路!用 Python 玩转图的 DFS 与 BFS,让数据结构难题无处遁形
【7月更文挑战第12天】图的遍历利器:DFS 和 BFS。Python 中,图可表示为邻接表或矩阵。DFS 沿路径深入,回溯时遍历所有可达顶点,适合找路径和环。BFS 层次遍历,先近后远,解决最短路径问题。两者在迷宫、网络路由等场景各显神通。通过练习,掌握这些算法,图处理将游刃有余。
157 3
|
存储 算法 Python
“解锁Python高级数据结构新姿势:图的表示与遍历,让你的算法思维跃升新高度
【7月更文挑战第13天】Python中的图数据结构用于表示复杂关系,通过节点和边连接。常见的表示方法是邻接矩阵(适合稠密图)和邻接表(适合稀疏图)。图遍历包括DFS(深度优先搜索)和BFS(广度优先搜索):DFS深入探索分支,BFS逐层访问邻居。掌握这些技巧对优化算法和解决实际问题至关重要。**
146 1
|
算法 Java
Java数据结构与算法:贪心算法之最小生成树
Java数据结构与算法:贪心算法之最小生成树
|
Java Android开发 Kotlin
Android面试题:App性能优化之Java和Kotlin常见的数据结构
Java数据结构摘要:ArrayList基于数组,适合查找和修改;LinkedList适合插入删除;HashMap1.8后用数组+链表/红黑树,初始化时预估容量可避免扩容。SparseArray优化查找,ArrayMap减少冲突。 Kotlin优化摘要:Kotlin的List用`listOf/mutableListOf`,Map用`mapOf/mutableMapOf`,支持操作符重载和扩展函数。序列提供懒加载,解构用于遍历Map,扩展函数默认参数增强灵活性。
152 0
|
10月前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?

热门文章

最新文章