/**使用邻接矩阵存储图*/
#include<iostream>
#include<limits.h>
#define MAX_V_NUM 20 //顶点的最大个数
using namespace std;
/**辅助数组的结构体,
每次将当前已选类顶点到待选类顶点的最短距离填写到数组中*/
struct closedge
{
int adjvex;//最小边的起点
int lowcost;//最小边的权值
};
/**图类*/
class MGraph
{
private:
char vertex[MAX_V_NUM];//图元素的一维数组
int arc[MAX_V_NUM][MAX_V_NUM];//图的邻接矩阵,二维数组
int vexNum, arcNum;//元素个数,边的个数
public:
MGraph();//构造函数
~MGraph( ) {};
void DFSTraverse(int v);
void BFSTraverse(int v);
void printMG();
int getIndex(char vertex);//获得顶点的下标
private:
void createDN();
void inputArc();//创建边
void inputVertex();//创建顶点数组
void setArc(int v1,int v2,int value);//设置边
public:
friend void Prim(MGraph graph);
friend int minEdge(closedge shortEdge[], int num);
};
/**创建无向网*/
MGraph::MGraph()
{
inputVertex();
inputArc();
}
/**创建边*/
void MGraph::inputArc()
{
//初始化二维矩阵,全部归INT_MAX
for (int i=0; i<vexNum; i++)
for (int j=0; j<vexNum; j++)
arc[i][j]=INT_MAX;
//输入边
cout<<"请输入边的个数: ";
cin>>this->arcNum;
cout<<"请依次输入"<<this->arcNum<<"个边的起点、终点和权值:\n";
//在二维数组中添加弧的数据
for(int i=0; i<arcNum; i++)
{
char v1,v2;
int value;
//输入弧头和弧尾,应该要补充下标的校验
cin>>v1>>v2>>value;
arc[getIndex(v1)][getIndex(v2)]=value;
arc[getIndex(v2)][getIndex(v1)]=value;
}
}
/**创建顶点数组*/
void MGraph::inputVertex()
{
cout<<"请输入顶点的个数:";
cin>>this->vexNum;
cout<<"请依次输入"<<this->vexNum<<"个顶点的值:\n";
//依次保存顶点本身的数据
for (int i=0; i<vexNum; i++)
{
cin>>vertex[i];
}
return;
}
/**打印顶点,边的信息*/
void MGraph::printMG()
{
cout<<"\n图的顶点有:";
for(int i=0; i<vexNum; i++)
{
cout<<this->vertex[i]<<" ";
}
cout<<"\n图的边有:";
for(int i=0; i<vexNum; i++)
for(int j=i; j<vexNum; j++) //无向网
{
if(this->arc[i][j]<INT_MAX)
cout<<vertex[i]<<"-"<<vertex[j]<<"["<<arc[i][j]<<"] ";
}
}
/**返回指定顶点值的下标*/
int MGraph::getIndex(char vertex)
{
for(int i=0; i<vexNum; i++)
{
if(this->vertex[i]==vertex)
return i;
}
return -1;
}
/**深度遍历*/
void MGraph::DFSTraverse(int v)
{
static int visited[MAX_V_NUM] = {0}; //定义为静态数组,所有函数公用一个数组
cout << vertex[v] << " ";//输出一个顶点
visited[v] = 1;
for(int j=0; j<vexNum; j++)//从邻接表的第v行中找所有连出去的顶点
if(arc[v][j]>0&& arc[v][j]<INT_MAX&& visited[j]==0)
DFSTraverse(j);
}
/**广度优先遍历*/
void MGraph :: BFSTraverse(int v)
{
const int MAX_QUEUE=100;
int visited[MAX_V_NUM]= {0}; //定义visited数组并初始化为0
char queue[MAX_QUEUE]; //定义队列
int front,rear;
cout << vertex[v] << " ";
visited[v] = 1;
front = rear = -1;
rear = (rear+1) % MAX_QUEUE;
queue[rear] = vertex[v]; //顶点v入队列Q
while (front!=rear) //当队列非空时
{
front = (front+1) % MAX_QUEUE;
v = getIndex(queue[front]); //将队头元素出队并送到v中
//访问队头元素所有相连的边
for (int j = 0; j < vexNum; j++)
//如果边存在,就输出边,将顶点入队
if (arc[v][j]>0&& arc[v][j]<INT_MAX&& visited[j] == 0 )
{
cout << vertex[j] << " ";
visited[j] = 1;
rear = (rear+1) % MAX_QUEUE;
queue[rear] = vertex[j];
}
}
//清零,下次运行
for (int i=0; i<MAX_V_NUM; i++)
visited[i] = 0;
}
/**
返回待选集合中,权值最小的边的终点下标
lowcost不为0则在待选集合中
num为顶点个数
closedge为辅助数组
*/
int minEdge(closedge shortEdge[], int num)
{
int min=INT_MAX;//最小权值的初值
int minIndex=-1;//最小下标
//在shortEdge数组中寻找待选集合中的最小值,记录下标
for(int i=0; i<num; i++)
{
if(shortEdge[i].lowcost!=0)
{
if(shortEdge[i].lowcost<min)
{
min=shortEdge[i].lowcost;
minIndex=i;
}
}
}
//权值为 0,说明顶点已经归入最小生成树的已选集合中;然后每次非0时和 min 变量进行比较,最后找出最小的。
//if(min==0)
//返回最小权值所在的数组下标
return minIndex;
}
/**
prim算法,输出最小生成树
参数graph 为邻接矩阵图
1. 初始化两个辅助数组lowcost和adjvex;
2. 输出顶点u0,将顶点u0加入集合U中;
3. 重复执行下列操作n-1次
3.1 在lowcost中选取最短边,取adjvex中对应的顶点序号k;
3.2 输出顶点k和对应的权值;
3.3 将顶点k加入集合U中;
3.4 调整数组lowcost和adjvex;
*/
void Prim(MGraph graph)
{
closedge *shortEdge = new closedge[graph.vexNum];//创建辅助数组
int i,j,min;
//初始化shortEdge,将邻接矩阵的第0行赋给它(意味着起点从0开始)
for(j=0; j<graph.vexNum; j++)
{
shortEdge[j].adjvex=0;
shortEdge[j].lowcost=graph.arc[0][j];
}
//0顶点加入已选集合
shortEdge[0].lowcost=0;
shortEdge[0].adjvex=0;
//循环vexNum-1次,
for(i=1; i<graph.vexNum;i++)
{
//调函数,求出最小边的终点下标vexNum
min=minEdge(shortEdge,graph.vexNum);
//输出顶点和权值
// if(min==-1)break;
cout<<"<"<<graph.vertex[shortEdge[min].adjvex]<<","<<graph.vertex[min]<<">"<<shortEdge[min].lowcost<<endl;
//顶点加入已选集合
shortEdge[min].lowcost=0;
//min顶点加入已选集合以后,更新shortEdge
for(j=0; j<graph.vexNum; j++)
{
if(shortEdge[j].lowcost!=0)
if(shortEdge[j].lowcost>graph.arc[min][j])//如果min顶点到顶点的距离比shortEdge中记录的还要小,就替换
{
shortEdge[j].adjvex=min;
shortEdge[j].lowcost=graph.arc[min][j];
}
}
}
delete [] shortEdge;
}
int main()
{
MGraph graph;
graph.printMG();
char v;
cout<<"\n请输入遍历的起始顶点";
cin>>v;
cout<<"-----------------\n深度优先遍历的结果:";
graph.DFSTraverse(graph.getIndex(v));
cout<<"\n-----------------\n广度优先遍历的结果:";
graph.BFSTraverse(graph.getIndex(v));
cout<<"\n最小生成树是:\n";
Prim(graph);
return 0;
}
/**
测试数据-1
8
A B C D E F G H
9
A B 5
A C 6
B D 8
B E 10
D F 9
E F 2
C G 5
C H 7
G H 6
测试数据-2
4
A B C D
5
A B 2
A C 4
A D 2
C D 3
B C 3
测试数据-3
6
A B C D E F
9
A C 46
A F 19
A B 34
B E 12
E F 26
D E 38
D F 25
C D 17
C F 25
*/
PrimMinCostSpanningTree
最新推荐文章于 2025-03-19 15:40:19 发布