克鲁斯卡尔算法得最小生成树

在写kruskal算法时,输入6个节点,9条边,但是输入第一个边之后程序输出直接跑飞了

代码如下,感觉不像是CreatVDN()函数出现的问题,但是输入却在输入边的权值的时候跑飞了,请问有没有指点一下

前面的代码都是一些功能性的函数,最主要是最后的kruskal()函数

#include<iostream>
using namespace std;
//kruskal算法最小生成树
#define max_weight 32767

//邻接矩阵来表示图
typedef struct
{
    char vexs[100];     //这里相比较书上多了顶点数组
    int arcs[100][100];
    int vexnum,arcnum;
}AMGraph;

//定义边
typedef struct
{
    char begin;
    char end;
    int lowcost;
}EDGE; 

//定义Edge数组
EDGE Edge[99*50];


//找出顶点在顶点数组的位置,如果没这个顶点,返回-1
int LocateVex(AMGraph G,char v)
{
    for(int i=0;i<G.vexnum;i++)
    {
        if(G.vexs[i]==v)
        {
            return i;
        }
    }
    return -1;
}

//为无向图赋值,同时Edge数组初始化
void CreatVDN(AMGraph &G)
{
    int i,j,k;
    cout<<"input the number of vexnum and arcnum separate with space key"<<endl;
    cin>>G.vexnum>>G.arcnum;
    cout<<endl;
//输入顶点
    cout<<"input name of vertex"<<endl;
    for(i=0;i<G.vexnum;i++)
    {
        cout<<"input No."<<i+1<<" vertex"<<endl;
        cin>>G.vexs[i];
    }
//邻接矩阵初始化
    for(i=0;i<G.vexnum;i++)
    {
        for(j=0;j<G.vexnum;j++)
        {
            if(i==j)
            {
                G.arcs[i][j]=0;
            }
            G.arcs[i][j]=max_weight;
        }
    }
//手动输入邻接矩阵
    cout<<"input the weight of arc :weight vex1 vex2"<<endl;
    int weight;
    int vex1,vex2;
    for(k=0;k<G.arcnum;++k)
    {

        cout<<"input the No."<<k+1<<" arc"<<endl;
        cin>>weight>>vex1>>vex2;
        i=LocateVex(G,vex1);
        j=LocateVex(G,vex2);
        if(i==-1 || j==-1)      //如果有一个vex没找到就输出error
        {
            cout<<"error"<<endl;
            k--;
        }
        else        //如果找到了就初始化邻接矩阵和Edge数组
        {

            G.arcs[i][j]=weight;
            G.arcs[j][i]=G.arcs[i][j];
            Edge[k].lowcost=weight;  //同时对Edge数组也进行初始化
            Edge[k].begin=vex1;
            Edge[k].end=vex2;
        }
    }
}



//冒泡法对边从小到大排序
void sort(EDGE Edge[],AMGraph G)  
{
    char temp_begin,temp_end;
    int temp_weight;
    for(int i=0;i<G.arcnum-1;i++)   
    {
        for(int j=0;j<G.arcnum-1-i;j++)
        {
            if(Edge[j].lowcost>Edge[j+1].lowcost)
            {
                temp_begin=Edge[j].begin;
                Edge[j].begin=Edge[j+1].begin;
                Edge[j+1].begin=temp_begin;

                temp_end=Edge[j].end;
                Edge[j].end=Edge[j+1].end;
                Edge[j+1].end=temp_end;

                temp_weight=Edge[j].lowcost;
                Edge[j].lowcost=Edge[j+1].lowcost;
                Edge[j+1].lowcost=temp_weight;
            }
        }
    }
    cout<<"after sorting the Edge[] is:"<<endl;
    for(int i=0;i<G.arcnum;i++)
    {
        cout<<Edge[i].begin<<"\t"<<Edge[i].end<<"\t"<<Edge[i].lowcost<<endl;
    }

}

//寻找根节点,输入是parent数组和要寻找其根节点的元素序号
//输出是根节点的序号
int Find(int *parent,int L) 
{
    while(parent[L]>-1)
    {
        L=parent[L];
    }
    return L;
}

