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

2023-11-05

目录

前言

一、克鲁斯卡尔算法构造过程

二、算法实现

1.辅助结构体、数组

2.算法核心

3.排序函数

总结


前言

承接上文普里姆算法,这里的克鲁斯卡尔算法是解决最短联通路径的另一种算法,细节就不多概述了,思想都是一样的,知识解决问题的出发点不一样


一、克鲁斯卡尔算法构造过程

1.首先克鲁斯卡尔算法是以边出发,通过比较边的大小来确定点

2.在联通网中将所有的边进行从小到大的排序

3.按次序输出边的两个点

4.重复3过程,知道全部的点都处理完

二、算法实现

1.辅助结构体、数组

这里需要将每条边所对应的点和权值都需要用一个结构体存储起来,方便后期的使用

代码如下(示例):

typedef struct
{
	VerType head;//边的始点
	VerType tail;//边的终点
	AreType lowcost;//最小边上的权值
}edge, * Edge;

2.算法核心

这里我将解析都写成注释了,这里就不一一进行赘述了,大家看代码就好了

代码如下(示例):

void Kruskal(Edge &E,Graph &G)//算法核心开始
{
	E = (Edge)malloc(sizeof(edge) * G.side);//开辟空间,有多少条边开辟多少空间
	VerType* vexset = (char*)malloc(sizeof(char) * G.vertex);//开辟一个辅助数组来判断点是否已经使用
	if (!E || !vexset)
		return ;

	for (int i = 0; i < G.vertex; i++)
	{
		vexset[i] = G.Ver[i];//将所有的点存入辅助数组中,后面进行判定
	}

	int num = 0;
	for (int i = 0; i < G.vertex; i++)//将有联系的边对应的两个点进行存储
	{
		for (int j = i; j < G.vertex; j++)
		{
			if (G.Are[i][j] != MaxInt)
			{
				E[num].lowcost = G.Are[i][j];
				E[num].head = G.Ver[i];
				E[num].tail = G.Ver[j];
				num++;
			}
		}
	}

	Sort(E,G);//将所有的边按照顺序排序,方便后面寻找点

	问题点:排序出现问题
	//for (int i = 0; i < G.side; i++)
	//{
	//	printf("%d%c%c ", E[i].lowcost,E[i].head,E[i].tail);//打印测试,说明排序出现问题!!
	//}
	/*printf("\n");*/

	for (int i = 0; i < G.side; i++)
	{
		int h = local_vertex(G, E[i].head);//头节点的位置
		int t = local_vertex(G, E[i].tail);//尾节点的位置
		char h1 = vexset[h];//找到辅助数组中的点
		char t1 = vexset[t];
		char hh = G.Ver[h];//通过图的点来打印
		char tt = G.Ver[t];

		if (h1 != t1)//只要我的辅助数组中的点没有全部相同说明还有点没有处理完
		{
			printf("%c%c ", hh, tt);
			for (int j = 0; j < G.vertex; j++)//通过此循环判断点是不是全部处理完
			{
				if (t1 == vexset[j])
				{
					vexset[j] = h1;
				}
			}
		}
	}
}

3.排序函数

这里我就用的最简单的冒泡,如果大家有更好的方法,那就用自己最好的方法就可以了

但是这里要注意,你将权值排序,那边所对应的点也要跟着移动

代码示例:

void Sort(Edge e,Graph G)//将边进行排序
{
	for (int i = 0; i < G.side - 1; i++)
	{
		for (int j = 0; j < G.side - 1 - i; j++)
		{
			if (e[j].lowcost > e[j + 1].lowcost)//排序过程中不仅要交换权值,还要将边所对应点进行交换
			{
				int temp = e[j].lowcost;
				e[j].lowcost = e[j + 1].lowcost;
				e[j + 1].lowcost = temp;

				char h = e[j].head;
				e[j].head = e[j + 1].head;
				e[j + 1].head = h;

				char t = e[j].tail;
				e[j].tail = e[j + 1].tail;
				e[j + 1].tail = t;
			}
		}
	}
}


总结

这里就不再仔细的去分析算法的过程了,如果要具体了解最小生成树可以看看之前的普里姆算法,核心都是一样的,只是处理的方式不一样,谢谢大家关注咯!(顺嘴提一下,没有图的基础这里确实看不懂,如果对图有疑问可以再看看我前面的图的创建)

