最小生成樹——Prim(普利姆)算法


【0】README

0.1) 本文總結於 數據結構與算法分析, 源代碼均為原創, 旨在 理解Prim算法的idea 並用 源代碼加以實現;
0.2)最小生成樹的基礎知識,參見 http://blog.csdn.net/pacosonswjtu/article/details/49947085


【1】Prim算法相關

1.1)計算最小生成樹的一種方法是使其連續地一步一步長成。在每一步, 都要吧一個節點當做根並往上加邊,這樣也就把相關聯的頂點加到增長中的樹上;
1.2)在算法中的任一時刻, 我們都可以看到一個已經添加到樹上的頂點集, 而其余頂點尚未加到這顆樹中。此時, 算法在每一階段都可以通過選擇邊(u, v),使得(u, v)的值是所有u 在樹上但v不在樹上的邊的值中的最小者, 而找出一個新的頂點並吧它添加到這顆樹中;
1.3)具體步驟概括為:

  • step1)給定一個頂點為根節點;
  • step2)每一步加一條邊和一個頂點; (這也迎合了 頂點個數-邊個數=1 );

1.4)看個荔枝:

對上圖的分析(Analysis):
A1)可以看到, 其實Prim算法基本上和求最短路徑的 Dijkstra算法一樣, 因此和前面一樣,我們對每一個頂點保留值 Dv和Pv 以及一個指標,指示該頂點是已知的還是未知的。這里,Dv是連接v 到已知頂點的最短邊的權, 而 Pv則是導致Dv改變的最后的頂點。
A2)算法的其余部分一樣, 唯一不同的是: ** 由於Dv的定義不同, 因此它的更新法則不一樣。事實上,Prim算法的更新法則比 Dijkstra算法簡單:在每一個頂點v被選取后, 對於每一個與 v 鄰接的未知的w, Dw=min(Dw, Cw,v);
這里寫圖片描述
對上圖的分析(Analysis):
A1)該算法整個的實現實際上和 Dijkstra算法的實現是一樣的, 對於 Dijkstra算法分析所做的每一件事都可以用到這里。 不過要注意, Prim算法是在無向圖上運行的, 因此當編寫代碼的時候要記住要吧每一條變都要放到兩個鄰接表中。
A2)**不用堆時的運行時間為O(|V|^2), 它對於稠密圖來說是最優的; 使用二叉堆的運行時間為 O(|E|log|V|), 它對於稀疏圖是一個好的界限;


【2】source code + printing results(將我的代碼打印結果 同 上圖中的手動模擬的prim算法的結果進行比較,你會發現, 它們的結果完全相同,這也證實了我的代碼的可行性)

2.1)download source code: https://github.com/pacosonTang/dataStructure-algorithmAnalysis/tree/master/chapter9/p237_prim
2.2)source code at a glance(for complete code , please click the given link above):

#include "prim.h"

//allocate the memory for initializing unweighted table
WeightedTable *initWeightedTable(int size)
{	
	WeightedTable* table;
	int i;

	table = (WeightedTable*)malloc(sizeof(WeightedTable) * size);
	if(!table)
	{
		Error("out of space ,from func initWeightedTable");
		return NULL;
	}

	for(i = 0; i < size; i++)
	{
		table[i] = makeEmptyWeightedTable();		
		if(!table[i])
			return NULL;
	}

	return table;
} 

// allocate the memory for every element in unweighted table  
WeightedTable makeEmptyWeightedTable()
{
	WeightedTable element;

	element = (WeightedTable)malloc(sizeof(struct WeightedTable));
	if(!element)
	{
		Error("out of space ,from func makeEmptyWeightedTable");
		return NULL;
	}	
	element->known = 0; // 1 refers to accessed , also 0 refers to not accessed
	element->distance = MaxInt;
	element->path = -1; // index starts from 0 and -1 means the startup vertex unreaches other vertexs

	return element;
}

// allocate the memory for storing index of  vertex in heap and let every element -1
int *makeEmptyArray(int size)
{
	int *array;
	int i;

	array = (int*)malloc(size * sizeof(int));
	if(!array)
	{
		Error("out of space ,from func makeEmptyArray");
		return NULL;
	}		
	for(i=0; i<size; i++)
		array[i] = -1;

	return array;
}

