图的应用——最小生成树(Kruskal算法)和(Prim算法)

一、一些概念的理解:

生成树:一个连通图的生成树是原图的极小连通图,它包含原图中的所有顶点,而且有尽可能少的边。也就意味着对于生成树来说,若砍去他的一条边,就会使生成树变成一个非连通图;若给他增加一条边,就会形成图中的一个回路。

最小生成树:

1、概念:

对于一个带权的连通图(即网络),如何找出一棵生成树,使得各边上的权值总和达到最小。

2、原则:

(1)必须只使用该网络中的边来构造

(2)必须只使用且仅适用n-1条边来连接网络中的n个顶点

(3)不能使用产生回路的边

3、算法:
(1)克鲁斯卡尔算法(Kruskal):

将各边的权值从小到大排列,依次连接符合原则且最小的边。

核心操作:father[i]

#pragma once
#include"AllHead.h"
#include<stdlib.h>
#include<search.h>
#define MAXSIZE 10 

struct EdgeNode
{
	int x;
	int y;
	int weight;
};
template<class T,class E>
class Grap
{
private:
	T *VerticesList;  //顶点元素
	E **Edge;         //动态的二维数组
	int maxVertices;  //预定最多的顶点个数
	int numVertices;  //记录元素的个数
	int numEdge;      //记录边的个数
public:
	Grap(int sz = 0):maxVertices(sz>MAXSIZE?sz:MAXSIZE),numVertices(0),numEdge(0)
	{
		int i,j;
		Edge = new E*[maxVertices];
		for(i = 0;i<maxVertices;++i)
		{
			Edge[i] = new E[maxVertices];
		}
		VerticesList = new T[maxVertices];
		for(i=0;i<maxVertices;++i)
		{
			VerticesList[i] = '#';
		}
		for(i = 0;i<maxVertices;i++)
		{
			for(j = 0;j<maxVertices;++j)
				Edge[i][j] = 0;
		}
	}
	Grap(T ar[],int sz):maxVertices(sz),numVertices(sz),numEdge(0)
	{
		int i,j;
		Edge = new E*[maxVertices];
		for(i = 0;i<maxVertices;++i)
		{
			Edge[i] = new E[maxVertices];
		}
		VerticesList = new T[maxVertices];
		for(i=0;i<maxVertices;++i)
		{
			VerticesList[i] = ar[i];
		}
		for(i = 0;i<maxVertices;i++)
		{
			for(j = 0;j<maxVertices;++j)
				Edge[i][j] = 0;
		}
	}
public:
	int GetVerticespos(T x)
	{
		int i;
		for(i = 0;i<numVertices;++i)
		{
			if(VerticesList[i] == x)
				return i;
		}
		return -1;
	}
	int NumberOfVertices()
	{return numVertices;}
	int NumberOfEdge()
	{return numEdge;}
public:
	int RemoveEdge(T x1,T x2)
	{
		int v1 = GetVerticespos(x1);
		int v2 = GetVerticespos(x2);
		if(v1 == -1||v2 == -1)
			return -1;
		Edge[v1][v2] = 0;
		Edge[v2][v1] = 0;
		--numEdge;
		return OK;
	}
	int RemoveVertex(T x)
	{
		int v = GetVerticespos(x);
		if(v == -1)
		{
			cout<<"结点不存在..."<<endl;
			return ERROR;
		}
		int i,j,tempedge = 0;
		for(int i=0; i<numVertices; ++i)
		{
			if(Edge[v][i] != 0)
				tempedge++;
		}
		VerticesList[v] = VerticesList[numVertices - 1];
		for(i = 0;i<numVertices;++i)
		{
			Edge[v][i] = Edge[numVertices - 1][i];
		}
		for(j = 0;j<numVertices;++j)
		{
			Edge[j][v] = Edge[j][numVertices - 1];
		}
		--numVertices;
		numEdge -= tempedge; 
	}
	int GetNextNeighbor(T x1,T x2)
	{
		int i;
		int v1 = GetVerticespos(x1);//头 
		int v2 = GetVerticespos(x2);//第一个子
		if(v1 == -1||v2 == -1)
		{
			cout<<"有个顶点不存在...";
			return ERROR;
		}
		if(Edge[v1][v2] == 0)
		{
			cout<<"第一条线并不存在....";
			return ERROR;
		}
		for(i = v2+1;i<numVertices;++i)
		{
			if(Edge[v1][i] == 1)
				return i;
		}
		cout<<"没有下一个顶点....";
		return -1;
	}
	int GetFirstNeighbor(T x)
	{
		int i;
		int v = GetVerticespos(x);
		if(v == -1)
		{
			cout<<"没有这个结点..."<<endl;
		}
		else
		{
			for(i=0;i<numVertices;++i)
			{
				if(Edge[v][i] == 1)
					return i;
			}
		}
		return -1;
	}
	int InsertEdge(T x1,T x2,int weight)
	{
		int v1 = GetVerticespos(x1);
		int v2 = GetVerticespos(x2);
		if(v1 != -1&&v2 != -1)
		{
			Edge[v1][v2] = weight;
			Edge[v2][v1] = weight;
			++numEdge;
			return OK;
		}
		else
			return ERROR;
	}
	int InsertVertices(T x)
	{
		if(numVertices >= maxVertices)
		{
			cout<<"空间已满(Insert)........"<<endl;
			return ERROR; 
		}
		VerticesList[numVertices++] = x;
		return OK;
	}
	void ShowGrap()
	{
		int i,j;
		cout<<"   ";
		for(i=0;i<numVertices;++i)
		{
			cout<<VerticesList[i]<<"  ";
		}
		cout<<endl;
		for(i = 0;i<numVertices;i++)
		{
			cout<<VerticesList[i]<<"  ";
			for(j = 0;j<numVertices;++j)
				cout<<Edge[i][j]<<"  ";
			cout<<endl;
		}
	}
	bool Is_Same(int father[],int i,int j)
	{
		while(father[i] != i)
		{
			i = father[i];
		}
		while(father[j] != j)
		{
			j = father[j];
		}
		return i == j;
	}
	void Mark_Same(int father[],int i,int j)
	{
		while(father[i]!=i)
		{
			i = father[i];
		}
		while(father[j]!=j)
		{
			j = father[j];
		}
		father[j] = i;
	}
	void Kruskal()
	{

		int k = 0;
		int n = numVertices;
		EdgeNode *reminfo = new EdgeNode[(n*(n-1))/2];
		for(int i=0;i<numVertices;++i)
		{
			for(int j=i;j<numVertices;++j)
			{
				if(Edge[i][j]!=0)
				{
					reminfo[k].x = i;
					reminfo[k].y = j;
					reminfo[k].weight = Edge[i][j];
					k++;
				}
					
			}
		}
		/用一个结构体数组将有权的边存起来。
		qsort(reminfo,k,sizeof(EdgeNode),compare);
		int *father = new int[k];//这个是核心!!!
		for(int i=0;i<k;i++)
		{
			father[i] = i;
		}
		int v1,v2;
		for(int i=0;i<k;++i)
		{
			if(!Is_Same(father,reminfo[i].x,reminfo[i].y))
			{
				v1 = reminfo[i].x;
			    v2 = reminfo[i].y;
			    cout<<i<<':'<<VerticesList[v1]<<"-->"<<VerticesList[v2]<<':'<<reminfo[i].weight<<endl;
				Mark_Same(father,v1,v2);
			}
		}
	}
};
//注意这个函数必须写到外面。
int compare(const void* w1,const void* w2)
{
	return ((*(EdgeNode*)w1).weight - (*(EdgeNode*)w2).weight);
}