这里我只是实现了这个算法,并没有优化,所以肯定是存在问题,希望大家多多理解

最后放一下所有的代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MaxInt 32767

typedef char VerType;
typedef int AreType;
typedef struct graph
{
	AreType side;
	AreType vertex;
    VerType* Ver;//顶点
	AreType** Are;
}Graph;

typedef struct
{
	VerType head;//边的始点
	VerType tail;//边的终点
	AreType lowcost;//最小边上的权值
}edge, * Edge;


int Local(Graph G, char vertex)
{
	for (int i = 0; i < G.vertex; i++)
	{
		if (G.Ver[i] == vertex)//遍历寻找边的位置
		{
			return i;
		}
	}
}

void Visit(Graph G)
{
	for (int i = 0; i < G.vertex; i++)
	{
		printf("%-2c", G.Ver[i]);//打印输入的顶点
	}
	printf("\n");
	for (int i = 0; i < G.vertex; i++)
	{
		for (int j = 0; j < G.vertex; j++)
		{
			if (G.Are[i][j] == MaxInt)
				printf("& ");//打印邻接矩阵
			else
				printf("%-2d", G.Are[i][j]);
		}
		printf("\n");
	}
}

void CreatGraph(Graph& G, FILE* fp)
{
	char input;
	G.Ver = (VerType*)malloc(sizeof(VerType) * G.vertex);
	G.Are = (AreType**)malloc(sizeof(AreType*) * G.vertex);
	for (int i = 0; i < G.vertex; i++)
	{
		G.Are[i] = (AreType*)malloc(sizeof(AreType) * G.vertex);
	}
	if ((!G.Ver) && (!G.Are))//分配不成功退出
		return;
	for (int i = 0; i < G.vertex; i++)
	{
		fscanf(fp, "%c\n", &input);
		G.Ver[i] = input;
	}
	for (int i = 0; i < G.vertex; i++)
	{
		for (int j = 0; j < G.vertex; j++)//对邻接矩阵进行初始化
		{
			G.Are[i][j] = MaxInt;
		}
	}
}

void WxW(Graph G, FILE* fp)  //邻接无向网
{
	char b1, b2;
	int n;
	for (int k = 0; k < G.side; k++)
	{
		fscanf(fp, "%c,%c,%d\n", &b1, &b2, &n);
		int i = Local(G, b1);
		int j = Local(G, b2);
		G.Are[i][j] = n;
		G.Are[j][i] = n;
	}
}

void Sort(Edge e,Graph G)//将边进行排序
{
	for (int i = 0; i < G.side - 1; i++)
	{
		for (int j = 0; j < G.side - 1 - i; j++)
		{
			if (e[j].lowcost > e[j + 1].lowcost)//排序过程中不仅要交换权值,还要将边所对应点进行交换
			{
				int temp = e[j].lowcost;
				e[j].lowcost = e[j + 1].lowcost;
				e[j + 1].lowcost = temp;

				char h = e[j].head;
				e[j].head = e[j + 1].head;
				e[j + 1].head = h;

				char t = e[j].tail;
				e[j].tail = e[j + 1].tail;
				e[j + 1].tail = t;
			}
		}
	}
}

int local_vertex(Graph G, VerType ver)//返回边的始点
{
	int i = 0;
	for (int i = 0; i < G.vertex; i++)
	{
		if (ver==G.Ver[i])
		{
			return i;
		}
	}
}


