最小生成树(Prim算法,Kruskal算法)

最小生成树

假设要在n个城市之间建立通信联络网,则连通n个城市只需要n-1条线路。这时,自然各

考虑这样一个问题,如何在最节省经费的前提下建立这个通信网。

在每两个城市之间都可设置一条线路,相应地都要付出一定的经济代价,n个城市之间,最多可能设置n(n-1)2条线路,那么,如何在这些可能的我路中选择n-1条,以使总的耗费最少呢?

可以用连通网来表示n个城市,以及n个城市间可能设置的通信线路,其中网的顶点表示城市,边表示两城市之间的线路,赋予边的权值表示相应的代价。对于n个顶点的连通网可以建立许多不同的生成树,每一棵生成树都可以是一个通信网。最合理的通信网应该是代价之和最小的生成树。在一个连通网的所有生成树,各边的代价之和最小的那棵生成树称为该连通网的最小代价生成树(Minimum Cost Spanning Tree),简称为最小生成树。

Prim算法

普里姆算法的实现思路

假设一个无向网G以邻接矩阵形式存储,从顶点u出发构造G的最小生成树T,要求输出T的各条边。为实现这个算法需附设一个辅助数组closedge,以记录从U到V-U具有最小权值的边。对每个顶点vi属于V-U,在辅助数组中存在一个相应分量closedge[i-1],它包括两个域:lowcost和adjvex。其中lowcost存储最小边上的权值,adjvex存储最小边在U中的那个顶点。显然,closedge[i-1].lowcost=Min{ cost(u,vi)|u属于U},其中cost(u,v)表示赋予边(u,v)的权。

Prim算法就是一直寻找“符合要求的”顶点,每次加入的顶点都可以使那一条边的权值是当前最小的,直到所有的顶点都被加入。

算法步骤

①首先将初始顶点u加入U中,对其余的每一个顶点vi,将closedge[j]均初始化为到u的边信息。

②循环n-1次,做如下处理:

从各组边closedge中选出最小边closedge[k],输出此边;

将k加入U中;

更新剩余的每组最小边信息closedge[j],对于V-U中的边,新增加了一条从k到j的边,如果新边的权值比closedge[j].lowcost小,则将closedge[j].lowcost更新为新边的权值。

【算法分析】

假设网中有n个顶点,则第一个进行初始化的循环语句的频度为n,第二个循环语句的频度为n-1。其中第二个有两个内循环:其一是在closedge[v].lowcost中求最小值,其频度为n-1;其二是重新选择具有最小权值的边,其频度为n。由此,普里姆算法的时间复杂度为0(n^2),与网中的边数无关,因此适用于求稠密网的最小生成树

#####################################################################

首先选择一个顶点加入到U中,即加入到已选顶点集中,接下来进行n-1次循环,每次的操作都是一样的。

