Kruskal 算法实现

根据算法导论给出的算法实现。

代码如下:

1.h:

#ifndef _MST_KRUSKAL_H_
#define _MST_KRUSKAL_H_

struct edge
{
	int value;
	int x;
	int y;
//	int rank;
//	struct edge *p;
};

struct vertex
{
	struct vertex *p;
	int rank;
};
//quick sort

void quick_sort(void *data, int count, int size, int (*compare)(const void *, const void *));

//disjoint set
void make_set(struct vertex *e);
struct vertex * find_set(struct vertex *x);
void union_set(struct vertex *x, struct vertex *y);

//kruskal alogirthm

#endif
1.c:

#include "1.h"

void swap(void *p, void *q, int size)
{
	unsigned char *x = (unsigned char *)p;
	unsigned char *y = (unsigned char *)q;
	int i;
	for(i = 0; i < size; i++)
	{
		unsigned char tmp = x[i];
		x[i] = y[i];
		y[i] = tmp;
	}
}


int get_partition(void *data, int p, int q, int size, int (*compare)(const void *, const void *))
{
//	int x = data[q];
	int i;
	int j = p-1;
	void *x = data + q * size;
	for(i = p; i < q; i++)
	{
		void *c = data + i * size;
		if(compare(c, x) < 0)
		{
			j++;
			int k;
			void *s = data + j * size;
			swap(c, s, size);
		//	int tmp = data[i];
		//	data[i] = data[j];
		//	data[j] = tmp;
		}
	}

	j++;
	swap(data + j * size, x, size);
	return j;
}

void _quick_sort(void *data, int p, int q, int size, int (*compare)(const void *, const void *))
{
	if(p < q)
	{
		int r = get_partition(data, p, q, size, compare);
		_quick_sort(data, p, r-1, size, compare);
		_quick_sort(data, r+1, q, size, compare);
	}
}

void quick_sort(void *data, int count, int size, int (*compare)(const void *, const  void *))
{
	_quick_sort(data, 0, count -1, size, compare);
	
}

void make_set(struct vertex *v)
{
	v->p = v;
	v->rank = 0;
}

struct vertex *find_set(struct vertex *v)
{
	if(v->p != v)
	{
		v->p = find_set(v->p);
	}
	return v->p;
}

void union_set(struct vertex *x, struct vertex *y)
{
	struct vertex *a = find_set(x);
	struct vertex *b = find_set(y);
	if(a->rank < b->rank)
	{
		a->p = b;
	}
	else
	{
		b->p = a;
		if(b->rank == a->rank)
		{
			a->rank = a->rank + 1;
		}
	}
}


test.c

#include "1.h"
#include <stdio.h>

int number_of_vertices, number_of_edges;
struct edge myedges[100];
struct vertex myvertices[100];
struct edge resultedges[100];

int number_of_result_edges;
int minimum_total_cost;

int compare(const void *a, const void *b)
{
	struct edge *pA = (struct edge *)a;
	struct edge *pB = (struct edge *)b;
	if(pA->value > pB->value)
	{
		return 1;
	}
	else if(pA->value < pB->value)
	{
		return -1;
	}
	else
	{
		return 0;
	}
}

void get_data(void)
{
	scanf("%d %d", &number_of_vertices, &number_of_edges);
	int i;
	for(i = 0; i < number_of_edges; i++)
	{
		scanf("%d %d %d", &myedges[i].x, &myedges[i].y, &myedges[i].value);
	}
}
int main(void)
{
	get_data();	

	int i;
	for(i = 0; i < number_of_vertices; i++)
	{
		make_set(&myvertices[i]);
	}

	quick_sort(myedges, number_of_edges, sizeof(struct edge), compare);

	for(i = 0; i < number_of_edges; i++)
	{
		struct vertex *x = &myvertices[myedges[i].x];
		struct vertex *y = &myvertices[myedges[i].y];
		if(find_set(x) != find_set(y))
		{
			resultedges[number_of_result_edges] = myedges[i];
			number_of_result_edges++;
			minimum_total_cost += myedges[i].value;
			union_set(x, y);			
		}
	}	
	return 0;
}

执行结果:

(gdb) p resultedges 
$2 = {{value = 1, x = 6, y = 7}, {value = 2, x = 8, y = 2}, {value = 2, x = 5, y = 6}, {value = 4, x = 2, y = 5}, {
    value = 4, x = 0, y = 1}, {value = 7, x = 2, y = 3}, {value = 8, x = 7, y = 0}, {value = 9, x = 3, y = 4}, {
    value = 0, x = 0, y = 0} <repeats 92 times>}
(gdb) p minimum_total_cost 
$3 = 37

和书上给出的例子结果一样。


输入数据:

9 14
0 1 4
1 2 8
2 3 7
3 4 9
4 5 10
5 6 2
6 7 1
7 8 7
8 2 2
2 5 4
3 5 14
6 8 6
7 0 8
7 1 11


Kruskal算法是一种用于求解最小生成树的贪心算法。在MATLAB中,可以通过以下步骤实现Kruskal算法: 1. 将所有边按照权值从小到大排序。 2. 初始化一个空的集合,用于存储最小生成树的边。 3. 遍历排序后的边,如果当前边的两个端点不在同一个集合中,则将该边加入最小生成树的集合中,并将两个端点合并到同一个集合中。 4. 重复步骤3,直到最小生成树的边数等于节点数减一。 在MATLAB中,可以使用sort函数对边进行排序,使用并查集来实现集合的合并和查找操作。具体实现可以参考以下代码: % Kruskal算法实现 function [MST, cost] = kruskal(G) % G为邻接矩阵表示的图,MST为最小生成树的边集,cost为最小生成树的权值和 n = size(G, 1); % 节点数 edges = []; % 边集 for i = 1:n for j = i+1:n if G(i,j) > % 存在边 edges = [edges; i, j, G(i,j)]; % 添加边 end end end edges = sortrows(edges, 3); % 按照权值排序 parent = 1:n; % 初始化并查集 MST = []; % 初始化最小生成树的边集 cost = ; % 初始化最小生成树的权值和 for i = 1:size(edges,1) u = edges(i,1); v = edges(i,2); w = edges(i,3); pu = find(parent, u); % 查找u所在的集合 pv = find(parent, v); % 查找v所在的集合 if pu ~= pv % u和v不在同一个集合中 MST = [MST; u, v]; % 添加边 cost = cost + w; % 更新权值和 parent(pu) = pv; % 合并集合 end if size(MST,1) == n-1 % 边数达到节点数减一,退出循环 break; end end % 并查集的查找操作 function p = find(parent, x) p = x; while parent(p) ~= p p = parent(p); end % 并查集的合并操作 function parent = union(parent, x, y) px = find(parent, x); py = find(parent, y); parent(px) = py;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值