void Kruskal(Edge &E,Graph &G)//算法核心开始
{
	E = (Edge)malloc(sizeof(edge) * G.side);//开辟空间,有多少条边开辟多少空间
	VerType* vexset = (char*)malloc(sizeof(char) * G.vertex);//开辟一个辅助数组来判断点是否已经使用
	if (!E || !vexset)
		return ;

	for (int i = 0; i < G.vertex; i++)
	{
		vexset[i] = G.Ver[i];//将所有的点存入辅助数组中,后面进行判定
	}

	int num = 0;
	for (int i = 0; i < G.vertex; i++)//将有联系的边对应的两个点进行存储
	{
		for (int j = i; j < G.vertex; j++)
		{
			if (G.Are[i][j] != MaxInt)
			{
				E[num].lowcost = G.Are[i][j];
				E[num].head = G.Ver[i];
				E[num].tail = G.Ver[j];
				num++;
			}
		}
	}

	Sort(E,G);//将所有的边按照顺序排序,方便后面寻找点

	问题点:排序出现问题
	//for (int i = 0; i < G.side; i++)
	//{
	//	printf("%d%c%c ", E[i].lowcost,E[i].head,E[i].tail);//打印测试,说明排序出现问题!!
	//}
	/*printf("\n");*/

	for (int i = 0; i < G.side; i++)
	{
		int h = local_vertex(G, E[i].head);//头节点的位置
		int t = local_vertex(G, E[i].tail);//尾节点的位置
		char h1 = vexset[h];//找到辅助数组中的点
		char t1 = vexset[t];
		char hh = G.Ver[h];//通过图的点来打印
		char tt = G.Ver[t];

		if (h1 != t1)//不能是同一个点
		{
			printf("%c%c ", hh, tt);
			for (int j = 0; j < G.vertex; j++)//通过此循环判断点是不是全部处理完
			{
				if (t1 == vexset[j])
				{
					vexset[j] = h1;
				}
			}
		}
	}
}