对于未选顶点集,每个顶点都有一个closedge数组分量,表示这个数组下标所对应的顶点(未选顶点集)与已选顶点集的顶点之间组成的边,其中权值最小的边的顶点(该顶点是已选顶点集中的顶点的序号,及此时最小的权值。

每次循环,让每个closedge得到最小的记录,并把这个顶点加入已选顶点集中,然后更新每组最小边信息,更新是最重要的一步,每一组都需要更新,就是未选顶点集中的每个顶点的相应closedge分量都要更新,为下一次循环做准备。

closedge的理解:closedge是一个Closedge类型的数组,数组的下标是未选的顶点集中的顶点,不同下标的数组空间中存储的是属于该顶点的信息(对应最小边信息)

知道了算法思路,接下来就是程序的编写了。把思路变为现实的代码需要注意很多技巧和细节。

//Prim算法 
  //加点法,需要附设一个辅助数组
  //顶点可以分为两组,一组是已选的,一组是未选的。如何把已选和未选体现在程序中,就需要你自己设置一个标记。显示出二者的区别。
struct  Closedge
{
    VerTexType adjvex;//最小边在已选的顶点集中的那个顶点(已选的顶点的序号)  主要是记录,便于表示我们找到的那条边
    int now_vex;//数组下标所对应的顶点  未选的顶点集
    ArcType lowcost;// 最小边上的权值(已选的顶点和未选的顶点之间的边的权值,取最小。已选对标未选) 
}closedge[MVNum];
//对于每一个未选的顶点都有一个自己的closedge分量,每个未选的closedge记录的信息都是通过观察已选的顶点得到的
//对于已选的顶点,需要标明出该顶点已选,则令其lowcost为0

int Min(Closedge closedge[],int n)比较权值即lowcost,得到顶点下标,该顶点是未选集中的//仅查找
{
    int Min,Min_vex,Min_index;
    for(int i=0;i<n;i++)
    {
        if(closedge[i].lowcost<min)
        {
             Min=closedge[i].lowcost;
            // Min_vex=closedge[i].now_vex;
             Min_index=i;
        } 
    }
    if(closedge[i].lowcost!=0) return Min_vex;//保证是未选顶点集中的
}

void MiniSpanTree_Prim(AMGraph G, VerTexType u)
{
    int i, j, k,count_U=0,count_V=0;
    VerTexType  u0, v0;

    k = LocateVex(G, u);
    
    for (j = 0; j < G.vexnum; j++)
    {
        int temp_vex=1;
        if (j != k)//初始化未选的顶点的closedge,closedge属于未选的顶点
        {
            //closedge[j] = { u,G.arcs[k][j] };
            
           // temp_vex++;
           // closedge[j].now_vex=temp_vex;
           
            closedge[j].adjvex=u;
            closedge[j].lowcost=G.arcs[k][j];
        }
        
    }
        closedge[k].lowcost = 0;//把已选的顶点加入已选顶点集中  如何让代码体现这个加入,只需要做一个标记即可
        count_U++;//已选加1
        count_V=G.vexnum-count_U;//未选
        
        //上述操作都是初始化,为接下来的工作做准备
        
        for (i = 1; i < G.vexnum; i++)//n-1次循环//选择n-1个顶点和n-1条边,上面已经选了一个顶点
        {
            k = Min(closedge,count_V);//得到当前权值最小的边
            //保证一致。。。
            u0 = closedge[k].adjvex;//u0为最小边的一个顶点,u0属于已选顶点集
            v0 = G.vexs[k];//v0为最小边的另一个顶点,我们所找到的符合要求的顶点,暂时未选........//vexs...
            cout << u0 << v0;//输出我们找到的这条边
            
            closedge[k].lowcost = 0;//把我们找到的这个符合要求的顶点加入到已选顶点集中
            count_U++;//已选加1
            count_V=G.vexnum-count_U;//未选
            
            for(j=0;j<G.vexnum;j++)//更新!!!!
            {
                if(G.arcs[k][j]<closedge[j].lowcost)
                {
                    closedge[j] = { G.vexs[k],G.arcs[k][j] };
                }
            }
            
        }
}


完整代码(具体的实现和存储结构,数据类型有关)

#include<iostream>
#include<new>
using namespace std;

typedef int Status;
#define  OK 1
#define ERROR 0
#define OVERFLOW -1


#define MaxInt 32767 //不相通
#define MVNum 100 //最大顶点个数
typedef char VerTexType;
typedef int ArcType;//权值类型


//邻接矩阵,二维数组
typedef struct
{
    VerTexType vexs[MVNum];//顶点 行 列 存储
    ArcType arcs[MVNum][MVNum];//存储
    int vexnum, arcnum;//图的当前点数和边数:我们申请的是固定空间,不是动态申请。固定申请的空间我们不知道将会使用多少,那么此时通过当前记录就可以知道了。

}AMGraph;

//邻接表
typedef struct
{

}OtherInfo;

typedef struct ArcNode//边节点
{
    int adjvex;//可以理解为这个边结点的顶点的序号,因为邻接表中顶点都存储在顶点数组中(表头数组)
    struct ArcNode* nextarc;
    OtherInfo info;//和边相关的信息
}ArcNode;

typedef struct VNode//表头结点
{
    VerTexType data;//对比  通过对比关键字可以找到“整体”
    ArcNode* firstarc;
}VNode, AdjList[MVNum];

typedef struct//邻接表
{
    AdjList vertices;//表头结点表
    int vexnum, arcnum;//图的当前点数和边数???什么作用???

}ALGraph;
#pragma once
#include"AMGraph.h"

int LocateVex_UDN(AMGraph G, VerTexType u)//如存在,返回顶点在图中的位置  //监视哨的方式查找
{
    //VerTexType vexs[MVNum], vexnum
    int i;
    for (i = 0; i < G.vexnum; i++)
    {
        if (G.vexs[i] == u)  return i;
    }
    return 0;

}


Status CreateUDN(AMGraph& G)
{
    int i, j, k;
    VerTexType v1, v2;
    ArcType w;

    cout << "请输入当前的顶点数和边数" << endl;
    cin >> G.vexnum >> G.arcnum;

    //初始化顶点和边(权值)//有权值 有关系 有边
    for (i = 0; i < G.vexnum; i++)
    {
        cout << "请输入第" << i + 1 << "个顶点的数据" << endl;
        cin >> G.vexs[i];
    }
    for (i = 0; i < G.vexnum; i++)//矩阵:矩阵的行和列是顶点个数
    {
        for (j = 0; j < G.vexnum; j++)
        {
            G.arcs[i][j] = MaxInt;
        }
    }

    //构造矩阵  有多少条边构造多少次(初始化的时候已经给边赋初值了,
    //那么接下来我们只需要把”有关系的边“赋给正确的权值(覆盖初值即可),”没有关系的边“,就是不相通,不需要赋值,初始值就表明他们不相通
    for (k = 0; k < G.arcnum; ++k)
    {
        cout << "请输入要创建的第" << k + 1 << "条边和它的权值" << endl;

        cin >> v1 >> v2 >> w;//
        i = LocateVex_UDN(G, v1);
        j = LocateVex_UDN(G, v2);

        G.arcs[i][j] = w;//图  1 ,网  w
        G.arcs[j][i] = G.arcs[i][j];//无向图  对称
    }
    return OK;
}


void PrintAMGraph(AMGraph G)//显示一个矩阵。。。(带权)
{
    for (int i = 0; i < G.vexnum;i++)
    {
        for(int j=0;j<G.vexnum;j++)
        {
            cout << G.arcnum[i][j] << " ";
        }
        cout << endl;
    }
}

//邻接表创建

int LocateVex_UDG(ALGraph G, VerTexType u)//如存在,返回顶点在图中的位置  在顶点中寻找比对  返回顶点的下标(无论是邻接表还是邻接矩阵,顶点都存储在数组中。。。)
{
    //G.vertices[i].data
    int i;
    for (i = 0; i < G.vexnum; i++)
    {
        if (G.vertices[i].data == u)  return i;
    }
    return 0;
}

Status CreateUDG(ALGraph& G)
{
    int i, j, k;
    VerTexType v1, v2;
    ArcNode* p1;
    ArcNode* p2;

    cout << "请输入当前的顶点数和边数" << endl;
    cin >> G.vexnum >> G.arcnum;
    //初始化
    for (i = 0; i < G.vexnum; i++)
    {
        cout << "请输入第" << i + 1 << "个顶点的数据" << endl;

        cin >> G.vertices[i].data;
        G.vertices[i].firstarc = NULL;
    }
    //构造
    for (k = 0; k < G.arcnum; ++k)
    {
        cout << "请输入要创建的第" << k + 1 << "条边" << endl;
        cin >> v1 >> v2;
        i = LocateVex_UDG(G, v1);
        j = LocateVex_UDG(G, v2);//两个顶点一条边  在顶点数组里面寻找。。表头数组vertices返回下标int
        //j

        p1 = new ArcNode;//新节点
        p1->adjvex = j;

        p1->nextarc = G.vertices[i].firstarc;//头插法
        G.vertices[i].firstarc = p1;

        //i  对称
        p2 = new ArcNode;
        p2->adjvex = i;

        p2->nextarc = G.vertices[j].firstarc;
        G.vertices[j].firstarc = p2;
    }
    return OK;
}

void PrintALGraph(ALGraph G)//显示一个数表。。。一行是一个单链表。。。
{
    ArcNode* p;
    ArcNode* q;
    
    cout << "提示:接下来的每一行,第一个为顶点信息,后面的为该顶点的邻接点的信息" << endl;
    for(int i=0;i<G.vertices;i++)
    {
        
        p = new ArcNode;
        p = G.vertices[i].firstarc;//第一个边结点

        cout << G.vertices[i].data << " ";
        while(NULL!=p)
        {
            cout << G.vertices[p->adjvex].data << "(该边)的信息为" << p->info << " ";
            p = p->nextarc;
        }
        cout << endl;

    }
}

// int main()//如需要。。。
// {
//     cout << "邻接矩阵的创建" << endl;
//     AMGraph G;
//     CreateUDN(G);

//     cout << "邻接矩阵创建完成,显示邻接矩阵:" << endl;
//     PrintAMGraph(G);

//     cout << "邻接表的创建" << endl;
//     ALGraph H;
//     CreateUDG(H);
//     cout << "邻接表创建完成,显示邻接表:" << endl;
//     PrintALGraph(H);

//     return 0;
// }

//最小生成树算法(Prim算法  Kruskal算法)

//Prim算法 
  //加点法,需要附设一个辅助数组
struct
{
    VerTexType adjvex;
    ArcType lowcost;
}closedge[MVNum];

int Min(Closedge closedge[],int n)比较权值即lowcost,得到顶点下标,该顶点是未选集中的//仅查找
{
    int Min,Min_vex,Min_index;
    for(int i=0;i<n;i++)
    {
        if(closedge[i].lowcost<min)
        {
             Min=closedge[i].lowcost;
            // Min_vex=closedge[i].now_vex;
             Min_index=i;
        } 
    }
    if(closedge[i].lowcost!=0) return Min_vex;//保证是未选顶点集中的
}

void MiniSpanTree_Prim(AMGraph G, VerTexType u)
{
    int i, j, k;
    VerTexType  u0, v0;

    k = LocateVex(G, u);
    for (j = 0; j < G.vexnum; j++)
    {
        if (j != k) closedge[j] = { u,G.arcs[k][j] };
        closedge[k].lowcost = 0;
        for (i = 1; i < G.vexnum; i++)
        {
            k = Min(closedge);
            u0 = closedge[k].adjvex;
            v0 = G.vexs[k];

            cout << u0 << v0;
            closedge[k].lowcost = 0;
            for(j=0;j<G.vexnum;j++)
            {
                if(G.arcs[k][j]<closedge[j].lowcost)
                {
                    closedge[j] = { G.vexs[k],G.arcs[k][j] };
                }
            }
        }

    }

}

Kruskal算法

克鲁斯卡尔算法的构造过程

假设连通网N=(V,E),将N中的边按权值从小到大的顺序排列。

①初始状态为只有n个顶点而无边的非连通图T=(V,{}),图中每个顶点自成一个连通分量。

②在E中选择权值最小的边,若该边依附的顶点落在T中不同的连通分量上(不形成回路),则将此边加入T中,否则舍去此边而选择下一条权值最小的边。

③重复②,直至T中所有顶点都在同一连通分量上为止。

【算法步骤】

①将数组Edge中的元素按权值从小到大排序。

②依次查看数组Edge中的边,循环执行以下操作:

依次从排好序的数组Edge中选出一条边(U1,U2);

在Vexset中分别查找v1和v2所在的连通分量vs1和vs2进行判断:如果vs1和vs2不等,表明所选的两个顶点分属不同的连通分量,输出此边,并合并vs1,和vs2两个连通分量;

如果vs1和vs2相等,表明所选的两个顶点属于同一个连通分量,舍去此边而选择下一条权值最小的边。

个人思考

①慢慢把边都加入,随着程序的进行,边越加越多,被合并的越多,即被连通的顶点不止一个,而是集合。

②Vexset[i]:标识各个顶点所在的连通分量。初始时Vexset[i]=i,表示各个顶点自成一个连通分量。

这个数组非常重要,是程序的关键。数组下标 代表不同顶点,不同下标的数组空间存储的值代表该顶点所在的连通分量。连通分量相同表明这些顶点相连通不相同则不连通。(此处、你要理解数组的含义,使用方法以及连通分量的概念)

//Kruskal算法
//加边法
int arcnum=100;
struct  KNode
{
    VerTexType Head;//边的始点
    VerTexType Tail;//边的终点
    ArcType  lowcost;
}Edge[arcnum];


int Vexset[MVNum];//标识各个顶点所属的连通分量   即表明谁与谁联通,谁与谁不连通

void Sort(struct KNode a[], int n)//从小到大排序,这里采用了改进版的冒泡排序
{
    int i, j,flag=1,m=n-1;//flag用来标记某一趟排序是否发生交换
    struct KNode temp;
    
   while((m>0)&&(flag==1))
    {
        flag=0;
        for (j = 1; j <=m; j++)
        {
            if (a[j]>a[j + 1])
            {
                flag=1;
                
                temp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = temp;
            }
            --m;
        }
    }

}

void MiniSpanTree_Kruskal(AMGraph G)
{
    int i,j,v1,v2,vs1,vs2;
    
    Sort(Edge,arcnum);//按权值从小到大排序
    
    for(i=0;i<G.vexnum;i++)//表示各个顶点自成一个连通分量
    {
        Vexset[i]=i;
    }
    
    for(i=0;i<G.arcnum;i++)//依次查看数组Edge中的边
    {
        //边
        v1=LocateVex(G,Edge[i].Head);//v1为边的始点Head的下标
        v2=LocateVex(G,Edge[i].Tail);//v1为边的终点Tail的下标
        
        //所在连通分量
        vs1=Vexset[v1];//获取边Edge[i]的始点所在的连通分量vs1
        vs2=Vexset[v2];//获取边Edge[i]的终点所在的连通分量vs2
        
        if(vs1!=vs2)//所加入的边起作用  边的两个顶点分属于不同的连通分量
        {
            cout<<Edge[i].Head<<Edge[i].Tail;//输出此边
            
            for(j=0;j<G.vexnum;j++)//合并vs1和vs2两个连通分量,即两个集合统一编号
            {
                if(Vexset[j]==vs2)  Vexset[j]=vs1;//集合编号为vs2的都改为vs1
            }
            
        }
        
    }

}

完整代码

#include<iostream>
#include<new>
using namespace std;

typedef int Status;
#define  OK 1
#define ERROR 0
#define OVERFLOW -1

#define MAXSIZE 100

#define MaxInt 32767 //不相通
#define MVNum 100 //最大顶点个数
typedef char VerTexType;
typedef int ArcType;//权值类型

bool visited[MVNum];

typedef int QElemType;
typedef struct
{
    QElemType data[MAXSIZE];
    int front; /*头指针*/
    int rear; /*尾指针,若队列不空,指向队列元素的下一个位置*/
}SqQueue;

SqQueue* Q;//链表  栈  队列  都是指针类型的?门牌号?不是房间吗?

//邻接矩阵,二维数组
typedef struct
{
    VerTexType vexs[MVNum];//顶点 行 列 存储
    ArcType arcs[MVNum][MVNum];//存储
    int vexnum, arcnum;//图的当前点数和边数

}AMGraph;


//邻接表
typedef struct
{

}OtherInfo;

typedef struct ArcNode//边节点
{
    int adjvex;
    struct ArcNode* nextarc;
    OtherInfo info;//和边相关的信息
}ArcNode;

typedef struct VNode//表头结点
{
    VerTexType data;
    ArcNode* firstarc;
}VNode, AdjList[MVNum];

typedef struct//邻接表
{
    AdjList vertices;//表头结点表
    int vexnum, arcnum;//图的当前点数和边数

}ALGraph;

int LocateVex_UDN(AMGraph G, VerTexType u)//如存在,返回顶点在图中的位置  //监视哨的方式查找
{
    //VerTexType vexs[MVNum], vexnum
    int i;
    for (i = 0; i < G.vexnum; i++)
    {
        if (G.vexs[i] == u)  return i;
    }
    return 0;

}


Status CreateUDN(AMGraph& G)
{
    int i, j, k;
    VerTexType v1, v2;
    ArcType w;

    cout << "请输入当前的顶点数和边数" << endl;
    cin >> G.vexnum >> G.arcnum;

    //初始化顶点和边(权值)//有权值 有关系 有边
    for (i = 0; i < G.vexnum; i++)
    {
        cout << "请输入第" << i + 1 << "个顶点的数据" << endl;
        cin >> G.vexs[i];
    }
    for (i = 0; i < G.vexnum; i++)//矩阵:矩阵的行和列是顶点个数
    {
        for (j = 0; j < G.vexnum; j++)
        {
            G.arcs[i][j] = MaxInt;
        }
    }

    //构造矩阵  有多少条边构造多少次(初始化的时候已经给边赋初值了,
    //那么接下来我们只需要把”有关系的边“赋给正确的权值(覆盖初值即可),”没有关系的边“,就是不相通,不需要赋值,初始值就表明他们不相通
    for (k = 0; k < G.arcnum; ++k)
    {
        cout << "请输入要创建的第" << k + 1 << "条边和它的权值" << endl;

        cin >> v1 >> v2 >> w;//
        i = LocateVex_UDN(G, v1);
        j = LocateVex_UDN(G, v2);

        G.arcs[i][j] = w;//图  1 ,网  w
        G.arcs[j][i] = G.arcs[i][j];//无向图  对称
    }
    return OK;
}


void PrintAMGraph(AMGraph G)//显示一个矩阵。。。(带权)
{
    for (int i = 0; i < G.vexnum;i++)
    {
        for(int j=0;j<G.vexnum;j++)
        {
            cout << G.arcnum[i][j] << " ";
        }
        cout << endl;
    }
}

//邻接表创建

int LocateVex_UDG(ALGraph G, VerTexType u)//如存在,返回顶点在图中的位置  在顶点中寻找比对  返回顶点的下标(无论是邻接表还是邻接矩阵,顶点都存储在数组中。。。)
{
    //G.vertices[i].data
    int i;
    for (i = 0; i < G.vexnum; i++)
    {
        if (G.vertices[i].data == u)  return i;
    }
    return 0;
}

Status CreateUDG(ALGraph& G)
{
    int i, j, k;
    VerTexType v1, v2;
    ArcNode* p1;
    ArcNode* p2;

    cout << "请输入当前的顶点数和边数" << endl;
    cin >> G.vexnum >> G.arcnum;
    //初始化
    for (i = 0; i < G.vexnum; i++)
    {
        cout << "请输入第" << i + 1 << "个顶点的数据" << endl;

        cin >> G.vertices[i].data;
        G.vertices[i].firstarc = NULL;
    }
    //构造
    for (k = 0; k < G.arcnum; ++k)
    {
        cout << "请输入要创建的第" << k + 1 << "条边" << endl;
        cin >> v1 >> v2;
        i = LocateVex_UDG(G, v1);
        j = LocateVex_UDG(G, v2);//两个顶点一条边  在顶点数组里面寻找。。表头数组vertices返回下标int
        //j

        p1 = new ArcNode;//新节点
        p1->adjvex = j;

        p1->nextarc = G.vertices[i].firstarc;//头插法
        G.vertices[i].firstarc = p1;

        //i  对称
        p2 = new ArcNode;
        p2->adjvex = i;

        p2->nextarc = G.vertices[j].firstarc;
        G.vertices[j].firstarc = p2;
    }
    return OK;
}

void PrintALGraph(ALGraph G)//显示一个数表。。。一行是一个单链表。。。
{
    ArcNode* p;
    ArcNode* q;
    
    cout << "提示:接下来的每一行,第一个为顶点信息,后面的为该顶点的邻接点的信息" << endl;
    for(int i=0;i<G.vertices;i++)
    {
        
        p = new ArcNode;
        p = G.vertices[i].firstarc;//第一个边结点

        cout << G.vertices[i].data << " ";
        while(NULL!=p)
        {
            cout << G.vertices[p->adjvex].data << "(该边)的信息为" << p->info << " ";
            p = p->nextarc;
        }
        cout << endl;

    }
}

// int main()//如需要。。。
// {
//     cout << "邻接矩阵的创建" << endl;
//     AMGraph G;
//     CreateUDN(G);

//     cout << "邻接矩阵创建完成,显示邻接矩阵:" << endl;
//     PrintAMGraph(G);

//     cout << "邻接表的创建" << endl;
//     ALGraph H;
//     CreateUDG(H);
//     cout << "邻接表创建完成,显示邻接表:" << endl;
//     PrintALGraph(H);

//     return 0;
// }

//最小生成树算法(Prim算法  Kruskal算法)

//Kruskal算法
int arcnum=100;
struct  KNode
{
    VerTexType Head;//边的始点
    VerTexType Tail;//边的终点
    ArcType  lowcost;
}Edge[arcnum];


int Vexset[MVNum];

void Sort(struct KNode a[], int n)
{
    int i, j;
    struct KNode temp;
    for (i = 0; i < n - 1; i++)
    {
        for (j = 0; j < n - i - 1; j++)
        {
            if (a[j]>a[j + 1])
            {
                temp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = temp;
            }
        }
    }

}


void MiniSpanTree_Kruskal(AMGraph G)
{
    int i,j,v1,v2,vs1,vs2;
    
    Sort(Edge,arcnum);
    for(i=0;i<G.vexnum;i++)
    {
        Vexset[i]=i;
    }
    for(i=0;i<G.arcnum;i++)
    {
        v1=LocateVex(G,Edge[i].Head);
        v2=LocateVex(G,Edge[i].Tail);
        vs1=Vexset[v1];
        vs2=Vexset[v2];
        if(vs1!=vs2)
        {
            cout<<Edge[i].Head<<Edge[i].Tail;
            for(j=0;j<G.vexnum;j++)
            {
                if(Vexset[j]==vs2)  Vexset[j]=vs1;
            }
        }
    }

}


编者语

小新还在努力,如有不足请指出。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值