Prim算法和Kruskal算法的基本思想和实现

这两个都是求最小生成树的算法,个人更喜欢Kruskal算法。

Prim算法

基本思想

有两个集合,A是空集,B集合里有现在图中的所有边。
将B中任意一点加入A集合,在这个点的所用通路中选择一个权值最小的边且这个边到的点不在B集合之中。然后将这个点加入A集合,再进行上述步骤,直到将B集合变成空集。

代码实现

#include
using namespace std;
const int INF=1<<30;
const int maxn=110;
typedef struct {
    int mp[maxn][maxn];
    int number;
}Graph;
void prim(Graph &a)
{
    int min,i,j,k;
    int adj[maxn],lowcost[maxn];
    lowcost[0]=0;//值为0代表已经放入A集合
    adj[0]=0;
    for(int i=1;i0][i];//初始化lowcost和adj数组。lowcost代表现在点到各个点的距离
        adj[i]=0;
    }
    for(int i=1;iint min=INF;
        int j=1,k=0;
        while(j < a.number)
        {
            if( lowcost[j]!=0 && lowcost[j]//在集合B中选出一个最小的边
                min = lowcost[j];
                k=j;
            }
            j++;
        }
        cout<<"("<","<")"<0;
        for(int j=1;jif(lowcost[j]!=0 && a.mp[k][j]//因为有新的点加入A集合,对应的数组更新
                adj[j]=k;
            }
        }
    }
}
int main()
{
    freopen("in.txt","r",stdin);
    Graph a;
    int v,e,x,y,w;
    cin>>v>>e;
    a.number=v;
    for(int i=0;ifor(int j=0;jfor(int i=0;i0;
    for(int i=0;icin>>x>>y>>w;
        a.mp[x][y]=w;
        a.mp[y][x]=w;
    }
    prim(a);
    return 0;
}

Kruskal算法

基本思路

学习Kruskal算法需要前置知识:并查集,一个简单但实用的数据结构。
学习链接:并查集的基本思想和实现
将并查集应用在图上还需要另外一个数据结构:边集数组
就是一个三位数组,里面存的是起始点,终止点,边权。
将这个数组以边权大小排序,小的在前。
然后按照顺序将数组中存的点连接起来,形成集合。而连起点的前提条件就是不属于一个集合。这个集合的判断就需要用到并查集了。在连接的时候也需要用到并查集进行合并。
直到将所有的点都合并为一个集合,循环结束。

代码实现

#include
using namespace std;
const int maxn=110;
typedef struct{
    int begin,end,weight;
}Edge;
int FindSet(int x,int *father)
{

    if(x!=father[x])
        father[x]=FindSet(father[x],father);
    return father[x];
}
bool Union(int x,int y,int *father,int *rank)
{
    x=FindSet(x,father);
    y=FindSet(y,father);
    if(x==y)//属于同一集合,不进行合并操作
        return false;
    if(rank[x]>rank[y])
        father[y]=x;
    else{
        if(rank[x]==rank[y])
            rank[y]++;
        father[x]=y;
    }
    return true;
}
bool cmp(Edge a,Edge b)
{
    return a.weightbool isfull(bool *flag,int n)//判断所有的点都属于一个集合了
{
    for(int i=0;iif(!flag[i])
            return false;
    }
    return true;
}
int main()
{
   // freopen("in.txt","r",stdin);
    Edge a[maxn];
    bool flag[maxn];
    int v,e;
    cin>>v>>e;
    memset(flag,false,sizeof(flag));
    for(int i=0;icin>>a[i].begin>>a[i].end>>a[i].weight;
    int father[maxn],rank[maxn];
    for(int i=0;i0;
    }
    sort(a,a+e,cmp);
    for(int i=0;iif(isfull(flag,v))
            break;
        Union(a[i].begin,a[i].end,father,rank);//每次将两个集合进行合并
        cout<<"("<","<")"<true;
        flag[a[i].end]=true;
    }
    return 0;
}

你可能感兴趣的:(Prim算法和Kruskal算法的基本思想和实现)