//kruskal算法
void kruskal(AMGraph G)
{
    //1.根据G的邻接矩阵初始化edge数组
    //2.对edge数组进行排序
    //3.创建parnet数组,根据edge数组对parent数组进行处理,并在处理时输出最小生成树的边
    int i,j;
    int k=0;
    int v1,v2;      //用来装结点的在edge数组中的序号
    int vex1,vex2;  //用来装寻找到的根节点
    for(i=0;i<G.vexnum-1;i++)       //按照邻接矩阵的上三角来填充edge数组
        for(j=i+1;j<G.vexnum;j++)
        {
            if(G.arcs[i][j]<max_weight)
            {
                Edge[k].lowcost=G.arcs[i][j];
                Edge[k].begin=i;
                Edge[k].end=j;
                k++;    //Edge数组中的元素个数,虽然不一样用得上
            }
        }
    }
    //Edge数组排序
    sort(Edge,G);       //sort自带排序后输出
    cout<<endl;

    int parent[G.vexnum];
    for(i=0;i<G.vexnum;i++)
    {
        parent[i]=-1;   //根节点在parent数组中的值默认为-1
    }

    //处理,输出最小生成树
    cout<<"mini tree :"<<endl;
    for(int num=0,i=0;i<G.arcnum && num<G.vexnum-1;i++)     //两个停止循环条件:要么循环完了,还没找到足够的边生成最小生成树,要么没循环完就找齐了边来生成最小生成树
    {
        v1=LocateVex(G,Edge[i].begin);  //v1是Edge[i].begin在G中的元素序号
        v2=LocateVex(G,Edge[i].end);    
        vex1=Find(parent,v1);       //vex1对应的元素在parent数组中的根节点
        vex2=Find(parent,v2);
        if(vex1!=vex2)          //如果是不同的树,就合并且生成一条边
        {
            parent[vex2]=vex1;
            cout<<Edge[i].begin<<"-->"<<Edge[i].end<<endl;
            num++;
        }
    }
}


int main()
{
    AMGraph G;
    CreatVDN(G);    //这里是引用,引用在使用时实参不需要加&
    kruskal(G);
    system("pause");
    return 0;
}
139 views
Comments
登录后评论
Sign In
·

这简直太好排查了

你定义的是

int weight;
int vex1,vex2;

然后输入cin>>weight>>vex1>>vex2;

那自然是爆炸

·

你程序实在写得太烂的(不要介意),我忍不住帮你改了一下,有些地方用面向对象写会更舒服,你没用那就没改了

介于你使用了C++的一些特性,那许多地方可以优化

  • std::swap直接交换结构体变量
  • struct AMGraph直接定义,不需要使用typedef
  • const变量代替魔数和宏定义

需要注意几个地方

  • 函数参数拷贝问题,比如kruskal函数的AMGraph G当参数会导致这个结构体全部拷贝一遍,即无缘无故浪费了内存,所以用const AMGraph &G替代
  • 全局变量尽量少用,比如EDGE Edge[99*50];,会导致程序混乱,即需要缩小变量作用域
  • 大变量不要放在栈上,比如main里的AMGraph G,使用new动态开辟在堆上
  • 区分C和C++的不同点,比如C++不支持int parent[G.vexnum];这种写法
  • 不要打开std命名空间,比如你的程序的sort就和std::sort撞车了,可能会带来不必要的麻烦
  • 拆分函数的功能,比如sort将打印分离出去,kruskal函数也可以拆我懒得处理了
  • ...

你只要一点一点看我写的程序和你的比较,探究我为什么这么写(当然我写的不一定全是对的),就一定有收获

总得来说你写代码的能力有点弱(缺乏debug的能力),需要多多练习,C语言语法掌握得还算OK,但C++基本只会使用std::cinstd::cout,如果数据结构和算法能放一放那就先放一放,多去写写Online Judge练习一下debug能力,比如编程题 - PAT (Basic Level) Practice,如果不想学习C++,那么尽量把程序写成纯C的,比如用scanfprintf替代

有什么问题都可以在网站问我,我很乐意解答

#include<iostream>

