数据结构—图的kruskal算法

Kruskal算法的思想如下

  1. 假设有n个顶点的连通图。首先先构造有顶点构成的集合0,每个顶点都是一个集合,不含有任何边。
  2. 在边找一个最小权值的边
  3. 判断这个边的俩个顶点是否来自于两个不同的集合,若是就将它俩归并为一个集合,然后将这个边添加到要构成的图的集合中。
  4. 直到上述的边的个数为顶点个数-1;否则,重复2-3;
    算法构成树的过程如下:
    如a图所示的图,下面是最小生成树的构造过程


    image.png

(a)


image.png

(b)


image.png

(c)


image.png

(d)


image.png

(e)


image.png

(f)


image.png

在这里判断一个边的两个顶点是不是属于同一个集合,采用的是并查集的方式来实现

并查集的基本思想如下:

并查集可以用数组来和树来实现,在这里先讲树来实现。
1:树实现并查集:
属于同一个集合的结点拥有同一个根,图示如下:

image.png

上面的树中这些元素都属于一个集合,他们的根元素是1;


image.png

上面树中元素属于都属于一个集合,他们的根元素都是11;
两个集合合并就是将一个集合连在另一个集合的根元素的下面就好了。如下图所示:


image.png

那在合并集合的时候怎么合并集合呢?有没有想过,如下图所示的集合


image.png

一个树的高度很大,一个树的高度很小,这俩个集合在合并的时候要把高度小的集合合并在高度大的集合中。因为在合并集合中的元素的时候,首先要查找这个结点属于那个结点,若是将高度高的集合合并在高度小的集合中,就会增加查找的时间,增加程序的时间复杂度。
数组实现并查集
基本思想就是,在属于一个集合的数据都用一个数据来表示就好,在合并集合的时候,就将两个集合用一个数据来表示就好了,
如下图:

image.png

有0——7个数据;刚开始的时候他们都是一个集合,单独的个体,每个的根都是自己本身,-1表示他们都是单独个个体,是个根,在查找根结点的时候就是一个判断依据,只要对应的数据项是负数,那就说明这个是根;现在将1和2合并为一个集合如下图:


image.png

将1对应数据项和2对应的数据项合并在一起,放在1对应的数据项中,在这里面就是-1+-1;将2对应的数据项改为1,表示它的根现在是1;这就是一个集合。
现在将4,5归为一个集合如下图:

image.png

原理和上面的一样
现在讲3添加到2所集合中如下图:


image.png

首相查找2的根,发现是1,然后在查找3的根,发现是3,然后在1对应的数据项中加上3对应的数据项。也就是-2+-1;然后将3对应的数据项改为-1;
现在将5所在的集合和3所在的集合合并在一块如下图:


image.png

先查找5所在的根结点,发现是是4;现在在查找3所在的结点,发现是1;然后还是是和之前一样相加。将4对应的数据项和1对应的数据项相加,合并两个根就好,然后将4对应的数据项改为1;
现在6加到5所在的集合中如下图:


image.png

查找5所在的集合,5对应的数据项是4,4对应的数据项是1,1对应的数据项是负数,说明这个是根,然后还是相加,还是合并;就好了
</br>
好了,并查集讲完了接下来就是树了
算法的流程图如下:

未命名文件.jpg

程序如下:

#include <iostream>
using namespace std;
typedef struct node  {
    int start;//边的起点
    int end;//边的终点
    int wieght;//边的权重
}node;
class Graph{
private:
    node *edge; //边的数组
    int edgeNum;//边的个数
    int vertexNum;//顶点的个数
    int* unionset;//并查集,顶点的集合
#pragma 下面的这几个private函数都是并查集的函数
    int findRoot(int node);//找根
    void unionSet(int node1,int node2);//合并俩结点成为一个集合
    bool isaSet(int node1,int node2);//判断俩结点在没在一个集合中
public:
    Graph(int size,int vertexNum);
    void create();
    void sort();//冒泡法按照权值从大到小的顺序排序;
    void kuscal();//kruskal算法;
    void print();//输出边的数组和 顶点的集合,
};
void Graph::print(){
    cout<<"unionSet-----------------------------------------------------\n";
    for (int i = 0; i<vertexNum+1; i++) {
        cout<<i<<":"<<unionset[i]<<endl;
    }
    cout<<"unionset______________________________________________________\n";
    
    for (int i =0; i<2; i++) {
        cout<<endl;
    }
    cout<<"edge----------------------------------------------------------\n";
    for (int i = 0; i<edgeNum; i++) {
        cout<<"("<<edge[i].start<<","<<edge[i].end<<","<<edge[i].wieght<<")";
    }
    cout<<endl;
    cout<<"edge__________________________________________________________\n";
}
//看是否在同一个集合,如果在一个集合,返回True,否则返回false;
bool  Graph::isaSet(int node1, int node2){
    return findRoot(node1)==findRoot(node2) ? true : false;
}


//把node2添加到node1集合中
void Graph::unionSet(int node1, int node2){
    int root1 = findRoot(node1);
    int root2 = findRoot(node2);
    unionset[root1]+=unionset[root2];
    unionset[root2] = root1;
}


void Graph::sort(){
    for (int i = 0; i<edgeNum -1; i++) {
        for (int j = 0; j<edgeNum-1-i; j++) {
            if(edge[j].wieght < edge[j+1].wieght){
                int temp = edge[j].wieght;
                int start = edge[j].start;
                int end = edge[j].end;
                edge[j].wieght = edge[j+1].wieght;
                edge[j+1].wieght = temp;
                
                edge[j].start = edge[j+1].start;
                edge[j+1].start = start;
                
                edge[j].end = edge[j+1].end;
                edge[j+1].end = end;
            }
        }
    }
    print();
}

int Graph::findRoot(int node){
    int root = node;
    while (unionset[root] >= 0) {
        root = unionset[root];
    }
    return  root;
}

Graph::Graph(int size,int vertexNum){
    edge = new node[size];
    edgeNum = size;
    this->vertexNum = vertexNum;
    /*
     1:一般来说,多申请一个,这样有利于数据的统一
     */
    unionset = new int[vertexNum+1];
    for (int i = 0; i<vertexNum+1; i++) {
        unionset[i]= -1;
    }
}

void Graph::create(){
    cout<<"input edge start and end and widght\n";
    for (int i = 0; i<edgeNum; i++) {
        cin>>edge[i].start>>edge[i].end>>edge[i].wieght;
    }

}
void Graph::kuscal(){
    sort();
    int edgeNum1 = 0;//找到的满足要求的边的个数
    int sum = 0;//找的满足要求的边的权重和�
    int i = edgeNum-1;//控制边数组的下标,从后往前取,最小值在后面
    while (edgeNum1 != this->vertexNum-1 ) {
        int start = edge[i].start;
        int end = edge[i].end;
        
        if( isaSet(start, end) == false){
            unionSet(start, end);
            edgeNum1++;
            sum+=edge[i].wieght;
        }
        I--;
    }
    cout<<"sum"<<sum<<endl;
}
int main(){
    Graph a(8, 6);
    a.create();
    a.print();
    a.kuscal();
    a.print();
}

测试的时候用的图就是这个图
image.png

输入如下:


image.png

输出如下:


image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容