C++無向帶權圖與最小生成樹
參考《算法》一書,C++語言基於鄰接表實現了無向帶權圖以及Prim算法得到圖的最小生成樹。圖的實現在無向圖的基礎上增加權重即可,可參考《C++鄰接表與圖》。Prim算法簡要說來,可寫成如下僞代碼:
for(int i=0;i<V;i++)
{
PrimVisit(i); //插入點並更新權重,同時得到更新後距離圖最近的點
}
具體原理不再詳述,可參考《算法》的講解,此處記錄C++實現無向帶權圖與最小生成樹代碼。
#include<iostream>
#include<queue>
#include<algorithm>
#include<map>
using namespace std;
/*
頂點 中間節點
VNode ENode
0 | A --> 2(C) 1(B)
1 | B --> 4(E) 3(D) 0(A)
2 | C --> 6(G) 5(F) 0(A)
3 | D --> 7(H) 1(B)
4 | E --> 7(H) 1(B)
5 | F --> 6(G) 2(C)
6 | G --> 5(F) 2(C)
7 | H --> 4(E) 3(D)
*/
const int MAX = 20;
struct ENode //鄰接表的中間節點
{
int adjvex; //對應索引
double weight; //邊的權重
ENode* next;
};
typedef struct VNode //鄰接表頂點
{
int vertex; //值
ENode* firstarc; //指向第一個中間節點
}AdjList[MAX];
class ALGraph //圖
{
private:
AdjList adjList; //鄰接表數組
int vexNum; //節點數量
int arcNum; //連邊數量
bool visited[MAX]; //標記被訪問
int edgeTo[MAX]; //最小生成樹連邊記錄
double distTo[MAX]; //樹枝權重
public:
void CreateGraph(); //創建圖
void PrintGraph(); //打印圖
void Prim(); //Prim算法尋找最小生成樹
void PrimVisit(int& delmin); //Prim算法插入結點並更新權值
};
void ALGraph::CreateGraph()
{
cout << "請輸入圖的頂點數:" << endl;
cin >> this->vexNum;
cout << "請輸入圖的弧數:" << endl;
cin >> this->arcNum;
cout << "請輸入頂點信息:" << endl;
for (int i = 0; i<this->vexNum; i++) //構建頂點數組
{
cin >> this->adjList[i].vertex;
this->adjList[i].firstarc = nullptr;
}
cout << "請輸入" << this->arcNum << "個弧的信息:" << endl;
for (int i = 0; i<this->arcNum; i++) //構建每條鄰接表
{
int h1, h2;
double weight;
cin >> h1 >> h2 >> weight;
ENode* temp = new ENode();
temp->adjvex = h2;
temp->weight = weight;
temp->next = this->adjList[h1].firstarc;
this->adjList[h1].firstarc = temp;
temp = new ENode();
temp->adjvex = h1;
temp->weight = weight;
temp->next = this->adjList[h2].firstarc;
this->adjList[h2].firstarc = temp;
}
}
void ALGraph::Prim()
{
int delmin=0; //記錄距離樹最近的圖節點,將其加入樹中
for(int i=0;i<this->vexNum;i++)
{
visited[i] = false;
distTo[i] = __DBL_MAX__; //樹中權重初始化
}
for(int i=0;i<this->vexNum;i++)
{
PrimVisit(delmin); //加入最近節點並更新權重
}
for(int i=0;i<this->vexNum;i++) //打印生成樹
{
cout<<edgeTo[i]<<"-"<<i<<" "<<distTo[i]<<endl;
}
}
void ALGraph::PrimVisit(int& delmin)
{
double mindst = __DBL_MAX__;
visited[delmin] = true;
if(delmin==0)
{
edgeTo[0] = 0;
distTo[0] = 0;
}
ENode* p = this->adjList[delmin].firstarc; //遍歷delmin所連節點,更新權重
while(p)
{
if(visited[p->adjvex])
{
p = p->next;
continue;
}
if(p->weight < distTo[p->adjvex]) //更新權重
{
edgeTo[p->adjvex] = delmin;
distTo[p->adjvex] = p->weight;
}
p = p->next;
}
for(int i=0;i<this->vexNum;i++) //找出下一個delmin
{
if(!visited[i] && mindst>distTo[i])
{
delmin = i;
mindst = distTo[i];
}
}
}
void ALGraph::PrintGraph()
{
for (int i = 0; i<this->vexNum; i++)
{
cout << this->adjList[i].vertex << "--------->";
ENode* p = this->adjList[i].firstarc;
while (p)
{
cout << this->adjList[p->adjvex].vertex << "("<<p->weight<<")"<<" ";
p = p->next;
}
cout << endl;
}
}
int main()
{
ALGraph* graph = new ALGraph();
graph->CreateGraph();
graph->PrintGraph();
graph->Prim();
return 0;
}