最小生成树(C语言)

article/2025/9/16 10:24:09

最小生成树问题(C语言)

所谓一个 带权图 的最小生成树,就是原图中边的权值最小的生成树 ,所谓最小是指边的权值之和小于或者等于其它生成树的边的权值之和。

kruskal

克鲁斯卡尔算法(Kruskal)是一种使用贪婪方法的最小生成树算法。 该算法初始将图视为森林,图中的每一个顶点视为一棵单独的树。 一棵树只与它的邻接顶点中权值最小且不违反最小生成树属性(不构成环)的树之间建立连边。

注意:一定要先排序!!

代码

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 10
typedef struct
{char letter;int id;
} letter_struct;
typedef struct
{letter_struct one;letter_struct two;int num;
} edge;edge a[MAXSIZE]= {{{'d',4},{'e',5},12},{{'a',1},{'c',3},10},{{'b',2},{'e',5},15},{{'a',1},{'b',2},18},{{'b',2},{'d',4},16},{{'c',3},{'d',4},20},{{'c',3},{'b',2},14},{{'a',1},{'d',4},28}};
int s[MAXSIZE] = {0,1,2,3,4,5};
void kruskal(edge a[MAXSIZE], int row,int column,int jiedian)
{int i,j;int oneid,twoid;int count = 0;for(i=0;i<column;i++){oneid = a[i].one.id;twoid = a[i].two.id;if(s[oneid]!=s[twoid])//说明不连通{for(j=0;j<column;j++){if(s[j]==s[twoid]){s[j]=s[oneid];}}printf("%c---%c:%d\n",a[i].one.letter,a[i].two.letter,a[i].num);count++;if(count>=jiedian-1) break;}}
}
/*排序*/
void simpleseselectsort(edge a[MAXSIZE],int row,int column,int jiedian)
{int i,j,k;edge *tmp = (edge *)malloc(sizeof(edge));for(i=0;i<column;i++){k=i;for(j=i+1;j<column;j++){if(a[j].num < a[k].num) k=j;}if(k!=i){tmp->num = a[i].num;tmp->one = a[i].one;tmp->two = a[i].two;a[i].num = a[k].num;a[i].one = a[k].one;a[i].two = a[k].two;a[k].num = tmp->num;a[k].one = tmp->one;a[k].two = tmp->two;}}
}int main()
{int i;int row = 3;int column = 8;int jiedian = 5;printf("排序前:\n");for(i=0;i<column;i++){printf("%c,%c,%d\n",a[i].one.letter,a[i].two.letter,a[i].num);}simpleseselectsort(a,row,column,jiedian);printf("排序后\n");for(i=0;i<column;i++){printf("%c,%c,%d\n",a[i].one.letter,a[i].two.letter,a[i].num);}printf("kruskal算法求得最小生成树\n");kruskal(a,row,column,jiedian);
}

截图

prim

普里姆算法在找最小生成树时,将顶点分为两类,一类是在查找的过程中已经包含在生成树中的顶点(假设为 A 类),剩下的为另一类(假设为 B 类)。

对于给定的连通网,起始状态全部顶点都归为 B 类。在找最小生成树时,选定任意一个顶点作为起始点,并将之从 B 类移至 A 类;然后找出 B 类中到 A 类中的顶点之间权值最小的顶点,将之从 B 类移至 A 类,如此重复,直到 B 类中没有顶点为止。所走过的顶点和边就是该连通图的最小生成树。

代码main.c

#include <stdio.h>
#include <stdlib.h>
#define FINITY 100
#include "sequence.h"//输入图基本信息
void inputinfo(edgeGraph *G)
{int k;char one,two;int num,oneid,twoid;printf("请输入结点个数:");scanf("%d",&G->jiedian);printf("请输入边数:");scanf("%d",&G->bian);int i,j;//初始化for(i=0;i<G->jiedian;i++){for(j=0;j<G->jiedian;j++){if(i==j) G->edges[i][j]=0;else G->edges[i][j] = FINITY;}}letter_struct shuzu[MAXSIZE] = {{'a',0},{'b',1},{'c',2},{'d',3},{'e',4}};for(i=0;i<G->jiedian;i++){G->vexs[i] = shuzu[i];}printf("请输入边信息:\n");for(k=0;k<G->bian;k++){scanf(" %c %c %d",&one,&two,&num);oneid = getid(one,G);twoid = getid(two,G);G->edges[oneid][twoid] = num;G->edges[twoid][oneid] = num;}return G;
}
//输出矩阵
void outputG(edgeGraph *G)
{int i,j;printf("\n矩阵是:\n");for(i=0;i<G->jiedian;i++){for(j=0;j<G->jiedian;j++){printf("%-5d",G->edges[i][j]);}printf("\n");}printf("\n");
}
//prim
void prim(sequence_queue *sq,int jiedian,int bian,char choose,edgeGraph *G,int count)
{if(count==G->jiedian-1){//read(sq);return ;}//选择的choose字符int chooseid = getid(choose,G);int i,j;char another;edge *tmp = (edge *)malloc(sizeof(edge));printf("你选择的%c的id为%d\n",choose,chooseid);for(j=0;j<jiedian;j++){if(G->edges[chooseid][j]!=FINITY && chooseid!=j){//printf("找到一个edge:id为%d和%d\n",chooseid,j);tmp->one.id = chooseid;tmp->one.letter = choose;tmp->two.id = j;tmp->two.letter = getid_char(j,G);tmp->num = G->edges[chooseid][j];push(sq,tmp);}}//read(sq);another = findmin(sq,count,G);printf("\n接下来找%c\n",another);prim(sq,jiedian,bian,another,G,count+1);
}int main()
{int i,j,k,num;char one,two;int oneid,twoid;char primchoose;edgeGraph *G = (edgeGraph *)malloc(sizeof(edgeGraph));inputinfo(G);outputG(G);sequence_queue *sq = (sequence_queue *)malloc(sizeof(sequence_queue));init(sq);printf("选择你要第一个开始的结点:");scanf(" %c",&primchoose);prim(sq,G->jiedian,G->bian,primchoose,G,0);
}
/*
a b 18
a c 10
c d 20
d e 12
b e 15
a d 28
c b 14
b d 16*/

队列sequence.h

#define MAXSIZE 20typedef struct
{char letter;//记录字符int id;//自己字符的id
} letter_struct;typedef struct
{letter_struct one; //记录边第一个顶点的信息letter_struct two;//记录边第二个顶点的信息int num;//记录边的权值
} edge;typedef edge datatype;
//队列
typedef struct{datatype a[MAXSIZE];//队列数组int front;//头指针int rear;//尾指针
}sequence_queue;
//定义图(邻接矩阵
typedef struct
{int jiedian;//结点个数int bian;//边个数letter_struct vexs[MAXSIZE]; //结点信息int edges[MAXSIZE][MAXSIZE];//邻接矩阵
} edgeGraph;//通过字符找id
int getid(char a,edgeGraph *G)
{int k;for(k=0;k<G->jiedian;k++){if(G->vexs[k].letter==a) return G->vexs[k].id;}
}
//通过id找字符
char getid_char(int id,edgeGraph *G)
{int k;for(k=0;k<G->jiedian;k++){if(G->vexs[k].id==id) return G->vexs[k].letter;}
}
//初始化队列
void init(sequence_queue *sq)
{sq->front=sq->rear=0;
}
//队列是否为空
int empty(sequence_queue *sq)
{return (sq->front==sq->rear?0:1);
}
//打印队列
void read(sequence_queue *sq)
{int i;if(!empty(sq)){printf("\n队列是空的!");exit(1);}else{for(i=sq->front;i<sq->rear;i++) printf("%c->%c:%d\n",sq->a[i].one.letter,sq->a[i].two.letter,sq->a[i].num);}
}
//队列pushyige边信息
void push(sequence_queue *sq,edge *x)
{if(sq->rear==MAXSIZE){printf("\n队列满了!");exit(1);}sq->a[sq->rear].num = x->num;sq->a[sq->rear].one = x->one;sq->a[sq->rear].two = x->two;sq->rear=sq->rear+1;
}
//队列中找到count到rear的最小权值边并交换信息到a[count]
char findmin(sequence_queue *sq,int count,edgeGraph *G)
{int i,k;k=count;edge *tmp = (edge *)malloc(sizeof(edge));for(i=count;i<sq->rear;i++){if(sq->a[i].num<sq->a[k].num){k=i;}}printf("最小的一组是:%c--%c:%d\n",sq->a[k].one.letter,sq->a[k].two.letter,sq->a[k].num);if(k!=count){tmp->one = sq->a[count].one;tmp->two = sq->a[count].two;tmp->num = sq->a[count].num;sq->a[count].one = sq->a[k].one;sq->a[count].two = sq->a[k].two;sq->a[count].num = sq->a[k].num;sq->a[k].one = tmp->one;sq->a[k].two = tmp->two;sq->a[k].num = tmp->num;}//read(sq);int oneid,twoid;oneid = getid(sq->a[count].one.letter,G);twoid = getid(sq->a[count].two.letter,G);G->edges[oneid][twoid] = FINITY;G->edges[twoid][oneid] = FINITY;return sq->a[count].two.letter;}void pop(sequence_queue *sq)
{if(sq->rear==sq->front){printf("空队列!");exit(1);}sq->front = sq->front+1;
}

截图

查看队列具体过程


http://chatgpt.dhexx.cn/article/VHrmdAkU.shtml

相关文章

最小生成树kruskal算法

最小生成树kruskal算法 概述算法分析代码 概述 克鲁斯卡尔 ( K r u s k a l ) (Kruskal) (Kruskal)算法是求连通网的最小生成树的另一种方法。与普里姆 ( P r i m ) (Prim) (Prim)算法不同&#xff0c;它的时间复杂度为 O ( e l o g e ) O(eloge) O(eloge)(e为网中的边数)&…

最小生成树:

定义&#xff1a; 将图中的 n 结点用 n-1 条边连接起来&#xff0c;使其各个边的权值之和最小的生成树。 普里姆算法&#xff1a; 从点的角度出发。 1、start 数组的值表示起始点的下标&#xff0c;start 的下标代表目的顶点&#xff1b;lowcost 数组的下标代表目的顶点&…

图——最小生成树

图——最小生成树 1. 基本概念 在一个连通无向图G(V, E)中&#xff0c;对于其中的每条边(u,v)∈E&#xff0c;赋予其权重w(u, v)&#xff0c;则最小生成树问题就是要在G中找到一个连通图G中所有顶点的无环子集T⊆E&#xff0c;使得这个子集中所有边的权重之和w(T) ∑ ( u , …

最小生成树的Kruskal算法-详解

最小生成树的Kruskal算法 一、 什么是最小生成树 1.1 最小生成树定义&#xff1a; 一个有 n 个结点的连通图的生成树是原图的极小连通子图&#xff0c;且包含原图中的所有 n 个结点&#xff0c;并且有保持图连通的最少的边。最小生成树可以用kruskal&#xff08;克鲁斯卡尔&a…

最小生成树(C语言简单实现)

最小生成树 本文参考自《大话数据结构》 一个连通图的生成树是一个极小的连通子图&#xff0c;它含有图中全部的顶点&#xff0c;但只有足以构成一棵树的n-1条边。我们把构造连通网的最小代价生成树称为最小生成树 。 找连通网的最小生成树&#xff0c;经典的有两种算法&#…

最小生成树怎么画?

介绍最小生成树的图形画法~以下图为例&#xff1a; 1、从1开始&#xff0c;以1为顶点画圈。在红色线经过的部分中&#xff0c;可见权重分别为6、1、5&#xff0c;最小权重为1。如下图。 2、以上图中得到的1、3为顶点的图中&#xff0c;继续画线&#xff0c;图为黄色线部分。经过…

最小生成树算法

最小生成树算法 生成树的概念最小生成树算法Prim算法Kruskal算法 生成树的概念 若图是连通的无向图或强连通的有向图&#xff0c;则从其中任一顶点出发&#xff0c;调用一次 d f s dfs dfs或者 b f s bfs bfs后&#xff0c;可以系统的访问图中所有顶点。若图是有根的有向图 &a…

【图】最小生成树

最小生成树&#xff1a;构造连通网的最小代价生成树。 最小生成树有两种算法&#xff1a;普利姆算法、克鲁斯卡尔算法。 普利姆&#xff08;Prim&#xff09;算法 加点&#xff0c;选择相邻点中边权最小的 需要两个一维数组&#xff0c;一个存权值&#xff0c;另一个存起始点…

最小生成树-Kruskal算法

数据结构:最小生成树-Kruskal算法 什么是最小生成树&#xff0c;最小生成树就是求图中把所有点都访问到的最短路径的长度 Kruskal算法采用的是边贪心思想&#xff0c;我们先大概讲一下它的大概思想&#xff0c;首先我们先假设先隐藏所有的边&#xff0c;这样每个点会成为一个连…

最小生成树(kruskal算法)

一、概述 最小生成树问题顾名思义&#xff0c;概括来说就是路修的最短。 接下来引入几个一看就明白的定义&#xff1a; 最小生成树相关概念&#xff1a; 带权图&#xff1a;边赋以权值的图称为网或带权图&#xff0c;带权图的生成树也是带权的&#xff0c;生成树T各边的权值…

最小生成树、最短路径树

一、最小生成树与最短路径树的区别 最小生成树能够保证整个拓扑图的所有路径之和最小&#xff0c;但不能保证任意两点之间是最短路径。 应用如网络部线&#xff0c;把所有的电脑(服务器&#xff1f;&#xff09;都连起来用的网线(光纤&#xff1f;&#xff09;最少&#xff0c…

【图解算法】最小生成树

今天我们介绍图论中的另一部分&#xff0c;最小生成树。 对图的最短路感兴趣的同学可以看&#xff1a; 【图解算法】一次解决最短路径问题 目录 1. 最小生成树简介2. Prim算法2.1 模板题2.2 思路模板2.3 代码实现2.3 prim 算法的优化 3. Kruskal算法3.1 模板题3.2 思路模板3.3…

数据结构—最小生成树

目录 一、生成树 二、最小生成树&#xff08;代价最小树&#xff09; 三、求最小生成树 1、Prim算法&#xff08;普里姆&#xff09; 2.Kruskal 算法&#xff08;克鲁斯卡尔&#xff09; 3.Prim算法和Kruskal算法对比 一、生成树 连通图的生成树是包含图中全部顶点的一个…

最小生成树详解

目录 最小生成树简介 什么是树 什么是生成树 什么是最小生成树 最小生成树的做法 Kruscal&#xff08;克鲁斯卡尔&#xff09;算法 思路 代码 其他算法 最小生成树简介 什么是树 树&#xff08;tree&#xff09;是一种特殊的图&#xff0c;一个图要成为树要满足三个条…

最小生成树的实现(C语言)

今天做洛谷的时候刷到好多图论的题&#xff0c;发现自己在这一方面算法的掌握还是有待提高啊。在这就先介绍最小生成树的算法吧。 最小生成树 最小生成树&#xff08;minimum spanning tree&#xff09;是由n个顶点&#xff0c;n-1条边&#xff0c;将一个连通图连接起来&…

详解: 最小生成树

详解: 最小生成树算法 最小生成树&#xff08;Minimum Spanning Tree, MST&#xff09;是在一个给定的无向图G(V, E)中求一棵树&#xff0c;使得这棵树有图G的所有顶点&#xff0c;且所有边都来自图G中的边&#xff0c;并且满足整棵树的边权之和最小. 最下生成树满足如下性质…

最小生成树

目录 一、最小生成树定义&#xff1a; 二、普里姆算法&#xff08;Prim&#xff09; 三、Kruskal算法&#xff08;克鲁斯卡尔&#xff09; 小结&#xff1a; 下一篇&#xff1a;最短路径算法 问题&#xff1a; 一、最小生成树定义&#xff1a; 对于一个带权连通无向图G(V,E)&am…

最小生成树——Prim算法(详细图解)

目录 最小生成树的概念 经典题目 prim算法简介 prim算法解析 &#xff08;详细图解&#xff09; 代码实现 代码实战 最小生成树的概念 在一给定的无向图G (V, E) 中&#xff0c;(u, v) 代表连接顶点 u 与顶点 v 的边&#xff0c;而 w(u, v) 代表此的边权重&#xff0c;若…

最小生成树入门(图解)

1.什么是最小生成树 来看百度百科的定义 一个有 n 个结点的连通图的生成树是原图的极小连通子图&#xff0c;且包含原图中的所有 n个结点&#xff0c;并且有保持图连通的最少的边。最小生成树可以用kruskal&#xff08;克鲁斯卡尔&#xff09;算法或prim&#xff08;普里姆&am…

最小生成树(Prim、Kruskal)算法,秒懂!

前言 在数据结构与算法的图论中&#xff0c;(生成)最小生成树算法是一种常用并且和生活贴切比较近的一种算法。但是可能很多人对概念不是很清楚&#xff0c;什么是最小生成树? 一个有 n 个结点的连通图的生成树是原图的极小连通子图&#xff0c;且包含原图中的所有 n 个结点&…