日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数据结构之最小生成树

發(fā)布時(shí)間:2024/7/23 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构之最小生成树 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

prime算法

普里姆(Prim)算法,是用來求加權(quán)連通圖的最小生成樹的算法。

基本思想
對(duì)于圖G而言,V是所有頂點(diǎn)的集合;現(xiàn)在,設(shè)置兩個(gè)新的集合U和T,其中U用于存放G的最小生成樹中的頂點(diǎn),T存放G的最小生成樹中的邊。 從所有u?U,v?(V-U) (V-U表示出去U的所有頂點(diǎn))的邊中選取權(quán)值最小的邊(u, v),將頂點(diǎn)v加入集合U中,將邊(u, v)加入集合T中,如此不斷重復(fù),直到U=V為止,最小生成樹構(gòu)造完畢,這時(shí)集合T中包含了最小生成樹中的所有邊。

鄰接矩陣實(shí)現(xiàn)

基本定義

class MatrixUDG {#define MAX 100#define INF (~(0x1<<31)) // 無窮大(即0X7FFFFFFF)private:char mVexs[MAX]; // 頂點(diǎn)集合int mVexNum; // 頂點(diǎn)數(shù)int mEdgNum; // 邊數(shù)int mMatrix[MAX][MAX]; // 鄰接矩陣public:// 創(chuàng)建圖(自己輸入數(shù)據(jù))MatrixUDG();// 創(chuàng)建圖(用已提供的矩陣)//MatrixUDG(char vexs[], int vlen, char edges[][2], int elen);MatrixUDG(char vexs[], int vlen, int matrix[][9]);~MatrixUDG();// 深度優(yōu)先搜索遍歷圖void DFS();// 廣度優(yōu)先搜索(類似于樹的層次遍歷)void BFS();// prim最小生成樹(從start開始生成最小生成樹)void prim(int start);// 打印矩陣隊(duì)列圖void print();private:// 讀取一個(gè)輸入字符char readChar();// 返回ch在mMatrix矩陣中的位置int getPosition(char ch);// 返回頂點(diǎn)v的第一個(gè)鄰接頂點(diǎn)的索引,失敗則返回-1int firstVertex(int v);// 返回頂點(diǎn)v相對(duì)于w的下一個(gè)鄰接頂點(diǎn)的索引,失敗則返回-1int nextVertex(int v, int w);// 深度優(yōu)先搜索遍歷圖的遞歸實(shí)現(xiàn)void DFS(int i, int *visited);};

MatrixUDG是鄰接矩陣對(duì)應(yīng)的結(jié)構(gòu)體。
mVexs用于保存頂點(diǎn),mVexNum是頂點(diǎn)數(shù),mEdgNum是邊數(shù);mMatrix則是用于保存矩陣信息的二維數(shù)組。例如,mMatrix[i][j]=1,則表示”頂點(diǎn)i(即mVexs[i])”和”頂點(diǎn)j(即mVexs[j])”是鄰接點(diǎn);mMatrix[i][j]=0,則表示它們不是鄰接點(diǎn)。

prime算法

/** prim最小生成樹** 參數(shù)說明:* start -- 從圖中的第start個(gè)元素開始,生成最小樹*/ void MatrixUDG::prim(int start) {int min,i,j,k,m,n,sum;int index=0; // prim最小樹的索引,即prims數(shù)組的索引char prims[MAX]; // prim最小樹的結(jié)果數(shù)組int weights[MAX]; // 頂點(diǎn)間邊的權(quán)值// prim最小生成樹中第一個(gè)數(shù)是"圖中第start個(gè)頂點(diǎn)",因?yàn)槭菑膕tart開始的。prims[index++] = mVexs[start];// 初始化"頂點(diǎn)的權(quán)值數(shù)組",// 將每個(gè)頂點(diǎn)的權(quán)值初始化為"第start個(gè)頂點(diǎn)"到"該頂點(diǎn)"的權(quán)值。for (i = 0; i < mVexNum; i++ )weights[i] = mMatrix[start][i];// 將第start個(gè)頂點(diǎn)的權(quán)值初始化為0。// 可以理解為"第start個(gè)頂點(diǎn)到它自身的距離為0"。weights[start] = 0;for (i = 0; i < mVexNum; i++){// 由于從start開始的,因此不需要再對(duì)第start個(gè)頂點(diǎn)進(jìn)行處理。if(start == i)continue;j = 0;k = 0;min = INF;// 在未被加入到最小生成樹的頂點(diǎn)中,找出權(quán)值最小的頂點(diǎn)。while (j < mVexNum){// 若weights[j]=0,意味著"第j個(gè)節(jié)點(diǎn)已經(jīng)被排序過"(或者說已經(jīng)加入了最小生成樹中)。if (weights[j] != 0 && weights[j] < min){min = weights[j];k = j;}j++;}// 經(jīng)過上面的處理后,在未被加入到最小生成樹的頂點(diǎn)中,權(quán)值最小的頂點(diǎn)是第k個(gè)頂點(diǎn)。// 將第k個(gè)頂點(diǎn)加入到最小生成樹的結(jié)果數(shù)組中prims[index++] = mVexs[k];// 將"第k個(gè)頂點(diǎn)的權(quán)值"標(biāo)記為0,意味著第k個(gè)頂點(diǎn)已經(jīng)排序過了(或者說已經(jīng)加入了最小樹結(jié)果中)。weights[k] = 0;// 當(dāng)?shù)趉個(gè)頂點(diǎn)被加入到最小生成樹的結(jié)果數(shù)組中之后,更新其它頂點(diǎn)的權(quán)值。for (j = 0 ; j < mVexNum; j++){// 當(dāng)?shù)趈個(gè)節(jié)點(diǎn)沒有被處理,并且需要更新時(shí)才被更新。if (weights[j] != 0 && mMatrix[k][j] < weights[j])weights[j] = mMatrix[k][j];}}// 計(jì)算最小生成樹的權(quán)值sum = 0;for (i = 1; i < index; i++){min = INF;// 獲取prims[i]在mMatrix中的位置n = getPosition(prims[i]);// 在vexs[0...i]中,找出到j(luò)的權(quán)值最小的頂點(diǎn)。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)算法,是用來求加權(quán)連通圖的最小生成樹的算法。

基本思想:按照權(quán)值從小到大的順序選擇n-1條邊,并保證這n-1條邊不構(gòu)成回路。
具體做法:首先構(gòu)造一個(gè)只含n個(gè)頂點(diǎn)的森林,然后依權(quán)值從小到大從連通網(wǎng)中選擇邊加入到森林中,并使森林中不產(chǎn)生回路,直至森林變成一棵樹為止。

克魯斯卡爾算法分析

根據(jù)前面介紹的克魯斯卡爾算法的基本思想和做法,我們能夠了解到,克魯斯卡爾算法重點(diǎn)需要解決的以下兩個(gè)問題:
問題一 對(duì)圖的所有邊按照權(quán)值大小進(jìn)行排序。
問題二 將邊添加到最小生成樹中時(shí),怎么樣判斷是否形成了回路。

問題一很好解決,采用排序算法進(jìn)行排序即可。

問題二,處理方式是:記錄頂點(diǎn)在”最小生成樹”中的終點(diǎn),頂點(diǎn)的終點(diǎn)是”在最小生成樹中與它連通的最大頂點(diǎn)”(關(guān)于這一點(diǎn),后面會(huì)通過圖片給出說明) 。然后每次需要將一條邊添加到最小生存樹時(shí),判斷該邊的兩個(gè)頂點(diǎn)的終點(diǎn)是否重合,重合的話則會(huì)構(gòu)成回路。 以下圖來進(jìn)行說明:

在將

// 邊的結(jié)構(gòu)體 class EData {public:char start; // 邊的起點(diǎn)char end; // 邊的終點(diǎn)int weight; // 邊的權(quán)重public:EData(){}EData(char s, char e, int w):start(s),end(e),weight(w){} };

EData是鄰接矩陣邊對(duì)應(yīng)的結(jié)構(gòu)體。

class MatrixUDG {#define MAX 100#define INF (~(0x1<<31)) // 無窮大(即0X7FFFFFFF)private:char mVexs[MAX]; // 頂點(diǎn)集合int mVexNum; // 頂點(diǎn)數(shù)int mEdgNum; // 邊數(shù)int mMatrix[MAX][MAX]; // 鄰接矩陣public:// 創(chuàng)建圖(自己輸入數(shù)據(jù))MatrixUDG();// 創(chuàng)建圖(用已提供的矩陣)//MatrixUDG(char vexs[], int vlen, char edges[][2], int elen);MatrixUDG(char vexs[], int vlen, int matrix[][9]);~MatrixUDG();// 深度優(yōu)先搜索遍歷圖void DFS();// 廣度優(yōu)先搜索(類似于樹的層次遍歷)void BFS();// prim最小生成樹(從start開始生成最小生成樹)void prim(int start);// 克魯斯卡爾(Kruskal)最小生成樹void kruskal();// 打印矩陣隊(duì)列圖void print();private:// 讀取一個(gè)輸入字符char readChar();// 返回ch在mMatrix矩陣中的位置int getPosition(char ch);// 返回頂點(diǎn)v的第一個(gè)鄰接頂點(diǎn)的索引,失敗則返回-1int firstVertex(int v);// 返回頂點(diǎn)v相對(duì)于w的下一個(gè)鄰接頂點(diǎn)的索引,失敗則返回-1int nextVertex(int v, int w);// 深度優(yōu)先搜索遍歷圖的遞歸實(shí)現(xiàn)void DFS(int i, int *visited);// 獲取圖中的邊EData* getEdges();// 對(duì)邊按照權(quán)值大小進(jìn)行排序(由小到大)void sortEdges(EData* edges, int elen);// 獲取i的終點(diǎn)int getEnd(int vends[], int i); };

MatrixUDG是鄰接矩陣對(duì)應(yīng)的結(jié)構(gòu)體。
mVexs用于保存頂點(diǎn),mVexNum是頂點(diǎn)數(shù),mEdgNum是邊數(shù);mMatrix則是用于保存矩陣信息的二維數(shù)組。例如,mMatrix[i][j]=1,則表示”頂點(diǎn)i(即mVexs[i])”和”頂點(diǎn)j(即mVexs[j])”是鄰接點(diǎn);mMatrix[i][j]=0,則表示它們不是鄰接點(diǎn)。

/** 克魯斯卡爾(Kruskal)最小生成樹*/ void MatrixUDG::kruskal() {int i,m,n,p1,p2;int length;int index = 0; // rets數(shù)組的索引int vends[MAX]={0}; // 用于保存"已有最小生成樹"中每個(gè)頂點(diǎn)在該最小樹中的終點(diǎn)。EData rets[MAX]; // 結(jié)果數(shù)組,保存kruskal最小生成樹的邊EData *edges; // 圖對(duì)應(yīng)的所有邊// 獲取"圖中所有的邊"edges = getEdges();// 將邊按照"權(quán)"的大小進(jìn)行排序(從小到大)sortEdges(edges, mEdgNum);for (i=0; i<mEdgNum; i++){p1 = getPosition(edges[i].start); // 獲取第i條邊的"起點(diǎn)"的序號(hào)p2 = getPosition(edges[i].end); // 獲取第i條邊的"終點(diǎn)"的序號(hào)m = getEnd(vends, p1); // 獲取p1在"已有的最小生成樹"中的終點(diǎn)n = getEnd(vends, p2); // 獲取p2在"已有的最小生成樹"中的終點(diǎn)// 如果m!=n,意味著"邊i""已經(jīng)添加到最小生成樹中的頂點(diǎn)"沒有形成環(huán)路if (m != n){vends[m] = n; // 設(shè)置m"已有的最小生成樹"中的終點(diǎn)為nrets[index++] = edges[i]; // 保存結(jié)果}}delete[] edges;// 統(tǒng)計(jì)并打印"kruskal最小生成樹"的信息length = 0;for (i = 0; i < index; i++)length += rets[i].weight;cout << "Kruskal=" << length << ": ";for (i = 0; i < index; i++)cout << "(" << rets[i].start << "," << rets[i].end << ") ";cout << endl; }

References
Prim算法(二)之 C++詳解 - 如果天空不死 - 博客園

Kruskal算法(二)之 C++詳解 - 如果天空不死 - 博客園

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

總結(jié)

以上是生活随笔為你收集整理的数据结构之最小生成树的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。