主函数:

#include"grap.h"
int main()
{
	Grap<char,int> gp1;
	cout<<"======================================"<<endl;
	gp1.InsertVertices('A');
	gp1.InsertVertices('B');
	gp1.InsertVertices('C');
	gp1.InsertVertices('D');
	gp1.InsertVertices('E');
	gp1.InsertVertices('F');
	gp1.InsertEdge('A','B',6);
    gp1.InsertEdge('A','C',1);
	gp1.InsertEdge('A','D',5);
	gp1.InsertEdge('B','C',5);
	gp1.InsertEdge('D','C',5);
	gp1.InsertEdge('E','C',6);
	gp1.InsertEdge('F','C',4);
	gp1.InsertEdge('B','E',3);
	gp1.InsertEdge('E','F',6);
	gp1.InsertEdge('D','F',2);
	gp1.ShowGrap();
	cout<<"-------------------------------"<<endl;
	gp1.Kruskal();
	return 0;
}

(2)普利姆算法(Prim)

从指定的一个点开始,链接权值最小的边,两个顶点合并遍历所有点,找权值最小的边,再相连,在合并(这个过程中不可以连上形成回路的边)......直到所有点都连完了。

核心操作是:增加两个数组:lowcost[i]和mst[i]
#pragma once
#include"AllHead.h"
#define MAXSIZE 10 
#define MAX_COST 0x7FFFFFFF
template<class T,class E>
class Grap
{
private:
	T *VerticesList;  //顶点元素
	E **Edge;         //动态的二维数组
	int maxVertices;  //预定最多的顶点个数
	int numVertices;  //记录元素的个数
	int numEdge;      //记录边的个数
public:
	Grap(int sz = 0):maxVertices(sz>MAXSIZE?sz:MAXSIZE),numVertices(0),numEdge(0)
	{
		int i,j;
		Edge = new E*[maxVertices];
		for(i = 0;i<maxVertices;++i)
		{
			Edge[i] = new E[maxVertices];
		}
		VerticesList = new T[maxVertices];
		for(i=0;i<maxVertices;++i)
		{
			VerticesList[i] = '#';
		}
		for(i = 0;i<maxVertices;i++)
		{
			for(j = 0;j<maxVertices;++j)
				Edge[i][j] = MAX_COST;
		}
		for(i = 0;i<maxVertices;++i)
		{
			for(j = 0;j<maxVertices;++j)
			{
				if(i == j)
				{
					Edge[i][j] = 0;
				}
			}

		}
	}
	Grap(T ar[],int sz):maxVertices(sz),numVertices(sz),numEdge(0)
	{
		int i,j;
		Edge = new E*[maxVertices];
		for(i = 0;i<maxVertices;++i)
		{
			Edge[i] = new E[maxVertices];
		}
		VerticesList = new T[maxVertices];
		for(i=0;i<maxVertices;++i)
		{
			VerticesList[i] = ar[i];
		}
		for(i = 0;i<maxVertices;i++)
		{
			for(j = 0;j<maxVertices;++j)
				Edge[i][j] = 0;
		}
	}
public:
	int GetVerticespos(T x)
	{
		int i;
		for(i = 0;i<numVertices;++i)
		{
			if(VerticesList[i] == x)
				return i;
		}
		return -1;
	}
	int NumberOfVertices()
	{return numVertices;}
	int NumberOfEdge()
	{return numEdge;}
public:
	int RemoveEdge(T x1,T x2)
	{
		int v1 = GetVerticespos(x1);
		int v2 = GetVerticespos(x2);
		if(v1 == -1||v2 == -1)
			return -1;
		Edge[v1][v2] = 0;
		Edge[v2][v1] = 0;
		--numEdge;
		return OK;
	}
	int RemoveVertex(T x)
	{
		int v = GetVerticespos(x);
		if(v == -1)
		{
			cout<<"结点不存在..."<<endl;
			return ERROR;
		}
		int i,j,tempedge = 0;
		for(int i=0; i<numVertices; ++i)
		{
			if(Edge[v][i] != 0)
				tempedge++;
		}
		VerticesList[v] = VerticesList[numVertices - 1];
		for(i = 0;i<numVertices;++i)
		{
			Edge[v][i] = Edge[numVertices - 1][i];
		}
		for(j = 0;j<numVertices;++j)
		{
			Edge[j][v] = Edge[j][numVertices - 1];
		}
		--numVertices;
		numEdge -= tempedge; 
	}
	int GetNextNeighbor(T x1,T x2)
	{
		int i;
		int v1 = GetVerticespos(x1);//头 
		int v2 = GetVerticespos(x2);//第一个子
		if(v1 == -1||v2 == -1)
		{
			cout<<"有个顶点不存在...";
			return ERROR;
		}
		if(Edge[v1][v2] == 0)
		{
			cout<<"第一条线并不存在....";
			return ERROR;
		}
		for(i = v2+1;i<numVertices;++i)
		{
			if(Edge[v1][i] == 1)
				return i;
		}
		cout<<"没有下一个顶点....";
		return -1;
	}
	int GetFirstNeighbor(T x)
	{
		int i;
		int v = GetVerticespos(x);
		if(v == -1)
		{
			cout<<"没有这个结点..."<<endl;
		}
		else
		{
			for(i=0;i<numVertices;++i)
			{
				if(Edge[v][i] == 1)
					return i;
			}
		}
		return -1;
	}
	int GetWeight(int v1,int v2)
	{
		if(v1 == -1||v2 == -1)
			return MAX_COST;
		return Edge[v1][v2];
	}
	int InsertEdge(T x1,T x2,int weight)
	{
		int v1 = GetVerticespos(x1);
		int v2 = GetVerticespos(x2);
		if(v1 != -1&&v2 != -1)
		{
			Edge[v1][v2] = weight;
			Edge[v2][v1] = weight;
			++numEdge;
			return OK;
		}
		else
			return ERROR;
	}
	int InsertVertices(T x)
	{
		if(numVertices >= maxVertices)
		{
			cout<<"空间已满(Insert)........"<<endl;
			return ERROR; 
		}
		VerticesList[numVertices++] = x;
		return OK;
	}
	void ShowGrap()
	{
		int i,j;
		cout<<"   ";
		for(i=0;i<numVertices;++i)
		{
			cout<<VerticesList[i]<<"  ";
		}
		cout<<endl;
		for(i = 0;i<numVertices;i++)
		{
			cout<<VerticesList[i]<<"  ";
			for(j = 0;j<numVertices;++j)
			{
				if(Edge[i][j] == MAX_COST)
				{
					cout<<"@  ";
				}
				else
				{
				    cout<<Edge[i][j]<<"  ";
				}
			}
			cout<<endl;
		}
	}
	void Prim(T x)
	{
		int begin,end;
		E cost;
		int n = numVertices;
		E *lowcost = new E[n];
		int *mst = new int[n];
		assert(lowcost != NULL&&mst != NULL);
		int k = GetVerticespos(x);
		for(int i=0;i<n;++i)
		{
			if(i != k)
			{
				lowcost[i] = GetWeight(k,i);//把起始点的权逐个放到lowcost的数组里
				mst[i] = k;
			}
			else
			{
				lowcost[i] = 0;
			}
		}
		for(int i=0;i<n-1;++i)
		{
			int min = MAX_COST;//记录上次一x为顶点的边的权值
			int min_index = -1;//记录上次一x为顶点的边的终点索引号
			for(int j=0;j<n;++j)
			{
				if(lowcost[j]!=0 && lowcost[j]<min)
				{
					min = lowcost[j];
					min_index = j;
				}
			}
			//打印信息;
			begin = mst[min_index];
			end = min_index;
			cout<<VerticesList[begin]<<"--->"<<VerticesList[end]<<':'<<min<<endl;
			//合并顶点。
			lowcost[min_index] = 0;
			for(int j = 0;j<n;++j)
			{
				cost = GetWeight(min_index,j);
				if(cost < lowcost[j])
				{
					lowcost[j] = cost;
					mst[j] = min_index;
				}
			}
		}
		delete[]lowcost;
		delete[] mst;
	}

};

主函数:

#include"MinSpanTree.h"
int main()
{
	Grap<char,int> MinST;
	MinST.InsertVertices('A');
	MinST.InsertVertices('B');
	MinST.InsertVertices('C');
	MinST.InsertVertices('D');
	MinST.InsertVertices('E');
	MinST.InsertVertices('F');
	MinST.InsertEdge('A','B',6);
	MinST.InsertEdge('A','C',1);
	MinST.InsertEdge('A','D',5);
	MinST.InsertEdge('C','B',5);
	MinST.InsertEdge('E','B',3);
        MinST.InsertEdge('C','E',6);
	MinST.InsertEdge('C','F',4);
	MinST.InsertEdge('D','F',2);
	MinST.InsertEdge('C','D',5);
	MinST.InsertEdge('E','F',6);
	MinST.ShowGrap();
	MinST.Prim('A');
	return 0;
}



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值