const int MAX_WEIGHT = 32767;
const int NUM = 100;

//邻接矩阵来表示图
struct AMGraph {
    int vexnum, arcnum;
    int arcs[NUM][NUM];
    char vexs[NUM];
};

//定义边
struct EDGE {
    union {
        int lowcost;
        int length;
    };
    char begin, end;
};

//找出顶点在顶点数组的位置,如果没这个顶点,返回-1
int LocateVex(const AMGraph &G, char v)
{
    for (int i = 0; i < G.vexnum; i++)
        if (G.vexs[i] == v) return i;
    return -1;
}

//寻找根节点,输入是parent数组和要寻找其根节点的元素序号
//输出是根节点的序号
int Find(int parent[], int L)
{
    while (parent[L] > -1)
        L = parent[L];
    return L;
}

//冒泡法对边从小到大排序
void BubbleSort(EDGE Edge[], int length)
{
    for (int i = 0; i < length - 1; i++)
        for (int j = 0; j < length - 1 - i; j++)
            if (Edge[j].length > Edge[j + 1].length)
                std::swap(Edge[j], Edge[j + 1]);
}

void Print(EDGE Edge[], const AMGraph& G, const char * text)
{
    std::cout << '\n' << text << " is:\n";
    for (int i = 0; i < G.arcnum; i++)
        std::cout << Edge[i].begin << "<-->" << Edge[i].end << ": " << Edge[i].length << '\n';
}

//为无向图赋值,同时Edge数组初始化
void CreateVDN(AMGraph& G,EDGE Edge[])
{
    std::cout << "input the number of vexnum and arcnum separate with space key\n";
    std::cin >> G.vexnum >> G.arcnum;
    std::cout << "\ninput name of vertex\n";
    for (int i = 0; i < G.vexnum; i++){
        std::cout << "input No." << i + 1 << " vertex: ";
        std::cin >> G.vexs[i];
    }
    for (int i = 0; i < G.vexnum; i++)
        for (int j = 0; j < G.vexnum; j++)
            G.arcs[i][j]=i == j?0:MAX_WEIGHT;

    std::cout << "\ninput the weight of arc[weight vex1 vex2]:\n";
    for (int k = 0; k < G.arcnum;){
        EDGE in;
        std::cout << "input the No." << k + 1 << " arc: ";
        std::cin >> in.length >> in.begin >> in.end;
        int i = LocateVex(G, in.begin),j = LocateVex(G, in.end);
        if (i == -1 || j == -1){
            std::cout << "error data, retry!\n";
        }else{
            G.arcs[i][j] = G.arcs[i][j] = in.length;
            Edge[k++]=in;
        }
    }
}

//kruskal算法
//1.根据G的邻接矩阵初始化edge数组
//2.对edge数组进行排序
//3.创建parnet数组,根据edge数组对parent数组进行处理,并在处理时输出最小生成树的边
void Kruskal(const AMGraph &G,EDGE Edge[])
{
    Print(Edge, G, "the Edge[]");
    BubbleSort(Edge, G.arcnum);
    Print(Edge, G, "after sorting the Edge[]");

    int* parent = new int[G.vexnum];
    for (int i = 0; i < G.vexnum;i++)
        parent[i] = -1;
    std::cout << "\nmini tree :\n";

    //两个停止循环条件:要么循环完了,还没找到足够的边生成最小生成树,要么没循环完就找齐了边来生成最小生成树
    for (int num = 0, i = 0; i < G.arcnum && num < G.vexnum - 1; i++){
        int vex1 = Find(parent, LocateVex(G, Edge[i].begin));
        int vex2 = Find(parent, LocateVex(G, Edge[i].end));
        if (vex1 != vex2){          //如果是不同的树,就合并且生成一条边
            parent[vex2] = vex1;
            std::cout << Edge[i].begin << "<-->" << Edge[i].end << '\n';
            num++;
        }
    }
    delete[] parent;
}


int main()
{
    EDGE *E = new EDGE[99 * 50];
    AMGraph *G = new(AMGraph);
    CreateVDN(*G,E);
    Kruskal(*G,E);
    delete G;
    delete[] E;
    return 0;
}