数据结构之最小生成树
prime算法
普里姆(Prim)算法,是用來求加權連通圖的最小生成樹的算法。
基本思想
對于圖G而言,V是所有頂點的集合;現在,設置兩個新的集合U和T,其中U用于存放G的最小生成樹中的頂點,T存放G的最小生成樹中的邊。 從所有u?U,v?(V-U) (V-U表示出去U的所有頂點)的邊中選取權值最小的邊(u, v),將頂點v加入集合U中,將邊(u, v)加入集合T中,如此不斷重復,直到U=V為止,最小生成樹構造完畢,這時集合T中包含了最小生成樹中的所有邊。
鄰接矩陣實現
基本定義
class MatrixUDG {#define MAX 100#define INF (~(0x1<<31)) // 無窮大(即0X7FFFFFFF)private:char mVexs[MAX]; // 頂點集合int mVexNum; // 頂點數int mEdgNum; // 邊數int mMatrix[MAX][MAX]; // 鄰接矩陣public:// 創建圖(自己輸入數據)MatrixUDG();// 創建圖(用已提供的矩陣)//MatrixUDG(char vexs[], int vlen, char edges[][2], int elen);MatrixUDG(char vexs[], int vlen, int matrix[][9]);~MatrixUDG();// 深度優先搜索遍歷圖void DFS();// 廣度優先搜索(類似于樹的層次遍歷)void BFS();// prim最小生成樹(從start開始生成最小生成樹)void prim(int start);// 打印矩陣隊列圖void print();private:// 讀取一個輸入字符char readChar();// 返回ch在mMatrix矩陣中的位置int getPosition(char ch);// 返回頂點v的第一個鄰接頂點的索引,失敗則返回-1int firstVertex(int v);// 返回頂點v相對于w的下一個鄰接頂點的索引,失敗則返回-1int nextVertex(int v, int w);// 深度優先搜索遍歷圖的遞歸實現void DFS(int i, int *visited);};MatrixUDG是鄰接矩陣對應的結構體。
mVexs用于保存頂點,mVexNum是頂點數,mEdgNum是邊數;mMatrix則是用于保存矩陣信息的二維數組。例如,mMatrix[i][j]=1,則表示”頂點i(即mVexs[i])”和”頂點j(即mVexs[j])”是鄰接點;mMatrix[i][j]=0,則表示它們不是鄰接點。
prime算法
/** prim最小生成樹** 參數說明:* start -- 從圖中的第start個元素開始,生成最小樹*/ void MatrixUDG::prim(int start) {int min,i,j,k,m,n,sum;int index=0; // prim最小樹的索引,即prims數組的索引char prims[MAX]; // prim最小樹的結果數組int weights[MAX]; // 頂點間邊的權值// prim最小生成樹中第一個數是"圖中第start個頂點",因為是從start開始的。prims[index++] = mVexs[start];// 初始化"頂點的權值數組",// 將每個頂點的權值初始化為"第start個頂點"到"該頂點"的權值。for (i = 0; i < mVexNum; i++ )weights[i] = mMatrix[start][i];// 將第start個頂點的權值初始化為0。// 可以理解為"第start個頂點到它自身的距離為0"。weights[start] = 0;for (i = 0; i < mVexNum; i++){// 由于從start開始的,因此不需要再對第start個頂點進行處理。if(start == i)continue;j = 0;k = 0;min = INF;// 在未被加入到最小生成樹的頂點中,找出權值最小的頂點。while (j < mVexNum){// 若weights[j]=0,意味著"第j個節點已經被排序過"(或者說已經加入了最小生成樹中)。if (weights[j] != 0 && weights[j] < min){min = weights[j];k = j;}j++;}// 經過上面的處理后,在未被加入到最小生成樹的頂點中,權值最小的頂點是第k個頂點。// 將第k個頂點加入到最小生成樹的結果數組中prims[index++] = mVexs[k];// 將"第k個頂點的權值"標記為0,意味著第k個頂點已經排序過了(或者說已經加入了最小樹結果中)。weights[k] = 0;// 當第k個頂點被加入到最小生成樹的結果數組中之后,更新其它頂點的權值。for (j = 0 ; j < mVexNum; j++){// 當第j個節點沒有被處理,并且需要更新時才被更新。if (weights[j] != 0 && mMatrix[k][j] < weights[j])weights[j] = mMatrix[k][j];}}// 計算最小生成樹的權值sum = 0;for (i = 1; i < index; i++){min = INF;// 獲取prims[i]在mMatrix中的位置n = getPosition(prims[i]);// 在vexs[0...i]中,找出到j的權值最小的頂點。for (j = 0; j < i; j++){m = getPosition(prims[j]);if (mMatrix[m][n]<min)min = mMatrix[m][n];}sum += min;}// 打印最小生成樹cout << "PRIM(" << mVexs[start] << ")=" << sum << ": ";for (i = 0; i < index; i++)cout << prims[i] << " ";cout << endl; }kruskal算法
克魯斯卡爾(Kruskal)算法,是用來求加權連通圖的最小生成樹的算法。
基本思想:按照權值從小到大的順序選擇n-1條邊,并保證這n-1條邊不構成回路。
具體做法:首先構造一個只含n個頂點的森林,然后依權值從小到大從連通網中選擇邊加入到森林中,并使森林中不產生回路,直至森林變成一棵樹為止。
克魯斯卡爾算法分析
根據前面介紹的克魯斯卡爾算法的基本思想和做法,我們能夠了解到,克魯斯卡爾算法重點需要解決的以下兩個問題:
問題一 對圖的所有邊按照權值大小進行排序。
問題二 將邊添加到最小生成樹中時,怎么樣判斷是否形成了回路。
問題一很好解決,采用排序算法進行排序即可。
問題二,處理方式是:記錄頂點在”最小生成樹”中的終點,頂點的終點是”在最小生成樹中與它連通的最大頂點”(關于這一點,后面會通過圖片給出說明) 。然后每次需要將一條邊添加到最小生存樹時,判斷該邊的兩個頂點的終點是否重合,重合的話則會構成回路。 以下圖來進行說明:
在將
// 邊的結構體 class EData {public:char start; // 邊的起點char end; // 邊的終點int weight; // 邊的權重public:EData(){}EData(char s, char e, int w):start(s),end(e),weight(w){} };EData是鄰接矩陣邊對應的結構體。
class MatrixUDG {#define MAX 100#define INF (~(0x1<<31)) // 無窮大(即0X7FFFFFFF)private:char mVexs[MAX]; // 頂點集合int mVexNum; // 頂點數int mEdgNum; // 邊數int mMatrix[MAX][MAX]; // 鄰接矩陣public:// 創建圖(自己輸入數據)MatrixUDG();// 創建圖(用已提供的矩陣)//MatrixUDG(char vexs[], int vlen, char edges[][2], int elen);MatrixUDG(char vexs[], int vlen, int matrix[][9]);~MatrixUDG();// 深度優先搜索遍歷圖void DFS();// 廣度優先搜索(類似于樹的層次遍歷)void BFS();// prim最小生成樹(從start開始生成最小生成樹)void prim(int start);// 克魯斯卡爾(Kruskal)最小生成樹void kruskal();// 打印矩陣隊列圖void print();private:// 讀取一個輸入字符char readChar();// 返回ch在mMatrix矩陣中的位置int getPosition(char ch);// 返回頂點v的第一個鄰接頂點的索引,失敗則返回-1int firstVertex(int v);// 返回頂點v相對于w的下一個鄰接頂點的索引,失敗則返回-1int nextVertex(int v, int w);// 深度優先搜索遍歷圖的遞歸實現void DFS(int i, int *visited);// 獲取圖中的邊EData* getEdges();// 對邊按照權值大小進行排序(由小到大)void sortEdges(EData* edges, int elen);// 獲取i的終點int getEnd(int vends[], int i); };MatrixUDG是鄰接矩陣對應的結構體。
mVexs用于保存頂點,mVexNum是頂點數,mEdgNum是邊數;mMatrix則是用于保存矩陣信息的二維數組。例如,mMatrix[i][j]=1,則表示”頂點i(即mVexs[i])”和”頂點j(即mVexs[j])”是鄰接點;mMatrix[i][j]=0,則表示它們不是鄰接點。
References
Prim算法(二)之 C++詳解 - 如果天空不死 - 博客園
Kruskal算法(二)之 C++詳解 - 如果天空不死 - 博客園
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的数据结构之最小生成树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IOS之计算器实现
- 下一篇: Android手绘效果实现