数据结构:最小生成树和最短路径

总代码:

#include <stdio.h>
#include <malloc.h>

//表示无穷 
#define MAX 100000

typedef struct net
{
	int **weights;
	int numNode;
}*netPtr;

netPtr netInit(int paraNodes,int **paraArray)
{
	int i,j;
	
	//全是动态的,都要malloc 
	netPtr resultNet = (netPtr)malloc(sizeof(struct net));
	resultNet->weights = (int**)malloc(paraNodes*sizeof(int*));
	for(i = 0;i < paraNodes;i ++)
	{
		resultNet->weights[i] = (int*)malloc(paraNodes*sizeof(int));
	}
	
	//纯纯拷贝 
	resultNet->numNode = paraNodes;
	for(i = 0;i < paraNodes;i ++)
		for(j = 0;j < paraNodes;j ++)
			resultNet->weights[i][j] = paraArray[i][j];
			
	return resultNet;
}

//后面一个参数单纯是为了选择用哪个算法而已 
void PrimOrDijkstra(netPtr paraNet,int paraAlgorithm)
{
	int i,j,tempBestNode,minDistance,resultCost;
	int *visited,*parent,*distant;
	int numNodes = paraNet->numNode;
	
	//这里是用来存放是否访问过、父节点、最短距离的数组 
	visited = (int*)malloc(sizeof(int) * paraNet->numNode);
	parent = (int*)malloc(sizeof(int) * paraNet->numNode);
	distant = (int*)malloc(sizeof(int) * paraNet->numNode);
	
	//我们默认起始点为0开始构建。 
	int source = 0;
	
	//初始化
	for(i = 0;i < paraNet->numNode;i ++)
	{
		visited[i] = 0;
		parent[i] = source;
		distant[i] = paraNet->weights[source][i];
	}
	
	distant[source] = 0;
	visited[source] = 1;
	parent[source] = -1;
	
	//算法开始,第一个结点已经在网中了,我们只需循环n-1次 
	for(i = 0;i < numNodes-1;i ++)
	{
		/*第一步,即第一个循环,实现要找到与目前结点
		项链且路径最短的那个结点为最佳结点*/
		minDistance = MAX;
		for(j = 0;j < numNodes;j ++)
		{
			if(distant[j] < minDistance && visited[j] == 0)
			{
				minDistance = distant[j];
				tempBestNode = j;
			}
		}
		//找到之后就表示他以及被放问过了,即已经入网了 
		visited[tempBestNode] = 1;
		
		/*第二步,是最佳结点要帮组其他结点了*/
		for(j = 0;j < numNodes;j ++)
		{
			//在网中直接下一个 
			if(visited[j] == 1)
			{
				continue;
			}
			
			/*后面的话初始化的时候,我们把图里面的0表示不连通直接转换为MAX无穷大了
			所有,无穷大即不连通的话直接下一个*/ 
			if(paraNet->weights[tempBestNode][j] >= MAX)
			{
				continue; 
			}
			
			//这里算法出现一点点分支 0是最短路径,1是最小生成树 
			if(paraAlgorithm == 0)
			{
				/*最短路径呢,是这样的:如果从始结点到最佳结点加上最佳结点到j结点
				这两者的距离比始节点直接到j结点的距离还要短,那么就肯定选第一种方法啊
				所以说就开始改变到j的最小距离,改变j的父节点为当前最佳结点。*/ 
				for(j = 0;j < numNodes;j ++) 
				{
					if(distant[tempBestNode] + paraNet->weights[tempBestNode][j] < distant[j])
					{
						distant[j] = paraNet->weights[tempBestNode][j] + distant[tempBestNode];
						parent[j] = tempBestNode;
					}
				}
			}
			
			if(paraAlgorithm == 1)
			{
				/*最小生成唯一不同的,是不用加上从始结点到最佳结点的距离了,我们要的是最小代价构建网
				所以不用加上之前的距离了,有更小距离的就可以直接帮助*/ 
				for(j = 0;j < numNodes;j ++) 
				{
					if(paraNet->weights[tempBestNode][j] < distant[j])
					{
						distant[j] = paraNet->weights[tempBestNode][j];
						parent[j] = tempBestNode;
					}
				}
			}
			 
		}
	}
	
	printf("the parent of each node: ");
	//打印父节点 
	for(i = 0; i < numNodes; i++) 
	{
		printf("%d, ", parent[i]);
	}
	printf("\r\n");
	
	if(paraAlgorithm == 0) 
	{
		/*最短路径算法distant里面存储的就是0到每各结点的最短路径
		所以直接打印就好*/ 
		printf("From node 0, path length to all nodes are: ");
		for(i = 0; i < numNodes; i++) 
		{
			printf("%d: %d, ", i, distant[i]);
		}
	} 
	if(paraAlgorithm == 1) 
	{
		/*最小生成树里面distant存储的其实是每个结点到父节点的距离
		,除了source,每个结点都有唯一一个父节点,所以把他们加起来就是
		总的代价*/ 
		resultCost = 0;
		for(i = 0; i < numNodes; i++) 
		{
			resultCost += distant[i];
			printf("cost of node %d is %d, total = %d\r\n", i, distant[i], resultCost);
		}
		printf("Finally, the total cost is %d.\r\n ", resultCost);
	}

	printf("\r\n");

}

netPtr constructSampleNet() 
{
	int i, j;
	int myGraph[6][6] = 
	{ 
		{0, 6, 1, 5, 0, 0},
		{6, 0, 5, 0, 3, 0}, 
		{1, 5, 0, 5, 6, 4}, 
		{5, 0, 5, 0, 0, 2}, 
		{0, 3, 6, 0, 0, 6},
		{0, 0, 4, 2, 6, 0}
	};
	int** tempPtr;
	int numNodes = 6;
	printf("Preparing data\r\n");
		
	tempPtr = (int**)malloc(numNodes * sizeof(int*));
	for (i = 0; i < numNodes; i ++) 
	{
		tempPtr[i] = (int*)malloc(numNodes * sizeof(int));
	}
	
	for (i = 0; i < numNodes; i ++) 
	{
		for (j = 0; j < numNodes; j ++) 
		{
			if (myGraph[i][j] == 0) 
			{
				tempPtr[i][j] = MAX;
			}
			else 
			{
				tempPtr[i][j] = myGraph[i][j];
			}
		}
	}
 
	printf("Data ready\r\n");
	
	netPtr resultNetPtr = netInit(numNodes, tempPtr);
	return resultNetPtr;
}

void testPrim() 
{
	netPtr tempNetPtr = constructSampleNet();
	printf("=====Dijkstra algorithm=====\r\n");
	PrimOrDijkstra(tempNetPtr, 0);
	printf("=====Prim algorithm=====\r\n");
	PrimOrDijkstra(tempNetPtr, 1);
}
int main()
{
	testPrim();
} 

总结:最小生成树与最短路径的区别以及实现方法. 最小生成树能够保证整个拓扑图的所有路径之和最小,但不能保证任意两点之间是最短路径。. 最短路径是从一点出发,到达目的地的路径最小。. 1. 最小生成树. 最小生成树有两种算法来得到:Prims算法和Kruskal算法。. Kruskal算法:根据边的加权值以递增的方式,一次找出加权值最低的边来构建最小生成树,而且规定:每次添加的边不能造成生成树有回路,知道找到N-1个边为止。. Prims算法:以每次加入一个的临界边来建立最小生成树,直到找到N-1个边为止。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值