//computing the unweighted shortest path between the vertex under initIndex and other vertexs
void prim(AdjTable* adj, int size, int startVertex, BinaryHeap bh)
{		
	int adjVertex;	
	int tempDistance;
	WeightedTable* table;
	int vertex;		
	AdjTable temp; 	
	Distance tempDisStruct;
	int *indexOfVertexInHeap;
	int indexOfHeap;

	table = initWeightedTable(size);	 	
	tempDisStruct = makeEmptyDistance();
	indexOfVertexInHeap = makeEmptyArray(size);
	
	tempDisStruct->distance = table[startVertex-1]->distance;
    tempDisStruct->vertexIndex = startVertex-1;
	insert(tempDisStruct, bh, indexOfVertexInHeap); // insert the (startVertex-1) into the binary heap	

	table[startVertex-1]->distance = 0;// update the distance 
	table[startVertex-1]->path = 0;// update the path of starting vertex

	while(!isEmpty(bh))
	{		
		vertex = deleteMin(bh, indexOfVertexInHeap).vertexIndex; // return the minimal element in binary heap
		//printBinaryHeap(bh);

 		table[vertex]->known = 1; // update the vertex as accessed, also let responding known be 1
		temp = adj[vertex]->next;
		while(temp)
		{
			adjVertex = temp->index; 
			if(table[adjVertex]->known == 1) // judge whether table[adjVertex]->known is 1 or not
			{
				temp = temp->next;
				continue;
			}

			//tempDistance = table[vertex]->distance + temp->weight; // update the distance
			tempDistance = temp->weight;
			if(tempDistance < table[adjVertex]->distance)
			{
				table[adjVertex]->distance = tempDistance;
				table[adjVertex]->path = vertex; //update the path of adjVertex, also responding path evaluated as vertex							
				
				// key, we should judge whether adjVertex was added into the binary heap				
				//if true , obviously the element has been added into the binary heap(so we can't add the element into heap once again)
				if(indexOfVertexInHeap[adjVertex] != -1) 
				{
					indexOfHeap = indexOfVertexInHeap[adjVertex];
					bh->elements[indexOfHeap]->distance = tempDistance; // update the distance of corresponding vertex in binary heap
				}
				else // if not ture
				{
					tempDisStruct->distance = table[adjVertex]->distance;
					tempDisStruct->vertexIndex = adjVertex;
					insert(tempDisStruct, bh, indexOfVertexInHeap); // insert the adjVertex into the binary heap
				}
			}			 
			temp = temp->next;		
		}		
		printPrim(table, size, startVertex);		
		printBinaryHeap(bh);
		printf("\n");
	}		
	
	printf("\n");
} 

//print unweighted table
void printPrim(WeightedTable* table, int size, int startVertex)
{
	int i;	
	char *str[4] = 
	{
		"vertex",
		"known",
		"distance",
		"path"
	};

	printf("\n\t === storage table related to Prim alg as follows: === ");	
	printf("\n\t %6s%6s%9s%5s", str[0], str[1], str[2], str[3]);	
	for(i=0; i<size; i++)
	{		
		if(i != startVertex-1 && table[i]->path!=-1) 
			printf("\n\t %-3d   %3d   %5d      v%-3d  ", i+1, table[i]->known, table[i]->distance, table[i]->path+1);
		else if(table[i]->path == -1)
			printf("\n\t %-3d   %3d   %5d      %-3d  ", i+1, table[i]->known, table[i]->distance, table[i]->path);
		else
			printf("\n\t *%-3d  %3d   %5d      %-3d  ", i+1, table[i]->known, table[i]->distance, 0);
	}	 
}

int main()
{ 
	AdjTable* adj;	
	BinaryHeap bh;
	int size = 7;
	int capacity;
	int i;
	int j;	
	int startVertex;
	 
	int adjTable[7][7] = 
	{
		{0, 2, 4, 1, 0, 0, 0},
		{2, 0, 0, 3, 10, 0, 0},
		{4, 0, 0, 2, 0, 5, 0},
		{1, 3, 2, 0, 7, 8, 4},
		{0, 10, 0, 7, 0, 0, 6},
		{0, 0, 5, 8, 0, 0, 1},
		{0, 0, 0, 4, 6, 1, 0},
	};

	printf("\n\n\t ====== test for Prim alg finding weighted shortest path from adjoining table ======\n");
	adj = initAdjTable(size);		
	
	printf("\n\n\t ====== the initial weighted adjoining table is as follows:======\n");
	for(i = 0; i < size; i++)
	 	for(j = 0; j < size; j++)	
			if(adjTable[i][j])			
				insertAdj(adj, j, i, adjTable[i][j]); // insertAdj the adjoining table over
	
	printAdjTable(adj, size);	
	
	capacity = 7;
	bh = initBinaryHeap(capacity+1);
	//conducting prim alg to find minimum spanning tree(MST)
	startVertex = 1; // you should know our index for storing vertex starts from 0
	prim(adj, size, startVertex, bh);	
	
	return 0;
} 

2.3)printing results:

這里寫圖片描述
這里寫圖片描述
這里寫圖片描述


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM