PrimMinCostSpanningTree

/**使用邻接矩阵存储图*/
#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
*/


在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值