数据结构-最小生成树的实现

合集下载

数据结构(Java版)图2(最小生成树)

数据结构(Java版)图2(最小生成树)

最小生成树举例
A
50 60 52 65 50
C
45 42 30 50
A
C
45
B
40
D
G
B
40 50
D
42 30
G
E
70
F
E
F
(a) 无向带权连通图G
(b) 无向带权图G 的最小生成树T
从最小生成树的定义可知,构造n个顶点的无向带权连 通图的最小生成树,必须满足如下三个条件: ① 必须包含n个顶点。 ② 有且仅有n-1条边。 ③ 没有回路。

将ej边加入到tree中;
}
实践项目

设计一个程序实现Prim和Kruskal算法.
表5-1 lowcost[ ]数组数据变化情况 表5-2 closest[ ]数组数据变化情况
扫描次数
closest[0]
closest[1]
closest[2]
closest[3]
closest[4]
closest[5]
求最小生成树算法

普里姆算法(Prim) (从点着手)

适合于求边稠密的最小生成树 适合于求边稀疏的最小生成树

克鲁斯卡尔算法(Kruskal)(从边着手)

普里姆算法(Prim)思想
1.
2.
3.
4.
令集合U={u0}(即从顶点u0开始构造最小生 成树),集合T={}。 从所有顶点u∈U和顶点v∈V-U的边权中选择最 小权值的边(u,v),将顶点v加入到集合U中,边 (u,v)加入到集合T中。 如此重复下去,直到U=V时则最小生成树构造完 毕。 此时集合U就是最小生成树的顶点集合,集合T 就是最小生成树的边集。

数据结构最小生成树克鲁斯卡尔算法代码

数据结构最小生成树克鲁斯卡尔算法代码

数据结构最小生成树克鲁斯卡尔算法代码以下是克鲁斯卡尔算法的实现代码:```python# 定义边的类class Edge:def __init__(self, src, dest, weight):self.src = srcself.dest = destself.weight = weight# 定义图的类class Graph:def __init__(self, vertices):self.V = verticesself.edges = []def add_edge(self, src, dest, weight):edge = Edge(src, dest, weight)self.edges.append(edge)# 查找顶点的根节点def find(self, parent, i):if parent[i] == i:return ireturn self.find(parent, parent[i])# 合并两个集合def union(self, parent, rank, x, y):xroot = self.find(parent, x)yroot = self.find(parent, y)if rank[xroot] < rank[yroot]:parent[xroot] = yrootelif rank[xroot] > rank[yroot]:parent[yroot] = xrootelse:parent[yroot] = xrootrank[xroot] += 1# 使用克鲁斯卡尔算法计算最小生成树def kruskal(self):result = []i = 0e = 0 # 已选择的边的数量# 按权重对边进行排序self.edges = sorted(self.edges, key=lambda x:x.weight)parent = []rank = []# 初始化每个顶点的父节点和秩for node in range(self.V):parent.append(node)rank.append(0)while e < self.V - 1:# 选择权重最小的边edge = self.edges[i]i += 1x = self.find(parent, edge.src)y = self.find(parent, edge.dest) # 判断是否形成环路if x != y:e += 1result.append(edge)self.union(parent, rank, x, y) return result# 测试代码g = Graph(4)g.add_edge(0, 1, 10)g.add_edge(0, 2, 6)g.add_edge(0, 3, 5)g.add_edge(1, 3, 15)g.add_edge(2, 3, 4)result = g.kruskal()for edge in result:print(f"{edge.src} -- {edge.dest} == {edge.weight}")```这段代码实现了克鲁斯卡尔算法,其中`Graph`类表示图,`Edge`类表示边。

实验5最小生成树算法的设计与实现(报告)

实验5最小生成树算法的设计与实现(报告)

实验5 最小生成树算法的设计与实现一、实验目的1、根据算法设计需要, 掌握连通图的灵活表示方法;2、掌握最小生成树算法,如Prim、Kruskal算法;3、基本掌握贪心算法的一般设计方法;4、进一步掌握集合的表示与操作算法的应用。

二、实验内容1、认真阅读算法设计教材和数据结构教材内容, 熟习连通图的不同表示方法和最小生成树算法;2、设计Kruskal算法实验程序。

有n个城市可以用(n-1)条路将它们连通,求最小总路程的和。

设计测试问题,修改并调试程序, 输出最小生成树的各条边, 直至正确为止。

三、Kruskal算法的原理方法边权排序:1 3 14 6 23 6 41 4 52 3 53 4 52 5 61 2 63 5 65 6 61. 初始化时:属于最小生成树的顶点U={}不属于最小生成树的顶点V={1,2,3,4,5,6}2. 根据边权排序,选出还没有连接并且权最小的边(1 3 1),属于最小生成树的顶点U={1,3},不属于最小生成树的顶点V={2,4,5,6}3. 根据边权排序,选出还没有连接并且权最小的边(4 6 2),属于最小生成树的顶点U={{1,3},{4,6}}(还没有合在一起,有两颗子树),不属于最小生成树的顶点V={2,5}4. 根据边权排序,选出还没有连接并且权最小的边(3 6 4),属于最小生成树的顶点U={1,3,4,6}(合在一起),不属于最小生成树的顶点V={2,5}5. 根据边权排序,选出还没有连接并且权最小的边(3 6 4),属于最小生成树的顶点U={1,2,3,4,6},,不属于最小生成树的顶点V={5}6. 根据边权排序,选出还没有连接并且权最小的边(3 6 4),属于最小生成树的顶点U={1,2,3,4,5,6}此时,最小生成树已完成四、实验程序的功能模块功能模块:bool cmp(Edge a,Edge b); //定义比较方法x);//在并查集森林中找到x的祖先int g etfa(intint s ame(int x,int y); //判断祖先是否是同一个,即是否联通 void merge(int x,int y); //合并子树,即联通两子树sort(e+1,e+m+1,cmp); //对边按边权进行升序排序详细代码:#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#define M AXN_E 100000#define M AXN_V 100000using namespace std;struct Edge{int f m,to,dist;//边的起始顶点,边的到达顶点,边权}e[MAXN_E];int f a[MAXN_V],n,m; //顶点数组,顶点总数,边总数 //定义比较,只是边权比较bool cmp(Edge a,Edge b){return a.dist < b.dist;}//查找x的祖先是在并查集森林中找到x的祖先x){//getfaint g etfa(intreturn fa[x];if(fa[x]==x)else r eturn fa[x] = getfa(fa[x]);}//判断祖先是否是同一个,即是否联通int s ame(int x,int y){return getfa(x)==getfa(y);}//合并两棵树void merge(int x,int y){int f ax=getfa(x),fay=getfa(y);fa[fax]=fay;}int m ain(){int i;cout<<"请输入顶点数目和边数目:"<<endl;cin>>n>>m;//n为点数,m为边数//输出顶点信息cout<<"各个顶点值依次为:"<<endl;for(i=0;i<n;i++){fa[i]=i;if(i!=0)cout<<fa[i]<<" ";}cout<<endl;cout<<"请输入边的信息(例子:1 4 5 从顶点1到顶点4的边权为5)"<<endl;for(i=1;i<=m;i++)用边集数组存放边,方便排序和调用 cin>>e[i].fm>>e[i].to>>e[i].dist;//sort(e+1,e+m+1,cmp); //对边按边权进行升序排序表示目前的点共存在于多少个集合中,初始情况是每 int r st=n,ans=0;//rst个点都在不同的集合中for(i=1;i<=m && rst>1;i++){int x=e[i].fm,y=e[i].to;函数是查询两个点是否在同一集合中 if(same(x,y))continue;//sameelse{函数用来将两个点合并到同一集合中 merge(x,y);//mergerst--;//每次将两个不同集合中的点合并,都将使rst值减1这条边是最小生成树中的边,将答案加上边权 ans+=e[i].dist;//}}cout<<ans;return 0;}五、测试数据和相应的最小生成树Input:6 101 2 61 3 11 4 52 3 52 5 63 4 53 5 63 6 44 6 25 6 6Putout:18生成树为:七、思考题1、微软面试题一个大院子里住了50户人家,每家都养了一条狗,有一天他们接到通知说院子里有狗生病了,并要求所有主人在发现自己家狗生病的当天就要把狗枪杀掉。

数据结构-图的连通性

数据结构-图的连通性

③数据结构的动态分析 (closedge[5].adjvex,G.vexs[5])
∞ 6 1 6 ∞ 5 1 5 ∞ 5 6 5 ∞ 3 6 ∞ ∞ 4
i
1
v2 5
3
5 v4
2
v3
5 ∞ 5 ∞ ∞ 2 2
∞ 3 6 ∞ ∞ 6 3
∞ ∞ 4 2 6 ∞ 4 5
3
6
4
2
4 v 5
6
v6
5
G.vexs:
一、最小生成树
2.实例:V={v1,v2,v3,v4,v5,v6}
①任取u0=v1, 则:U={v1}, V-U={v2,v3,v4,v5,v6}
v2 6
v1 5 1 5 v3 3 6 4 2 5 v4
v5
6
v6
一、最小生成树
2.实例:V={v1,v2,v3,v4,v5,v6}
①任取u0=v1, 则:U={v1}, V-U={v2,v3,v4,v5,v6} ②取边(v1,v3),则:U={v1,v3} V-U={v2,v4,v5,v6}
一、最小生成树
3.算法的实现:
③数据结构的动态分析 G.arcs如下:
0 0 1 2 3 4 5 1 2 3 4 5 6
0
v1 5 1
1
v2 5
3
5 v4
2
v3
∞ 6 1 6 ∞ 5 1 5 ∞ 5 6 5 ∞ 3 6 ∞ ∞ 4
i
5 ∞ 5 ∞ ∞ 2 2
∞ 3 6 ∞ ∞ 6 3
∞ ∞ 4 2 6 ∞ 4 5
v2 6
v1 5 1 5 v3 3 6 4 2 5 v4
v5
6
v6
④取边(v6,v4),则:U={v1,v3, v6,v4} V-U={v2,v5} ⑤取边(v3,v2),则:U={v1,v3, v6,v4,v2} ⑥取边(v2,v5),则:U={v1,v3, v6,v4,v2,v5}

6-4-数据结构——从概念到C++实现(第3版)-王红梅-清华大学出版社

6-4-数据结构——从概念到C++实现(第3版)-王红梅-清华大学出版社

数 据 结



012345
概 念

adjvex[n] = 0 0 0 0 0 0
实 现 )


lowcost[n] = 0 34 46 ∞ ∞ 19
大 学 出


Prim算法——存储结构
每一次迭代,设数组lowcost[n]中的最小权值是lowcost [j],则
令lowcost[j] = 0,表示将顶点 j 加入集合U中;
从 概 念


如何存储候选最短边集(连接U和V-U的候选最短边)?
现 ) 清

例如:{(v0 , v1)34,(v0 , v2)46,(v0, v3)∞,(v0 , v4)∞,(v0, v5 )19}
大 学 出


数组adjvex[n]:表示候选最短边的邻接点
adjvex[i] = j
数组lowcost[n]:表示候选最短边的权值
v4)26}
数 据
V-U={v1 , v3 , v4 }
结 构 ( 从
cost ={(v0 , v1)34, (v2, v3)17, (v5 , v4)26}
概 念 到




第三次迭代:
华 大 学

U={v0 , v5, v2 , v3 }
版 社
V-U={v1 , v4}
cost={(v0 , v1)34, (v5 , v4)26}
学 出 版

U:涂色
V-U:尚未涂色
方法:一个顶点涂色、另一个顶点尚未涂色的最短边
Prim算法——运行实例
34
v1
v0 19 v5

数据结构的实验报告

数据结构的实验报告

一、实验目的本次实验旨在让学生掌握数据结构的基本概念、逻辑结构、存储结构以及各种基本操作,并通过实际编程操作,加深对数据结构理论知识的理解,提高编程能力和算法设计能力。

二、实验内容1. 线性表(1)顺序表1)初始化顺序表2)向顺序表插入元素3)从顺序表删除元素4)查找顺序表中的元素5)顺序表的逆序操作(2)链表1)创建链表2)在链表中插入元素3)在链表中删除元素4)查找链表中的元素5)链表的逆序操作2. 栈与队列(1)栈1)栈的初始化2)入栈操作3)出栈操作4)获取栈顶元素5)判断栈是否为空(2)队列1)队列的初始化2)入队操作3)出队操作4)获取队首元素5)判断队列是否为空3. 树与图(1)二叉树1)创建二叉树2)遍历二叉树(前序、中序、后序)3)求二叉树的深度4)求二叉树的宽度5)二叉树的镜像(2)图1)创建图2)图的深度优先遍历3)图的广度优先遍历4)最小生成树5)最短路径三、实验过程1. 线性表(1)顺序表1)初始化顺序表:创建一个长度为10的顺序表,初始化为空。

2)向顺序表插入元素:在顺序表的第i个位置插入元素x。

3)从顺序表删除元素:从顺序表中删除第i个位置的元素。

4)查找顺序表中的元素:在顺序表中查找元素x。

5)顺序表的逆序操作:将顺序表中的元素逆序排列。

(2)链表1)创建链表:创建一个带头结点的循环链表。

2)在链表中插入元素:在链表的第i个位置插入元素x。

3)在链表中删除元素:从链表中删除第i个位置的元素。

4)查找链表中的元素:在链表中查找元素x。

5)链表的逆序操作:将链表中的元素逆序排列。

2. 栈与队列(1)栈1)栈的初始化:创建一个栈,初始化为空。

2)入栈操作:将元素x压入栈中。

3)出栈操作:从栈中弹出元素。

4)获取栈顶元素:获取栈顶元素。

5)判断栈是否为空:判断栈是否为空。

(2)队列1)队列的初始化:创建一个队列,初始化为空。

2)入队操作:将元素x入队。

3)出队操作:从队列中出队元素。

图的最短路径与最小生成树算法实践

图的最短路径与最小生成树算法实践

图的最短路径与最小生成树算法实践在计算机科学中,图(Graph)是一种抽象的数据结构,它由节点(Vertex)和边(Edge)组成。

图的最短路径和最小生成树是图算法中的两个重要问题,它们在网络、交通、社交网络等领域有着广泛的应用。

本文将介绍图的最短路径算法和最小生成树算法的实践。

一、图的最短路径算法实践图的最短路径算法用于求解两个节点之间的最短路径,常用的算法有迪杰斯特拉算法(Dijkstra Algorithm)和弗洛伊德算法(Floyd Algorithm)。

(这里可以介绍迪杰斯特拉算法和弗洛伊德算法的思想和流程,注意使用文字和图示来说明)在实际应用中,最短路径算法可以被用于许多场景,比如导航系统中的路径规划、物流配送中的最优路线选择等。

例如,在一座城市中,我们需要规划出从A地到B地的最短路径,可以使用最短路径算法来求解。

二、图的最小生成树算法实践图的最小生成树算法用于找到一个连通图的最小生成树,最常用的算法是普里姆算法(Prim Algorithm)和克鲁斯卡尔算法(Kruskal Algorithm)。

(这里可以介绍普里姆算法和克鲁斯卡尔算法的思想和流程,注意使用文字和图示来说明)最小生成树算法在实际应用中也有很多用途,比如电力系统的最优输电线路规划、通信网络的构建等。

例如,在一个城市的交通网络中,我们希望为每个区域之间建立电缆线路,以便实现高速、稳定的通信,可以使用最小生成树算法来求解。

三、图的最短路径和最小生成树算法在实践中的应用图的最短路径和最小生成树算法在现代社会中有广泛的应用,下面将介绍一些实际应用场景。

1. 路径规划最短路径算法可以用于导航系统中的路径规划。

通过输入起点和终点,最短路径算法可以帮助我们找到从起点到终点的最短路径,以便在导航系统上为驾驶员提供准确的路线指引。

2. 物流配送在物流配送中,最短路径算法可以用于选择最优路线,以节省时间和成本。

通过计算各个配送点之间的距离和路径,可以帮助物流公司规划出最佳配送路线,提高配送效率。

最小生成树的算法

最小生成树的算法

最小生成树的算法王洁引言:求连通图的最小生成树是数据结构中讨论的一个重要问题.在现实生活中,经常遇到如何得到连通图的最小生成树,求最小生成树不仅是图论的基本问题之一 ,在实际工作中也有很重要的意义,,人们总想寻找最经济的方法将一个终端集合通过某种方式将其连接起来 ,比如将多个城市连为公路网络 ,要设计最短的公路路线;为了解决若干居民点供水问题 ,要设计最短的自来水管路线等.而避开这些问题的实际意义 ,抓住它们的数学本质 ,就表现为最小生成树的构造。

下面将介绍几种最小生成树的算法。

一,用“破圈法”求全部最小生成树的算法1 理论根据1.1 约化原则给定一无向连通图 G =(V ,E )( V 表示顶点,E 表示边),其中 V={ 1v , 2v ,3v …… n v },E= { 1e , 2e , 3e …… n e }对于 G 中的每条边 e ∈ E 都赋予权ω(i e )>0,求生成树 T = (V ,H ),H ⊆ E ,使生成树所有边权最小,此生成树称为最小生成树.(1) 基本回路将属于生成树 T 中的边称为树枝,树枝数为n -1,不属于生成树的边称为连枝.将任一连枝加到生成树上后都会形成一条回路.把这种回路称为基本回路,记为()cf e 。

基本回路是由 T 中的树枝和一条连枝构成的回路.(2) 基本割集设无向图 G 的割集 S (割集是把连通图分成两个分离部分的最少支路集合) ,若 S 中仅包含有T 中的一条树枝,则称此割集为基本割集,记为()S e 。

