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;
}