int main()
{

	Graph G;
	Edge E;
	int d, b;
	FILE* fp;
	fp = fopen("abc.txt", "r");//读取名为abc的文本文件 
	if (fp == NULL)
		printf("文件为空!");
	fscanf(fp, "%d %d\n", &d, &b);
	G.vertex = d;
	G.side = b;
	CreatGraph(G, fp);
	WxW(G, fp);
	fclose(fp);
	Visit(G);
	Kruskal(E,G);
	return 0;;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

最小生成树之克鲁斯卡尔算法 的相关文章

随机推荐

  • 一文详细介绍什么是数据标注?

    机器学习和深度学习算法都依赖于数据 为构建可靠的人工智能模型 需要为算法提供结构良好且标注良好的数据 为了让机器学习算法学习如何完成特定任务 我们必须标注它们用于训练的数据 换句话说 标注数据很简单 但并不总是那么容易 幸运的是 我们将通过
  • 第一届世界区块链大会·三点钟峰会(W.B.C)在澳门开幕 万人峰会大咖云集明星嘉年华

    2018年4月23日晚 以 技术重构世界 为主题的第一届世界区块链大会 三点钟峰会 W B C 在中国澳门威尼斯人大酒店隆重开幕 为期三天 大会由世界区块链联合协会首倡 世界区块链大会组委会 三点钟 深创学院主办 深圳大学区块链研究院 银河
  • 解决org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.spring

    从svn上取下来的之前一直在开发的项目 因为项目我是中途接手的 所以同步下来 配置好tomcat 运行的时候报错 Cannot find class com lhzxt dhub MyExceptionHandler for bean wi
  • JavaScript基础(Dom操作)

    目录 一 BOM模型 1 1 BOM可实现功能 二 Window对象的常用属性 2 1 Window对象的常用方法 2 1 1 open 和close 方法 三 History对象 四 Location对象 五 Document对象的常用方
  • tab页过多,展现按钮可左右移动tab页

    1 结果如下图 tab太多 一行放不下 右侧展现左右按钮 鼠标移上tab页可左右移动 2 代码 功能按钮过多时 可左右移动 param id 按钮区域id param dom 按钮元素 param btnclass 按钮样式 param m
  • this指针详解

    什么是this指针 this是指向实例化对象本身时候的一个指针 里面存储的是对象本身的地址 通过该地址可以访问内部的成员函数和成员变量 一个对象的this指针并不是对象本身的一部分 其不会影响sizeof 对象 的结果 this指针的用处
  • 设计一个windows应用程序,定义一个Student类,包含学号和姓名两个字段,并定义一个班级类ClassList

    设计一个windows应用程序 定义一个Student类 包含学号和姓名两个字段 并定义一个班级类ClassList 该类包含一个Student集合 使用索引器访问该集合 1 创建一个Windows应用程序Myproject6 1 2 设计
  • vue自定义$confirm弹窗确认组件

    前言 1 Vue extend 使用基础 Vue 构造器 创建一个 子类 参数是一个包含组件选项的对象 vue单文件经过webpack打包之后是一个组件示例对象 因此可以传到Vue extend中生成一个包含此组件的类 2 new VueC
  • 关闭window10状态栏热点资讯

    前言 最近window10更新了 在桌面右下角的工具栏出现气温的小图标 占用了工具栏位置 挺不爽的 想关闭它 解决 1 在气温图标上 点击鼠标右键 然后选择资讯和兴趣 在弹出的下级菜单中选择 关闭
  • VC++6.0 没用atlstr.h 怎么办

    在VC 6 0中配置WTL9 0 提示没有atlstr h 这个文件 怎么办呢 于是把atlmisc h这个文件 复制一份 把名称改成atlstr h 不就OK了 又可使用CString 这个恶心的东西了 编绎一下试试 提示 error C
  • CSS选择器器练习之餐厅小游戏答案和解析(下)

    17 small last child 伪类选择器 last child选择最后一个子元素 18 plate nth child 3 伪类选择器 nth child 选择第n个子元素 19 bento nth last child 3 伪类
  • linux命令行将已有项目提交到github

    用git是在windows下用git的图形化界面进行操作的 这次有一个写了几天的小项目想提交到git上 linux命令行下面没有图形化的界面 所以全部需要git命令来操作 实践之后 主要是下面几个步骤 1 登陆github 创建一个repo
  • Layui之选项卡案例 详细易懂

    本期精彩 利用Layui框架实现动态选项卡 继上一篇已经实现了左边的树形菜单栏 这一关卡我们已通过 接下来就是实现右边的动态选项卡的关卡 上个关卡的效果及链接 链接 http t csdn cn tYccL 目录 本期精彩 利用Layui框
  • Android JNI开发从0到1,java调C,C调Java,保姆级教程详解

    前些天发现了一个蛮有意思的人工智能学习网站 8个字形容一下 通俗易懂 风趣幽默 感觉非常有意思 忍不住分享一下给大家 点击跳转到教程 第一步首先配置Android studio的NDK开发环境 首先在Android studio中下载NDK
  • 3.5.1 ASM规划及实现

    最后更新2021 08 14 AMS规划 规划涉及到几个参数 它们之间互相影响 如果需要修改其中一个 注意是否需要同时修改其它几个 下面是几个重要参数及其概念 Memory Pool size共享内存池的大小 使用同一共享内存池的分区数量
  • 贷后联动管控指标与差异化案件的分配逻辑

    在风控精细化运营的当下 贷后工作的开展 越来越需要精细化管理 如何做好相关的精细化管理工作 首先我们从这些贷后相关的名词如下开始熟悉 贷后基本催收名词解释 Flow Rate 迁移率就是在贷后资产评估里最重要的报表了 比如计算M0到M1的迁
  • shell脚本获取当前ip地址

    需求 shell脚本里我需要根据不同的ip地址做出不同的操作 因此我需要在shell脚本里获取当前主机的ip地址 我需要获取到192 168 1 111这个ip地址 方法1 ifconfig grep inet 地址 grep 192 16
  • (十五)视频处理、不用事先训练

    十五 视频处理 不用事先训练 本文的代码的功能是 可以对人物视频进行操作 不用预先耗时训练模型 效率极高 可进行视频处理 使用了人工智能的算法 注 请移步最新博文 十八 一 主要功能 以下的Python代码的功能 选择视频 主要包括 1 对
  • 图解数据结构与算法-搜索与回溯

    前言 本博客是leetcode上图解算法数据结构 LeetBook 力扣 LeetCode 全球极客挚爱的技术成长平台的刷题记录 可能存在错误 仅供参考 主要记录刷题过程的思路 错误 代码以及总结 更详细的解答可以直接看上面这本书 如发现错
  • 最小生成树之克鲁斯卡尔算法

    目录 前言 一 克鲁斯卡尔算法构造过程 二 算法实现 1 辅助结构体 数组 2 算法核心 3 排序函数 总结 前言 承接上文普里姆算法 这里的克鲁斯卡尔算法是解决最短联通路径的另一种算法 细节就不多概述了 思想都是一样的 知识解决问题的出发