基本割集是集合中的元素只有一条是树枝,其他的为连枝.(3) 等长变换设T=(V,H),为一棵生成树,e ∈ H, 'e ∈ E, 'e ∉ H,当且仅当'e ∈()cf e ,也就是说e ∈()S e ,则'T =T ⊕{e, 'e }也是一棵生成树。

当()e ω='()e ω时,这棵生成树叫做等长变换。

《数据结构》课程设计 普里姆算法 最小生成树

《数据结构》课程设计 普里姆算法 最小生成树
printf("(%d %d %d)\n",lge[i].start_vex,lge
[i].stop_vex,lge[i].weight); /*输出N-1条最小边的信息*/
for(i=0;i<12;i++)
{
line(vex[lge[i].start_vex][0],vex[lge[i].start_vex][1],vex[lge
lge[min]=lge[i];
lge[i]=edge;
vx=lge[i].stop_vex;
for(j=i+1; j<pgraph->n-1; j++)
{
vy=lge[j].stop_vex;
weight=pgraph->arcs[vx][vy];
if(weight<lge[j].weight)
{
{550,250},{520,330},{430,400},{350,450},{270,400},{200,330}};
/*初始化个顶点的坐标*/
int info[12][12];
char *text;
void initalGraph(int vec[][2]) /*画出顶点函数*/
{
int gd=DETECT,gm;
[i].stop_vex][0],vex[lge[i].stop_vex][1]);
}
/*根据生成的最小边数组连线*/
printf("---It is done!---");
getch();
exit(1);
}
此程序再TURBOC2.0环境中编译通过运行.TURBOC2.0下载的地址

最小生成树

最小生成树
16
17
D
应用举例——最小生成树
Prim算法 34 A 46 19 F B 12 26 25 E 38 cost'={(A, B)34, (C, D)17, (F, E)26}
17
U={A, F, C, D}
V-U={B, E}
cost={(A, B)34, (F, E)26}
25
C
17
D
应用举例——最小生成树
{B, C, D, E, F} (A F)19
{B, C, D, E} {B, D, E} {B, E} {B} {}
(F C)25
(C D)17
(F E)26
adjvex lowcost
adjvex lowcost
4 12
{A, F, C, D, E}
{A,F,C,D,E,B}
(E B)12
21
应用举例——最小生成树
Prim算法——伪代码
1. 将顶点0加入集合U中; 2. 初始化辅助数组shortEdge,分别为lowcost和adjvex赋值; 3. 重复执行下列操作n-1次 3.1 在shortEdge中选取最短边,取其对应的下标k; 3.2 输出边(k, shortEdge[k].adjvex)和对应的权值; 3.3 将顶点k加入集合U中; 3.4 调整数组shortEdge;
U
V-U
输出
adjvex lowcost adjvex lowcost adjvex lowcost adjvex lowcost
0 34 0 34 0 34 0 34
0 46 5 25
0 ∞ 5 25 2 17
0 ∞ 5 26 5 26 5 26
0 19

数据结构之最小生成树Prim算法

数据结构之最小生成树Prim算法

数据结构之最⼩⽣成树Prim算法普⾥姆算法介绍 普⾥姆(Prim)算法,是⽤来求加权连通图的最⼩⽣成树算法 基本思想:对于图G⽽⾔,V是所有顶点的集合;现在,设置两个新的集合U和T,其中U⽤于存放G的最⼩⽣成树中的顶点,T存放G的最⼩⽣成树中的边。

从所有uЄU,vЄ(V-U) (V-U表⽰出去U的所有顶点)的边中选取权值最⼩的边(u, v),将顶点v加⼊集合U中,将边(u, v)加⼊集合T中,如此不断重复,直到U=V为⽌,最⼩⽣成树构造完毕,这时集合T中包含了最⼩⽣成树中的所有边。

代码实现1. 思想逻辑 (1)以⽆向图的某个顶点(A)出发,计算所有点到该点的权重值,若⽆连接取最⼤权重值#define INF (~(0x1<<31)) (2)找到与该顶点最⼩权重值的顶点(B),再以B为顶点计算所有点到改点的权重值,依次更新之前的权重值,注意权重值为0或⼩于当前权重值的不更新,因为1是⼀当找到最⼩权重值的顶点时,将权重值设为了0,2是会出现⽆连接的情况。

(3)将上述过程⼀次循环,并得到最⼩⽣成树。

2. Prim算法// Prim最⼩⽣成树void Prim(int nStart){int i = 0;int nIndex=0; // prim最⼩树的索引,即prims数组的索引char cPrims[MAX]; // prim最⼩树的结果数组int weights[MAX]; // 顶点间边的权值cPrims[nIndex++] = m_mVexs[nStart].data;// 初始化"顶点的权值数组",// 将每个顶点的权值初始化为"第start个顶点"到"该顶点"的权值。

for (i = 0; i < m_nVexNum; i++){weights[i] = GetWeight(nStart, i);}for (i = 0; i < m_nVexNum; i ++){if (nStart == i){continue;}int min = INF;int nMinWeightIndex = 0;for (int k = 0; k < m_nVexNum; k ++){if (weights[k]!= 0 && weights[k] < min){min = weights[k];nMinWeightIndex = k;}}// 找到下⼀个最⼩权重值索引cPrims[nIndex++] = m_mVexs[nMinWeightIndex].data;// 以找到的顶点更新其他点到该点的权重值weights[nMinWeightIndex]=0;int nNewWeight = 0;for (int ii = 0; ii < m_nVexNum; ii++){nNewWeight = GetWeight(nMinWeightIndex, ii);// 该位置需要特别注意if (0 != weights[ii] && weights[ii] > nNewWeight){weights[ii] = nNewWeight;}}for (i = 1; i < nIndex; i ++){int min = INF;int nVexsIndex = GetVIndex(cPrims[i]);for (int kk = 0; kk < i; kk ++){int nNextVexsIndex = GetVIndex(cPrims[kk]);int nWeight = GetWeight(nVexsIndex, nNextVexsIndex);if (nWeight < min){min = nWeight;}}nSum += min;}// 打印最⼩⽣成树cout << "PRIM(" << m_mVexs[nStart].data <<")=" << nSum << ": ";for (i = 0; i < nIndex; i++)cout << cPrims[i] << "";cout << endl;}3. 全部实现#include "stdio.h"#include <iostream>using namespace std;#define MAX 100#define INF (~(0x1<<31)) // 最⼤值(即0X7FFFFFFF)class EData{public:EData(char start, char end, int weight) : nStart(start), nEnd(end), nWeight(weight){} char nStart;char nEnd;int nWeight;};// 边struct ENode{int nVindex; // 该边所指的顶点的位置int nWeight; // 边的权重ENode *pNext; // 指向下⼀个边的指针};struct VNode{char data; // 顶点信息ENode *pFirstEdge; // 指向第⼀条依附该顶点的边};// ⽆向邻接表class listUDG{public:listUDG(){};listUDG(char *vexs, int vlen, EData **pEData, int elen){m_nVexNum = vlen;m_nEdgNum = elen;// 初始化"邻接表"的顶点for (int i = 0; i < vlen; i ++){m_mVexs[i].data = vexs[i];m_mVexs[i].pFirstEdge = NULL;}char c1,c2;int p1,p2;ENode *node1, *node2;// 初始化"邻接表"的边for (int j = 0; j < elen; j ++){// 读取边的起始顶点和结束顶点p1 = GetVIndex(c1);p2 = GetVIndex(c2);node1 = new ENode();node1->nVindex = p2;node1->nWeight = pEData[j]->nWeight;if (m_mVexs[p1].pFirstEdge == NULL){m_mVexs[p1].pFirstEdge = node1;}else{LinkLast(m_mVexs[p1].pFirstEdge, node1);}node2 = new ENode();node2->nVindex = p1;node2->nWeight = pEData[j]->nWeight;if (m_mVexs[p2].pFirstEdge == NULL){m_mVexs[p2].pFirstEdge = node2;}else{LinkLast(m_mVexs[p2].pFirstEdge, node2);}}}~listUDG(){ENode *pENode = NULL;ENode *pTemp = NULL;for (int i = 0; i < m_nVexNum; i ++){pENode = m_mVexs[i].pFirstEdge;if (pENode != NULL){pTemp = pENode;pENode = pENode->pNext;delete pTemp;}delete pENode;}}void PrintUDG(){ENode *pTempNode = NULL;cout << "邻接⽆向表:" << endl;for (int i = 0; i < m_nVexNum; i ++){cout << "顶点:" << GetVIndex(m_mVexs[i].data)<< "-" << m_mVexs[i].data<< "->"; pTempNode = m_mVexs[i].pFirstEdge;while (pTempNode){cout <<pTempNode->nVindex << "->";pTempNode = pTempNode->pNext;}cout << endl;}}// Prim最⼩⽣成树void Prim(int nStart){int i = 0;int nIndex=0; // prim最⼩树的索引,即prims数组的索引char cPrims[MAX]; // prim最⼩树的结果数组int weights[MAX]; // 顶点间边的权值cPrims[nIndex++] = m_mVexs[nStart].data;// 初始化"顶点的权值数组",// 将每个顶点的权值初始化为"第start个顶点"到"该顶点"的权值。

数据结构:第7章 图3-最小生成树

数据结构:第7章 图3-最小生成树

• 按照生成树的定义,n 个顶点的连通网络的生成树有 n
个顶点、n-1 条边。
即有权图
目标:
在网络的多个生成树中,寻找一个各边权值之和最小的
生成树。
构造最小生成树的准则 ❖ 必须只使用该网络中的边来构造最小生成树;
❖ 必须使用且仅使用n-1条边来联结网络中的n个顶点;
❖ 不能使用产生回路的边。
典型用途:
(b) u={1} w={2,3,4,5,6}
0 6 1 5
6
0
5
3
1 5 0 7 5 4
5
7
0
2
3 5 0 6
4 2 6 0
i
1234
closest[i] 1 1 1 1
lowcost[i] 0 6 1 5
56 11 ∞∞
closest用于存放顶点序号 lowest存放权值
15 4 6
1 25
3
54
5
6
(c ) u={1,3} w={2,4,5,6}
1
1
4
25
6
32
54
5
6
(d) u={1,3,6} w={2,4,5}
i
1234 5 6
closest[i] 1 3 1 1 3 3
lowcost[i] 0 5 0 5 5 4
i
1234 5 6
closest[i] 1 3 1 6 3 3

v3 v1

树 v4 v2
v1
0^ 1^ 0^ 1^
2.生成森林
若一个图是非连通图或非强连通图,但有若 干个连通分量或若干个强连通分量,则通过 深度优先搜索遍历或广度优先搜索遍历,不 可以得到生成树,但可以得到生成森林,且 若非连通图有 n 个顶点,m 个连通分量或强 连通分量,则可以遍历得到m棵生成树,合 起来为生成森林,森林中包含n-m条树边。

最小生成树实验报告

最小生成树实验报告

最小生成树实验报告最小生成树(Minimum Spanning Tree,MST)是图论中的一个重要概念,用于在一个连通带权无向图中找到一个子图,使得这个子图是一个树(即无环连通图),并且所有边的权值之和最小。

最小生成树在诸多领域有着广泛的应用,如网络设计、电力传输等。

在本次实验中,我们实现了最小生成树算法,并将其运用到多个实际问题上。

下面将依次介绍算法原理、实现过程、实验结果以及对实验的进一步改进。

1.算法原理Kruskal算法的基本思想是,首先将所有边按照权值从小到大排序,然后从最小的边开始,逐一加入生成树,直到生成树包含了所有的顶点。

在加入一条边时,需要判断这条边将两个顶点连通起来是否会形成环,如果不会则加入生成树。

Prim算法的基本思想是,从一个顶点开始,逐步加入生成树的顶点,每次加入一个顶点时,选择一个离生成树最近的点,并将这个点加入生成树。

通过不断的选择顶点和加入边,最终得到最小生成树。

2.实现过程首先,我们实现了图的数据结构和边的数据结构。

在图的数据结构中,我们定义了图的顶点数和边数,并用邻接矩阵来表示图的连接情况。

边的数据结构包含了两个顶点和边的权值。

其次,我们实现了两种算法。

对于Kruskal算法,我们首先将所有边按照权值从小到大进行排序。

然后,逐个加入边,判断是否形成环。

如果不会形成环,则将该边加入生成树。

最后,我们使用并查集数据结构来判断两个顶点是否连通。

对于Prim算法,我们首先选择一个起点作为生成树的初始顶点,并将其加入生成树。

然后,每次选择一个离生成树最近的顶点,并将其加入生成树,同时更新其他顶点到生成树的距离。

最后,所有顶点都被加入生成树后,得到最小生成树。

3.实验结果我们在实验中选择了不同大小的图进行测试。

经过对比,我们发现Kruskal算法和Prim算法得到的最小生成树结果是一致的,但是Kruskal 算法的时间复杂度要稍高于Prim算法。

具体的结果如下:对于一个边数为10的图,我们得到了如下最小生成树:1-2-4-5-3总权重为12对于一个边数为20的图,我们得到了如下最小生成树:2-1-4-5-3总权重为16对于一个边数为30的图2-1-4-5-6-7-3总权重为22从实验结果来看,无论是规模较小的图还是规模较大的图,我们都能够得到最小生成树,并且所得到的结果是正确的。

克鲁斯卡尔算法最小生成树生成c++

克鲁斯卡尔算法最小生成树生成c++

克鲁斯卡尔算法最小生成树生成c++克鲁斯卡尔算法是一种用于求解最小生成树的经典算法。

下面将展示如何使用C++实现克鲁斯卡尔算法来生成最小生成树。

在使用克鲁斯卡尔算法之前,我们需要定义一些数据结构来表示图和边。

首先,我们可以使用一个二维数组来表示图,其中每个元素表示两个节点之间的边权重。

然后,我们可以使用一个结构体来表示边,包含起点、终点和权重这三个属性。

接下来,我们可以按照以下步骤来实现克鲁斯卡尔算法:1. 创建一个并查集(Union-Find)数据结构来帮助判断两个节点是否连通。

2. 将图中的所有边按照权重从小到大进行排序。

3. 创建一个空的最小生成树。

4. 遍历排序后的边,对于每条边,如果它连接的两个节点不在同一个连通分量中,则将这条边加入最小生成树,并将这两个节点合并到同一个连通分量中。

5. 重复步骤4,直到最小生成树中有V-1条边(V为图中的节点数),或者遍历完所有的边为止。

下面是用C++实现克鲁斯卡尔算法的代码示例:```c++#include <iostream>#include <vector>#include <algorithm>using namespace std;struct Edge {int src, dest, weight;};struct Graph {int V, E;vector<Edge> edges;};bool compare(Edge a, Edge b) {return a.weight < b.weight;}int findParent(vector<int>& parent, int i) {if (parent[i] == -1)return i;return findParent(parent, parent[i]);}void unionSet(vector<int>& parent, int x, int y) {int xset = findParent(parent, x);int yset = findParent(parent, y);parent[xset] = yset;}void KruskalMST(Graph graph) {vector<Edge> result;vector<int> parent(graph.V, -1);sort(graph.edges.begin(), graph.edges.end(), compare); int i = 0, j = 0;while (i < graph.V - 1 && j < graph.E) {Edge nextEdge = graph.edges[j++];int x = findParent(parent, nextEdge.src);int y = findParent(parent, nextEdge.dest);if (x != y) {result.push_back(nextEdge);unionSet(parent, x, y);i++;}}cout << 'Edges in Minimum Spanning Tree:' << endl;for (i = 0; i < result.size(); i++) {cout << result[i].src << ' - ' << result[i].dest << ' , Weight: ' << result[i].weight << endl;}}int main() {Graph graph;graph.V = 4;graph.E = 5;graph.edges.push_back({0, 1, 10});graph.edges.push_back({0, 2, 6});graph.edges.push_back({0, 3, 5});graph.edges.push_back({1, 3, 15});graph.edges.push_back({2, 3, 4});KruskalMST(graph);return 0;}```上述代码会输出最小生成树中的边以及它们的权重。

最小生成树三种求解方法的分析与实现

最小生成树三种求解方法的分析与实现

最小生成树三种求解方法的分析与实现作者:李龙霞陈燕于晓倩来源:《电脑知识与技术》2021年第33期摘要:圖作为一种典型的非线性结构,用图来描述问题简明直观。

而最小生成树作为图的重要应用之一,用于解决优化路线,如何使网络通信线路成本最低,电话线路最短等问题。

将此类问题转化为最小生成树问题进行求解。

最小生成树是所有生成树中代价最小的生成树。

它以邻接矩阵的方式存储,采用Prim算法,Kruskal算法和破圈法的方法进行求解。

关键词:图;最小生成树;Prim算法;Kruskal算法;破圈法中图分类号:TP301.6;TP311.12 文献标识码:A文章编号:1009-3044(2021)33-0044-03开放科学(资源服务)标识码(OSID):Analysis and Realization of Three Methods of Solving Minimum Spanning TreeLI Long-xia, CHEN Yan, YU Xiao-qian(School of Maritime Economics and Management, Dalian Maritime University, Dalian 116026, China)Abstract: Graph, as a typical nonlinear structure, is simple and intuitive to describe the problem. As one of the most important applications of graphs, the minimum spanning tree is used to solve the problems of optimizing routes, minimizing the cost of network communication lines and the shortest telephone lines. This kind of problem is transformed into the minimum spanning tree problem to solve. The minimum spanning tree is the spanning tree with the least cost among all spanning trees. It is stored in the form of adjacency matrix and solved by Prim algorithm, Kruskal algorithm and loop breaking method.Key words: Graph; Minimum Spanning Tree; Prim algorithm; Kruskal algorithm; Broken Ring Method1 引言求解最小生成树是解决工程类问题的一种重要手段。

数据结构和算法学习笔记八:带权连通图的最小生成树

数据结构和算法学习笔记八:带权连通图的最小生成树

数据结构和算法学习笔记⼋:带权连通图的最⼩⽣成树⼀.简介: 对于⼀个n个顶点的连通图,其最⼩⽣成树是指将所有顶点连接起来的权值之和的最⼩树,树中包含n个顶点和n-1条边.最⼩⽣成树常见的⽣成算法有普⾥姆算法和克鲁斯卡尔算法,它们分别基于顶点的⾓度和边的⾓度⽣成最⼩⽣成树. 声明:对于本⽂中实现图结构的各种类,详见:⼆.两种算法简介 1.普⾥姆算法:普⾥姆算法基于顶点实现,基本思路是将所有已经纳⼊到最⼩⽣成树中的顶点存储起来,然后遍历当前的最⼩⽣成树的端点,找出权值最⼩且不会闭环的边并延伸最⼩⽣成树,然后将新的顶点纳⼊到最⼩⽣成树中(和其他已经纳⼊到树中的顶点⼀起存储起来) 2.克鲁斯卡尔算法:克鲁斯卡尔算法基于边实现,⾸先将所有边按照权值由⼩到⼤排序,然后再从⼩到达依次遍历所有边,⼀⼀判断当前边加⼊最⼩⽣成树中后是否会形成环路,在不形成环路的情况下将此边加⼊最⼩⽣成树,并将顶点存储起来.顶点的存储结构类似于倒置的树,根节点在最下⽅.在最⼩⽣成树的⽣成过程中可能会同时存在多颗顶点树,但是最终所有顶点树会汇聚成⼀颗.三.代码实现(c#)/************************************* 创建⼈:movin* 创建时间:2021/7/4 19:55:02* 版权所有:个⼈***********************************/using System;using System.Collections.Generic;using System.Text;namespace GraphCore{///<summary>///最⼩⽣成树算法///</summary>public class MinimumCostSpanningTreeUtil{///<summary>///计算最⼩⽣成树-普⾥姆算法///要求参数必须是⼀个连通图,此处没有校验参数graph是否是连通图的过程,可⾃⾏添加///</summary>///<param name="graph"></param>///<param name="findAEdgeCallBack">找到⼀条边后的回调函数,参数为边的两个关联点下标和权值</param>public static void MiniSpanTree_Prim(AdjacencyMatrixGraph graph,Action<int,int,int> findAEdgeCallBack = null){//数组lowcast,数组的长度和顶点的个数⼀致,数组中每个下标的值和顶点⼀⼀对应//lowcast的作⽤有两个,以lowcast[1] = 5为例,意思是当前已经找过的顶点中到1顶点的最短路径权值为5//所以作⽤⼀是某下标对应值不为0时代表当前已经⽣成的部分最⼩⽣成树到某下标对应顶点的权值最⼩的边的权值//作⽤⼆是某下标对应值为0时代表此下标对应顶点已经在最⼩⽣成树中,不再参与继续⽣成最⼩⽣成树int[] lowcast = new int[graph.Count];//数组adjvex,这个数组作⽤是对应记录lowcast中最⼩权值边的另⼀个依附顶点下标(⼀个依附顶点下标就是lowcast下标)int[] adjvex = new int[graph.Count];lowcast[0] = 0;//从0号顶点开始⽣成最⼩⽣成树,⾸先将0号顶点对应位置置为0//adjvex[0] = 0;//这句代码加不加都ok,0号位已经加⼊最⼩⽣成树,这个值也就⽤不上了//初始化lowcast数组的其他下标值for(int i = 1;i < lowcast.Length; i++){//当前最⼩⽣成树中只有0号顶点,所以以0号顶点到i号顶点的边的权值就是当前的最⼩边权值lowcast[i] = graph.adjacencyMatrix[0, i];//这些边的另⼀个依附顶点当然是0号顶点adjvex[i] = 0;}//开始计算最⼩⽣成树,结果存储到result中int min = int.MaxValue;//⽤来存储找到的最⼩权值边的权值的临时变量int tempIndex = 0;//⽤来存储即将加⼊最⼩⽣成树的边的顶点(也就是即将加⼊最⼩⽣成树的顶点)的临时变量,另⼀个顶点存储在adjvex数组中//循环length-1次,每次将⼀个顶点和⼀条边加⼊最⼩⽣成树中for(int i = 1;i < graph.Count; i++){//循环在当前的lowcast中找到⾮0的最⼩值(到没有找过的顶点中的最⼩边)min = int.MaxValue;tempIndex = 0;for(int j = 1;j < lowcast.Length; j++){if(lowcast[j] != 0 && lowcast[j] < min){min = lowcast[j];tempIndex = j;}}//找到边后调⽤回调函数if(findAEdgeCallBack != null){findAEdgeCallBack(tempIndex, adjvex[tempIndex], lowcast[tempIndex]);}//更新lowcast数组lowcast[tempIndex] = 0;//每次延申了最⼩⽣成树后需要将lowcast中的值更新,⽅便下次继续延申最⼩⽣成树//刚才将下标为tempIndex的顶点和⼀条边加⼊了最⼩⽣成树,接下来只需要更新这个顶点相关的边即可for(int j = 1;j < lowcast.Length;j++){//判断顶点tempIndex和顶点j之间的边//j顶点不在最⼩⽣成树中且这条边的权值⽐lowcast中记录的最⼩权值要⼩时//更新到顶点j的最⼩权值边的权值,并且记录到顶点j的最⼩权值边的另⼀个顶点为tempIndexif(lowcast[j] != 0 && lowcast[j] > graph.adjacencyMatrix[tempIndex, j]){lowcast[j] = graph.adjacencyMatrix[tempIndex, j];adjvex[j] = tempIndex;}}}}///<summary>///计算最⼩⽣成树-克鲁斯卡尔算法///要求参数必须是连通图///</summary>///<param name="graph"></param>///<param name="findAEdgeCallBack">找到⼀条边后的回调函数,参数为边的两个关联点下标和权值</param>public static void MinSpanTree_Kruskal(EdgesetArrayGraph graph, Action<int, int, int> findAEdgeCallBack = null){//将边集数组排序SortEdgeNode(graph.edgeNodes);//声明⼀个数组,数组下标对应顶点下标//数组中值为-1时代表对应顶点还没有加⼊最⼩⽣成树//当某个顶点被加⼊最⼩⽣成树后,将数组中对应的下标的值修改,修改后的值指向下⼀个加⼊最⼩⽣成树的顶点下标//如vertices[5] = 7代表5号顶点和7号顶点都在最⼩⽣成树中,其中5号顶点的下⼀个顶点是7号顶点//在构建最⼩⽣成树的过程中会通过这个数组检验当前边添加进数组是否会构成环//分析后⾯的代码可以知道,最终数组中length-1个值会被修改,刚好对应添加到最⼩⽣成树中的length-1条边int[] vertices = new int[graph.edgeNodes.Length];//数组初始值都为-1for (int i = 0; i < vertices.Length; i++){vertices[i] = -1;}//下⾯构建最⼩⽣成树//循环遍历所有边,⼀⼀校验是否可以加⼊最⼩⽣成树for (int i = 0; i < graph.edgeNodes.Length; i++){EdgesetArrayEdgeNode node = graph.edgeNodes[i];int startIndex = GetNextVertex(vertices, node.headIndex);int endIndex = GetNextVertex(vertices, node.tailIndex);//检验是否成环,不成环则这条边可以加⼊最⼩⽣成树if (startIndex != endIndex){vertices[startIndex] = endIndex;if(findAEdgeCallBack != null){findAEdgeCallBack(node.headIndex, node.tailIndex, node.weight);}}}}///<summary>///在vertices中,顶点之间的先后次序最终的存储⽅式类似于⼀颗倒过来的树,根顶点在最下⽅,存储时会⼀直向下找,直到找到根顶点,存储时会将下⼀个存储到最⼩⽣成树中的顶点挂到根顶点下⽅成为新///查找时看此顶点是否有后继顶点,如果有那么继续查找后继顶点的后继顶点...以此类推,直到某个顶点对应下标值为-1,即没有后继顶点,返回这个顶点下标///如果两个顶点之间会构成环路,那么它们所在的顶点的后继中⼀定会有相同的顶点,最终查找下去得到的值为顶点相同///</summary>///<param name="vertices"></param>///<param name="index"></param>///<returns></returns>private static int GetNextVertex(int[] vertices,int index){while(vertices[index] != -1){index = vertices[index];}return index;}///<summary>///将给定边集数组按照从⼩到达排序///采⽤选择排序///</summary>///<param name="graph"></param>private static void SortEdgeNode(EdgesetArrayEdgeNode[] edgeNodes){for (int i = 0; i < edgeNodes.Length; i++){int minIndex = i;for (int j = i + 1; j < edgeNodes.Length; j++){if(edgeNodes[minIndex].weight > edgeNodes[j].weight){minIndex = j;}}if(minIndex != i){EdgesetArrayEdgeNode temp = edgeNodes[i];edgeNodes[i] = edgeNodes[minIndex];edgeNodes[minIndex] = temp;}}}}}。

最小生成树算法的一种实现方法及其在代数理论上的探讨

最小生成树算法的一种实现方法及其在代数理论上的探讨
_
构 成 边 的 一 个 端 点 / \ / 的权 值 / 边 构 成 边 的 另 一 个 端 点 /
eg ; de / 指 向 下 一
诸边不构成 回路的一条最短边, 这样 继续下去直到 条
边 已经 选 出为 止 。
sr c x Ed e * e t e t u t Ve g n xv x
收稿 日期 :08 0 —9 修 回 日期 :0 80 — 2 20— 9 1 ; 20 — 9 2 作者 简介 : 奇 (94 )男 , 士研 究生 , 究 方 向: 王栓 18一 , 硕 研 抽象 代 数。
A r ai a i n o h ag ih e l to f t e lort m o n mum p nn n r e a d t ag b ac d s u so z f mi i s a i g t e n is l e r i ic s i n
W ANG h a - i S u n q ,ZHANG S a — e h o fi
《 农业网络信 g}o 8 2o 年第 1 期 交 流 园 地 1
最小 生成树算 法 的一种 实现方 法 及 其在代数 理论上 的探讨
王栓 奇 , 张绍飞
( 北京 航 空航 天大 学 理 学 院 , 京 10 9 ) 北 0 11

要: 图论 中最小 生成 树 问题 的算 法在 现 实 中应 用 非 常广 泛 , 文先 根据 其 中 的 Kukl 法 的步 骤 并结 合 数据 结 构 中 本 rsa 算
(c ol fS i c fB i n n e i , e i 0 1 1 h a Sh o o c ne o e a g U i r t B in 10 9 ,C i ) e h v sy jg n

最小生成树c语言

最小生成树c语言

最小生成树c语言全文共四篇示例,供读者参考第一篇示例:最小生成树(Minimum Spanning Tree)是图论中的一个重要概念,它表示一个无向连通图的子图,该子图是该连通图的一棵树,包含图中的所有顶点,并且具有最小的权值总和。

在计算机科学领域中,最小生成树的算法被广泛应用在网络设计、通信传输、电力分配等领域,具有重要的实际意义。

Prim算法和Kruskal算法是两种常用的最小生成树算法。

Prim算法基于贪心策略,在每一步选择连接已经选取的顶点和未选取的顶点之间权值最小的边,直到所有顶点都被选取为止。

而Kruskal算法则是基于并查集实现的,首先将所有的边按照权值排序,然后按照权值从小到大的顺序逐个考虑,如果该边连接的两个端点不在同一个集合中,就将它和这两个端点所在的集合合并,直到生成最小生成树。

在本文中,我们将介绍使用C语言实现Prim算法和Kruskal算法的方法,并通过一个具体的例子来说明如何计算最小生成树。

我们来看看Prim算法的实现:```c#include <stdio.h>#include <stdlib.h>#define MAXV 10000#define INF 1000000int graph[MAXV][MAXV];int visited[MAXV];int parent[MAXV];int key[MAXV];int prim(int n) {int i, j, u, v, min, mincost = 0; for (i = 0; i < n; i++) {key[i] = INF;visited[i] = 0;}key[0] = 0;parent[0] = -1;for (i = 0; i < n; i++) {min = INF;u = -1;for (j = 0; j < n; j++) {if (!visited[j] && key[j] < min) {min = key[j];u = j;}}if (u == -1) return -1;return mincost;}上面的代码实现了Prim算法,通过输入图的顶点数和边数,以及每条边的起点、终点和权值,计算得到最小生成树的最小权值总和。

数据结构(三十三)最小生成树(Prim、Kruskal)

数据结构(三十三)最小生成树(Prim、Kruskal)

数据结构(三⼗三)最⼩⽣成树(Prim、Kruskal) ⼀、最⼩⽣成树的定义 ⼀个连通图的⽣成树是⼀个极⼩的连通⼦图,它含有图中全部的顶点,但只有⾜以构成⼀棵树的n-1条边。

在⼀个⽹的所有⽣成树中,权值总和最⼩的⽣成树称为最⼩代价⽣成树(Minimum Cost Spanning Tree),简称为最⼩⽣成树。

构造最⼩⽣成树的准则有以下3条:只能使⽤该图中的边构造最⼩⽣成树当且仅当使⽤n-1条边来连接图中的n个顶点不能使⽤产⽣回路的边 对⽐两个算法,Kruskal算法主要是针对边来展开,边数少时效率会⾮常⾼,所以对于稀疏图有很⼤的优势;⽽Prim算法对于稠密图,即边数⾮常多的情况会更好⼀些。

⼆、普⾥姆(Prim)算法 1.Prim算法描述 假设N={V,{E}}是连通⽹,TE是N上最⼩⽣成树中边的集合。

算法从U={u0,u0属于V},TE={}开始。

重复执⾏下⾯的操作:在所有u属于U,v 属于V-U的边(u,v)中找⼀条代价最⼩的边(u0,v0)并加⼊集合TE,同时v0加⼊U,直到U=V为⽌。

此时TE中必有n-1条边,则T=(V,{TE})为N的最⼩⽣成树。

2.Prim算法的C语⾔代码实现/* Prim算法⽣成最⼩⽣成树 */void MiniSpanTree_Prim(MGraph G){int min, i, j, k;int adjvex[MAXVEX]; /* 保存相关顶点下标 */int lowcost[MAXVEX]; /* 保存相关顶点间边的权值 */lowcost[0] = 0;/* 初始化第⼀个权值为0,即v0加⼊⽣成树 *//* lowcost的值为0,在这⾥就是此下标的顶点已经加⼊⽣成树 */adjvex[0] = 0; /* 初始化第⼀个顶点下标为0 */for(i = 1; i < G.numVertexes; i++) /* 循环除下标为0外的全部顶点 */{lowcost[i] = G.arc[0][i]; /* 将v0顶点与之有边的权值存⼊数组 */adjvex[i] = 0; /* 初始化都为v0的下标 */}for(i = 1; i < G.numVertexes; i++){min = INFINITY; /* 初始化最⼩权值为∞, *//* 通常设置为不可能的⼤数字如32767、65535等 */j = 1;k = 0;while(j < G.numVertexes) /* 循环全部顶点 */{if(lowcost[j]!=0 && lowcost[j] < min)/* 如果权值不为0且权值⼩于min */{min = lowcost[j]; /* 则让当前权值成为最⼩值 */k = j; /* 将当前最⼩值的下标存⼊k */}j++;}printf("(%d, %d)\n", adjvex[k], k);/* 打印当前顶点边中权值最⼩的边 */lowcost[k] = 0;/* 将当前顶点的权值设置为0,表⽰此顶点已经完成任务 */for(j = 1; j < G.numVertexes; j++) /* 循环所有顶点 */{if(lowcost[j]!=0 && G.arc[k][j] < lowcost[j]){/* 如果下标为k顶点各边权值⼩于此前这些顶点未被加⼊⽣成树权值 */lowcost[j] = G.arc[k][j];/* 将较⼩的权值存⼊lowcost相应位置 */adjvex[j] = k; /* 将下标为k的顶点存⼊adjvex */}}}}Prim算法 3.Prim算法的Java语⾔代码实现package bigjun.iplab.adjacencyMatrix;/*** 最⼩⽣成树之Prim算法*/public class MiniSpanTree_Prim {int lowCost; // 顶点对应的权值public CloseEdge(Object adjVex, int lowCost) {this.adjVex = adjVex;this.lowCost = lowCost;}}private static int getMinMum(CloseEdge[] closeEdges) {int min = Integer.MAX_VALUE; // 初始化最⼩权值为正⽆穷int v = -1; // 顶点数组下标for (int i = 0; i < closeEdges.length; i++) { // 遍历权值数组,找到最⼩的权值以及对应的顶点数组的下标if (closeEdges[i].lowCost != 0 && closeEdges[i].lowCost < min) {min = closeEdges[i].lowCost;v = i;}}return v;}// Prim算法构造图G的以u为起始点的最⼩⽣成树public static void Prim(AdjacencyMatrixGraphINF G, Object u) throws Exception{// 初始化⼀个⼆维最⼩⽣成树数组minSpanTree,由于最⼩⽣成树的边是n-1,所以数组第⼀个参数是G.getVexNum() - 1,第⼆个参数表⽰边的起点和终点符号,所以是2 Object[][] minSpanTree = new Object[G.getVexNum() - 1][2];int count = 0; // 最⼩⽣成树得到的边的序号// 初始化保存相关顶点和相关顶点间边的权值的数组对象CloseEdge[] closeEdges = new CloseEdge[G.getVexNum()];int k = G.locateVex(u);for (int j = 0; j < G.getVexNum(); j++) {if (j!=k) {closeEdges[j] = new CloseEdge(u, G.getArcs()[k][j]);// 将顶点u到其他各个顶点权值写⼊数组中}}closeEdges[k] = new CloseEdge(u, 0); // 加⼊u到⾃⾝的权值0for (int i = 1; i < G.getVexNum(); i++) { // 注意,这⾥从1开始,k = getMinMum(closeEdges); // 获取u到数组下标为k的顶点的权值最短minSpanTree[count][0] = closeEdges[k].adjVex; // 最⼩⽣成树第⼀个值为uminSpanTree[count][1] = G.getVexs()[k]; // 最⼩⽣成树第⼆个值为k对应的顶点count++;closeEdges[k].lowCost = 0; // 下标为k的顶点不参与最⼩权值的查找了for (int j = 0; j < G.getVexNum(); j++) {if (G.getArcs()[k][j] < closeEdges[j].lowCost) {closeEdges[j] = new CloseEdge(G.getVex(k), G.getArcs()[k][j]);}}}System.out.print("通过Prim算法得到的最⼩⽣成树序列为: {");for (Object[] Tree : minSpanTree) {System.out.print("(" + Tree[0].toString() + "-" + Tree[1].toString() + ")");}System.out.println("}");}} 4.举例说明Prim算法实现过程 以下图为例: 测试类:// ⼿动创建⼀个⽤于测试最⼩⽣成树算法的⽆向⽹public static AdjacencyMatrixGraphINF createUDNByYourHand_ForMiniSpanTree() {Object vexs_UDN[] = {"V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7", "V8"};int arcsNum_UDN = 15;int[][] arcs_UDN = new int[vexs_UDN.length][vexs_UDN.length];for (int i = 0; i < vexs_UDN.length; i++) // 构造⽆向图邻接矩阵for (int j = 0; j < vexs_UDN.length; j++)if (i==j) {arcs_UDN[i][j]=0;} else {arcs_UDN[i][j] = arcs_UDN[i][j] = INFINITY;}arcs_UDN[0][5] = 11;arcs_UDN[1][2] = 18;arcs_UDN[1][6] = 16;arcs_UDN[1][8] = 12;arcs_UDN[2][3] = 22;arcs_UDN[2][8] = 8;arcs_UDN[3][4] = 20;arcs_UDN[3][6] = 24;arcs_UDN[3][7] = 16;arcs_UDN[3][8] = 21;arcs_UDN[4][5] = 26;arcs_UDN[4][7] = 7;arcs_UDN[5][6] = 17;arcs_UDN[6][7] = 19;for (int i = 0; i < vexs_UDN.length; i++) // 构造⽆向图邻接矩阵for (int j = i; j < vexs_UDN.length; j++)arcs_UDN[j][i] = arcs_UDN[i][j];return new AdjMatGraph(GraphKind.UDN, vexs_UDN.length, arcsNum_UDN, vexs_UDN, arcs_UDN);}public static void main(String[] args) throws Exception {AdjMatGraph UDN_Graph = (AdjMatGraph) createUDNByYourHand_ForMiniSpanTree();MiniSpanTree_Prim.Prim(UDN_Graph, "V0");} 输出为:通过Prim算法得到的最⼩⽣成树序列为: {(V0-V1)(V0-V5)(V1-V8)(V8-V2)(V1-V6)(V6-V7)(V7-V4)(V7-V3)} 分析算法执⾏过程:从V0开始:-count为0,k为0,closeEdges数组的-lowCost为{0 10 INF INF INF 11 INF INF INF},adjVex数组为{V0,V0,V0,V0,V0,V0,V0,V0,V0}-⽐较lowCost,于是k为1,adjVex[1]为V0,minSpanTree[0]为(V0,V1),lowCost为{0 0 INF INF INF 11 INF INF INF}-k为1,与V1的权值⾏⽐较,得到新的-lowCost为:{0 0 18 INF INF 11 16 INF 12},adjVex数组为{V0,V0,V1,V0,V0,V0,V1,V0,V1}-⽐较lowCost,于是k为5,adjVex[5]为V0,minSpanTree[1]为(V0,V5),lowCost为{0 0 18 INF INF 0 16 INF 12}-k为5,与V5的权值⾏⽐较,得到新的-lowCost为{0 0 18 INF 26 0 16 INF 12},adjVex数组为{V0,V0,V1,V0,V5,V0,V1,V0,V1}-⽐较lowCost,于是k为8,adjVex[8]为V1,minSpanTree[2]为(V1,V8),lowCost为{0 0 18 INF INF 0 16 INF 0}... 三、克鲁斯卡尔(Kruskal)算法 1.Kruskal算法描述 Kruskal算法是根据边的权值递增的⽅式,依次找出权值最⼩的边建⽴的最⼩⽣成树,并且规定每次新增的边,不能造成⽣成树有回路,直到找到n-1条边为⽌。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

// mygraph2.cpp : Defines the entry point for the console application.///*题目:用邻接表的形式表示图。

最小生成树编译器:visualc++ 6.0参考资料:《数据结构(用面向对象方法与c++语言描述)》尚未处理的边放在最小堆中,通过并査集的find运算,可以很快的判断任意一条边的两个端点是否来自同一个联通分量,是就舍去,不是就留下,通过并査集的union运算,将两棵树合二为一,直到成了一棵树P262-266并査集实现P235-239最小堆的实现P349-P350 图的模板基类P355-P356 用邻接表表示图P364-P366 图的广度优先和深度优先搜索P372 krusakal算法实现最小生成树*/#include "StdAfx.h"#include<iostream>#include<queue>#include <ASSERT.H>using namespace std;#define DefaultVertices 30//图的基类,主要包含初始化,虚函数,方便以后拓展template<class T,class E>class Graph{public:Graph(intsz=DefaultVertices){} //constructor~Graph(){} // destructorboolGraphEmpty(){ // isemptyif(numEdges==0)return true;elsereturn false;}boolGraphFull(){ //isfullif(numVertices==maxVertices||numEdges==maxVertices*(Vertices-1)/2)return true;elsereturn false;}intNumberOfVertices() // return the number of current vertices{returnnumVertices;}intNumberOfEdges() //return the number of current edges {returnnumEdges;}virtual T getValue(inti)=0;virtual E getWeight(int v1,int v2)=0;virtualintgetFirstNeighbor(int v)=0;virtualintgetNextNeighbor(intv,int w)=0;virtualboolinsertVertex(T& vertex)=0;virtualboolinsertEdge(int v1,int v2,E cost)=0;virtualboolremoveVertex(int v)=0;virtualboolremoveEdge(int v1,int v2)=0;intmaxVertices;intnumEdges;intnumVertices;virtualintgetVertexPos(T vertex)=0;};//边的结构体template<class T,class E>struct Edge{intdest; //存放的是指向那个E cost; //权值Edge<T,E> *link;Edge(){} //构造函数Edge(intnum,E weight):dest(num),cost(weight),link(NULL){}bool operator !=(Edge<T,E>& R){return (dest!=R.dest)?true:false;}};//顶点的结构体,包含数据,还有边template<class T,class E>struct Vertex{T data;Edge<T,E> *adj;};//用邻接矩阵表示的图的形式template<class T,class E>classGraphlnk:public Graph<T,E>{friendistream& operator>>(istream&in,Graphlnk<T,E>& G);friendostream& operator<<(ostream&out,Graphlnk<T,E>& G); public:Graphlnk(intsz=DefaultVertices); //构造函数~Graphlnk(); //析构函数T getValue(inti) //获得处于i位置的值{return (i>=0&&i<numVertices)?NodeTable[i].data:0;}E getWeight(int v1,int v2); //获得权值boolinsertVertex(T& vertex); //插入顶点boolremoveVertex(int v); //移除顶点boolinsertEdge(int v1,int v2,E cost); //插入边boolremoveEdge(int v1,int v2); //移除边intgetFirstNeighbor(int v);//获得第一个intgetNextNeighbor(intv,int w);//获得相邻的Vertex<T,E> *NodeTable;intgetVertexPos(T vertex){for(inti=0;i<numVertices;i++)if(NodeTable[i].data==vertex)returni;return -1;}};/**///建立空图template<class T,class E>Graphlnk<T,E>::Graphlnk(intsz){//thismaxVertices=sz;numVertices=0;numEdges=0;//创建顶点数组NodeTable=new Vertex<T,E>[maxVertices];if(NodeTable==NULL)cout<<"存储失败"<<endl;for(inti=0;i<maxVertices;i++)NodeTable[i].adj=NULL;};//destructor /template<class T,class E>Graphlnk<T,E>::~Graphlnk(){for(inti=0;i<numVertices;i++){Edge<T,E> *p=NodeTable[i].adj;while(p!=NULL){NodeTable[i].adj=p->link;delete p;p=NodeTable[i].adj;}}delete[] NodeTable;}//获取边的权值template<class T,class E>E Graphlnk<T,E>::getWeight(int v1,int v2) {if(v1!=-1&&v2!=-1){Edge<T,E> *p=NodeTable[v1].adj;while(p!=NULL&&p->dest!=v2){p=p->link;}if(p!=NULL)return p->cost;}return 0;}//插入顶点的函数实现template<class T,class E>boolGraphlnk<T,E>::insertVertex(T& vertex) {if(numVertices==maxVertices)return false;NodeTable[numVertices].data=vertex;numVertices++;return true;};//删除顶点的实现template<class T,class E>boolGraphlnk<T,E>::removeVertex(int v){if(numVertices==1||v<0||v>=numVertices)return false;Edge<T,E>*p,*s,*t;int k;//删除第v个边链表的顶点while(NodeTable[v].adj!=NULL){cout<<"测试顶点的数值"<<NodeTable[v].data<<endl;//cout<<"test"<<endl;p=NodeTable[v].adj;cout<<"p的权值"<<p->cost<<endl;k=p->dest;cout<<"k是邻接节点"<<k<<endl;//找对称存放的边结点s=NodeTable[k].adj;cout<<"s->cost 测试"<<s->cost<<endl;t=NULL;while(s!=NULL&&s->dest!=v){//cout<<t-<<"弄懂t算法"<<endl;t=s;s=s->link;cout<<"s->dest"<<s->dest<<endl;cout<<s->link<<"能显示吗"<<endl;cout<<"在while循环测"<<s->cost<<endl;}//删除堆存放的边结点cout<<"删除堆存放的边结点"<<endl;if(s!=NULL){if(t==NULL){cout<<"s->link的权值"<<s->link->cost<<endl;NodeTable[k].adj=s->link;cout<<"NodeTable[k].adjifceshi"<<NodeTable[k].adj->cost<<endl;}else{cout<<t->link->cost<<"之前"<<endl;cout<<s->link<<endl;t->link=s->link;//cout<<t->link->cost<<"之后"<<endl;}delete s;}//清除顶点v的边链表结点NodeTable[v].adj=p->link;delete p;numEdges--;}// cout<<"执行出来"<<endl;numVertices--;//填补cout<<"NodeTable[v].data"<<NodeTable[v].data<<endl;NodeTable[v].data=NodeTable[numVertices].data;p=NodeTable[v].adj=NodeTable[numVertices].adj;cout<<"p=NodeTable[v].adj=NodeTable[numVertices].adj "<<NodeTable[v].adj->cost<<endl;while(p!=NULL){// cout<<"死循环??"<<endl;// cout<<NodeTable[p->dest].data<<endl;s=NodeTable[p->dest].adj;while(s!=NULL)if(s->dest==numVertices){s->dest=v;break;}elses=s->link;p=p->link;}return true;};//移除边的函数的实现template<class T,class E>boolGraphlnk<T,E>::removeEdge(int v1,int v2){if(v1!=-1&&v2!=-1){Edge<T,E> *p=NodeTable[v1].adj,*q=NULL,*s=p;while(p!=NULL&&p->dest!=v2){q=p;p=p->link;}if(p!=NULL){if(p==s)NodeTable[v1].adj=p->link;elseq->link=p->link;delete p;}elsereturn false;p=NodeTable[v2].adj;q=NULL,s=p;while(p->dest!=v1){q=p;p=p->link;}if(p==s)NodeTable[v2].adj=p->link;elseq->link=p->link;delete p;return true;}return false;};//插入边的函数实现template<class T,class E>boolGraphlnk<T,E>::insertEdge(int v1,int v2,E weight){if(v1>=0&&v1<numVertices&&v2>=0&&v2<numVertices) {//v1对应边链表头指针Edge<T,E> *q,*p=NodeTable[v1].adj;//寻找邻接顶点v2while(p!=NULL&&p->dest!=v2)p=p->link;//找到此边不插入if(p!=NULL)return false;// 否则,创建新结点p=new Edge<T,E>;q=new Edge<T,E>;p->dest=v2;p->cost=weight;p->link=NodeTable[v1].adj;//链入v1边链表NodeTable[v1].adj=p;q->dest=v1;q->cost=weight;q->link=NodeTable[v2].adj;//链入v2边链表NodeTable[v2].adj=q;numEdges++;return true;}return 0;};//获得第一个邻接定点的位置template<class T,class E>intGraphlnk<T,E>::getFirstNeighbor(int v){//对应边链表第一个边节点if(v!=-1){//存在,返回第一个邻接顶点Edge<T,E> *p=NodeTable[v].adj;if(p!=NULL)//第一个邻接顶点不存在return p->dest;}return -1;};//输出某邻接顶点w的下一邻接顶点,思路同上template<class T,class E>intGraphlnk<T,E>::getNextNeighbor(intv,int w) {if(v!=-1){Edge<T,E> *p=NodeTable[v].adj;while(p!=NULL&&p->dest!=w)p=p->link;if(p!=NULL&&p->link!=NULL)return p->link->dest;}return -1;};//重载运算符template<class T,class E>istream& operator>>(istream&in,Graphlnk<T,E>& G){ int choose;cout<<"what do you want to do"<<endl;in>>choose;switch(choose){case 0: break;}}//重载运算template<class T,class E>ostream& operator<<(ostream&out,Graphlnk<T,E>& G) {for(inti=0;i<G.numVertices;i++)out<<G.NodeTable[i].data<<endl;return out;}//深度优先搜索template<class T,class E>void DFS(Graph<T,E>& G,T& v){inti,n=G.NumberOfVertices();intloc;bool *visited=new bool[n];for(i=0;i<n;i++)visited[i]=false;loc=G.getVertexPos(v);DFS(G,loc,visited);delete[] visited;}//深度优先具体实现template<class T,class E>void DFS(Graph<T,E>&G,intv,bool visited[]){//深度优先,cout<<G.getValue(v)<<" ";visited[v]=true;int w=G.getFirstNeighbor(v);while(w!=-1){if(visited[w]==false)DFS(G,w,visited);w=G.getNextNeighbor(v,w);}}//广度优先=函数template<class T,class E>void BFS(Graph<T,E>& G,T& v){inti,w,n=G.NumberOfVertices();bool *visited=new bool[n];for(i=0;i<n;i++)visited[i]=false;intloc=G.getVertexPos(v);cout<<G.getValue(loc)<<" ";visited[loc]=true;queue<int> q;q.push(loc);while(!q.empty()){intloc=q.front();q.pop();w=G.getFirstNeighbor(loc);while(w!=-1){if(visited[w]==false){cout<<G.getValue(w)<<" ";visited[w]=true;q.push(w);}w=G.getNextNeighbor(loc,w);}}delete[] visited;}//并査集intDefaultSize=10;classUFSets{public:UFSets(intsz=DefaultSize);~UFSets(){delete[] parent;}UFSets& operator=(UFSets& R);void Union(int Root1,int Root2);int Find(int x);voidWeightUnion(int Root1,int Root2);int *parent;int size;};//并査集构造函数UFSets::UFSets(intsz){size=sz;parent=new int[size];for(inti=0;i<size;i++)parent[i]=-1;}//并査集查找intUFSets::Find(int x){while(parent[x]>=0)x=parent[x];return x;}//union简单,但是好容易出现退化树的情况voidUFSets::Union(int Root1,int Root2){parent[Root1]+=parent[Root2];parent[Root2]=Root1;}//P265,为了避免出现退化的树,而用的算法,用加权的原则来改进union算法voidUFSets::WeightUnion(int Root1,int Root2){int r1=Find(Root1),r2=Find(Root2),temp;if(r1!=r2){temp=parent[r1]+parent[r2];if(parent[r1]>parent[r2]){parent[r1]=r2;parent[r2]=temp;}else{parent[r2]=r1;parent[r1]=temp;}}elseUnion(Root1,Root2);}//最小生成树边节点的类声明template<class T,class E> structMSTEdgeNode{//顶点的位置以及权值inttail,head;E key;//构造函数MSTEdgeNode():tail(-1),head(-1),key(0){}bool operator<=(MSTEdgeNode<T,E>& R){return key<=R.key;}bool operator>(MSTEdgeNode<T,E>& R){return key>R.key;}};//最小生成树template<class T,class E> classMinSpanTree{protected:MSTEdgeNode<T,E> *edgevalue;intmaxSize,n;public:MinSpanTree(intsz=DefaultSize-1):maxSize(sz),n(0){edgevalue=new MSTEdgeNode<T,E>[sz];}int Insert(MSTEdgeNode<T,E>& item);};//最小生成树的插入template<class T,class E>intMinSpanTree<T,E>::Insert(MSTEdgeNode<T,E>& item){cout<<item.tail<<" "<<item.head<<endl;return 0;}//P124~P125优先队列constintDefaultPQSize=50;template<class T>classPQueue{public:PQueue(intsz=DefaultPQSize); //构造函数~PQueue(){delete[] pqelements;} //析构函数bool Insert(T& x); //插入函数boolRemoveMin(T& x); //移除最小元素boolgetFront(T& x); //取出最小元素void makeEmpty(){count=0;} //制空队列boolIsEmpty() //判断是队列否为空{return (count==0)?true:false;}boolIsFull() //判断队列是否已满{return (count==maxSize)?true:false;}intgetSize() //获得队列目前大小{return count;}protected:T *pqelements; //dataint count; //当前队列个数intmaxSize; //队列最大值void adjust(); //调整函数};//最小优先级最烈的构造函数P125template<class T>PQueue<T>::PQueue(intsz):maxSize(sz),count(0){pqelements=new T[maxSize];assert(pqelements!=NULL);}//插入函数,插入到队尾P125template<class T>boolPQueue<T>::Insert(T& x){if(count==maxSize)return false;pqelements[count++]=x;adjust();return true;}//删除优先权值最小元素P126template<class T>boolPQueue<T>::RemoveMin(T& x){if(count==0)return false;x=pqelements[0];for(inti=1;i<count;i++)pqelements[i-1]=pqelements[i];count--;return true;}//取得最小优先权函数的值P126template<class T>boolPQueue<T>::getFront(T& x){if(count==0)return false;else{x=pqelements[0];return true;}}//P125~P126 将队尾元素按优先权调整到适当的位置,保持优先权不变template<class T>voidPQueue<T>::adjust(){T temp=pqelements[count-1];int j;for(j=count-2;j>=0;j--)if(pqelements[j]<=temp)break;elsepqelements[j+1]=pqelements[j];pqelements[j+1]=temp;}//P236 最小堆的类template<class E>classMinHeap:publicPQueue<E>{public:MinHeap(intsz=DefaultSize); //构造函数MinHeap(E arr[],int n); //重载构造函数~MinHeap(){delete[] heap;} //析构函数bool Insert(E& x); //插入函数boolRemoveMin(E& x); //移除最小值函数boolIsEmpty() //查看是否是空{return (currentSize==0)?true:false;}boolIsFull() //查看是否是满的{return (currentSize==maxHeapSize)?true:false;}void MakeEmpty() //将最小堆置成空{currentSize=0;}E getMin(); // 获取最小值void output(); //输出最小堆的元素,进行验证private:E* heap; //存放最小堆元素的数组intcurrentSize; //最小堆当前元素的个数intmaxHeapSize; //最小堆最多元素个数void siftDown(intstart,int m); //下滑调整为最小堆void siftUp(int start); //上滑调整为最小堆};//构造函数P237template<class E>MinHeap<E>::MinHeap(intsz){maxHeapSize=(DefaultSize<sz)?sz:DefaultSize;heap=new E[maxHeapSize];if(heap==NULL){cerr<<"123"<<endl;exit(1);}currentSize=0;}//最小堆的构造函数P237template<class E>MinHeap<E>::MinHeap(E arr[],int n){maxHeapSize=(DefaultSize<n)?n:DefaultSize;heap=new E[maxHeapSize];if(heap==NULL){cerr<<"123"<<endl;exit(1);}for(inti=0;i<n;i++)heap[i]=arr[i];currentSize=n;intcurrentPos=(currentSize-2)/2;while(currentPos>=0){siftDown(currentPos,currentSize-1);currentPos--;}}//最小堆的下滑调整P238template<class E>voidMinHeap<E>::siftDown(intstart,int m){inti=start,j=2*i+1;E temp=heap[i];while(j<=m){if(j<m&&heap[j]>heap[j+1])j++;if(temp<=heap[j])break;else{heap[i]=heap[j];i=j;j=2*j+1;}}heap[i]=temp;}//最小堆的上滑调整P238~P239template<class E>voidMinHeap<E>::siftUp(int start) {int j=start,i=(j-1)/2;E temp=heap[j];while(j>0){if(heap[i]<=temp)break;else{heap[j]=heap[i];j=i;i=(i-1)/2;}}heap[j]=temp;}//最小堆移除最小值也就是根P239 template<class E>boolMinHeap<E>::RemoveMin(E& x) {if(!currentSize){cout<<"Heap Empty"<<endl;return false;}x=heap[0];heap[0]=heap[currentSize-1];currentSize--;siftDown(0,currentSize-1);return true;}//最小堆的插入P239template<class E>boolMinHeap<E>::Insert(E& x){if(currentSize==maxHeapSize){cerr<<"Heap Full"<<endl;return false;}heap[currentSize]=x;siftUp(currentSize);currentSize++;return true;}//获得最小堆的根template<class E>E MinHeap<E>::getMin(){return heap[0];}//最小堆的输出template<class E>voidMinHeap<E>::output(){for(inti=0;i<currentSize;i++)cout<<heap[i]<<" ";cout<<endl;}//krusal算法,逐步寻找最小权值的边,然后连接template<class T,class E>voidKruskal(Graph<T,E>&G,MinSpanTree<T,E>& MST){MSTEdgeNode<T,E>ed;intu,v,count;//n是顶点的数目int n=G.NumberOfVertices();//m是边的数目int m=G.NumberOfEdges();MinHeap<MSTEdgeNode<T,E>> H(m);UFSets F(n);//并査集for(u=0;u<n;u++)for(v=u+1;v<n;v++)if(G.getWeight(u,v)!=0){// cout<<"u"<<u<<"v"<<v<<endl;// cout<<G.getWeight(u,v)<<"进行测试全知"<<endl;ed.tail=u;ed.head=v;ed.key=G.getWeight(u,v);H.Insert(ed);}count=1;//最小生成树加入边数计算cout<<"这是分割线"<<endl;while(count<n){//反复执行,取N-1条边H.RemoveMin(ed);//从最小对中退出具有最小值的边edu=F.Find(ed.tail);v=F.Find(ed.head);// cout<<"u"<<u<<"v"<<v<<endl;//取两定点所在党的根U,Vif(u!=v){cout<<"u"<<u<<"v"<<v<<endl;//合并,联通他们F.Union(u,v);MST.Insert(ed);count++;}}}//----------------------------------主函数----------------------//大多数测试都在step6中完成的,这一步主要完成最小生成树int main(){MinSpanTree<int,int>mst;Graphlnk<int,int> graph(7);int a[7]={0,1,2,3,4,5,6};for(inti=0;i<7;i++)graph.insertVertex(a[i]);//前面构建书上树已经成功,现在构建自己的树graph.insertEdge(0,1,100);graph.insertEdge(1,3,110);graph.insertEdge(3,4,60);graph.insertEdge(4,6,70);graph.insertEdge(5,6,80);graph.insertEdge(2,0,10);graph.insertEdge(2,5,30);graph.insertEdge(2,3,20);graph.insertEdge(2,4,50);graph.insertEdge(2,6,40);graph.insertEdge(5,0,90);//广度优先搜索cout<<"这是广度优先"<<endl;BFS(graph,a[0]);cout<<endl;//深度优先搜索,depth,是往下一直找cout<<"这是深度优先"<<endl;DFS(graph,a[0]);cout<<endl;//MSTEdgeNode<int,int>//根据书上的图所做的,kruskal算法Kruskal(graph,mst);cout<<"节点的数目"<<graph.NumberOfVertices()<<endl;cout<<"边的数目"<<graph.NumberOfEdges()<<endl;// if (graph.removeVertex(6))// cout<<"删除成功"<<endl;/* if (graph.removeVertex(3)){cout<<"删除成功"<<endl;}*/if (graph.removeVertex(1))cout<<"删除成功"<<endl;cout<<"节点的数目"<<graph.NumberOfVertices()<<endl;cout<<"边的数目"<<graph.NumberOfEdges()<<endl;//cout<<graph;return 0;}。

相关文档
最新文档