C语言 union-find算法 图的连通性

连通分量

任何连通图的连通分量只有一个,即是其自身,非连通的无向图有多个连通分量。
比如:
这里写图片描述
图(a)的连通分量只有一个,而图(b)的连通分量有6个。

现在有数据如下,怎么判断有多少个连通分量?

    int e[10][2] = {
        { 4, 3 },  //两个节点之间相互连接
        { 3, 8 },
        { 6, 5 },
        { 9, 4 },
        { 2, 1 },
        { 8, 9 },
        { 5, 0 },
        { 7, 2 },
        { 6, 1 },
        { 1, 0 },
    };

我们主要有两种算法:quick-find算法和quick-union算法

代码实现

ADT

#include <stdio.h>
#include <malloc.h>
#include <memory.h>
#include <assert.h>
#define MAXVEX 100
#define MAXNUM 10
#define BOOLEAN int
#define VTYPE int
#define TRUE 1
#define FALSE 0


typedef struct UF
{
    int count;  //连通分量数量
    VTYPE id[MAXNUM];  //连通分量ID

    int(*countUF)(struct UF *);
    BOOLEAN(*connectedUF)(struct UF *, VTYPE, VTYPE);
    int(*findUF)(struct UF *, VTYPE);
    void(*unionUF)(struct UF *, VTYPE, VTYPE);
} UF, *UFPtr;

int countUF(UFPtr this);
BOOLEAN connectedUF(UFPtr this, VTYPE p, VTYPE q);

/*********find算法*********/
int findUF(UFPtr this, VTYPE p);
void unionUF(UFPtr this, VTYPE p, VTYPE q);
/*********find算法*********/

UFPtr newUF();

quick-find算法

quick-find算法通过遍历整个数组,将与p的分量值相同的重命名为q的分量值,使得两个分量归并在一起

int findUF(UFPtr this, VTYPE p) {
    return this->id[p];
}
void unionUF(UFPtr this, VTYPE p, VTYPE q) {
    //将p和q归并到相同的分量中
    int pID = this->findUF(this, p);
    int qID = this->findUF(this, q);

    if (pID == qID)
        return;

    //将p的分量重命名为q的名称
    for (int i = 0; i < MAXNUM; i++) {
        if (this->id[i] == pID) {
            this->id[i] = qID;
        }
    }
    this->count--;
}

quick-union算法

quick-union算法是通过构造树,结点的分量指向触点的分量,而根节点的分量则指向自身。union则是将两个分量的根节点都指向其中一个节点的分量,从而实现连通分量归并。
这里写图片描述

int findUF_2(UFPtr this, VTYPE p) {
    //找出根节点的分量名称
    while (p != this->id[p])
        p = this->id[p];
    return p;
}
void unionUF_2(UFPtr this, VTYPE p, VTYPE q) {
    int pRoot = this->findUF(this, p);
    int qRoot = this->findUF(this, q);

    if (pRoot == qRoot)
        return;

    this->id[pRoot] = qRoot;

    this->count--;
}

quick-find和quick-sort的完整代码

#include <stdio.h>
#include <malloc.h>
#include <memory.h>
#include <assert.h>
#define MAXVEX 100
#define MAXNUM 10
#define BOOLEAN int
#define VTYPE int
#define TRUE 1
#define FALSE 0


typedef struct UF
{
    int count;
    VTYPE id[MAXNUM];

    int (*countUF)(struct UF *);
    BOOLEAN (*connectedUF)(struct UF *, VTYPE, VTYPE);
    int (*findUF)(struct UF *, VTYPE);
    void (*unionUF)(struct UF *, VTYPE, VTYPE);
} UF, *UFPtr;

int countUF(UFPtr this) {
    return this->count;
}

BOOLEAN connectedUF(UFPtr this, VTYPE p, VTYPE q) {
    if (this->findUF(this, p) == this->findUF(this, q))
        return TRUE;
    return FALSE;
}

/*********quick-find算法*********/

int findUF(UFPtr this, VTYPE p) {
    return this->id[p];
}
void unionUF(UFPtr this, VTYPE p, VTYPE q) {
    int pID = this->findUF(this, p);
    int qID = this->findUF(this, q);

    if (pID == qID)
        return;

    for (int i = 0; i < MAXNUM; i++) {
        if (this->id[i] == pID) {
            this->id[i] = qID;
        }
    }
    this->count--;
}

/*********quick-find算法*********/

/*********quick-union算法*********/

int findUF_2(UFPtr this, VTYPE p) {
    //找出根节点的分量名称
    while (p != this->id[p])
        p = this->id[p];
    return p;
}
void unionUF_2(UFPtr this, VTYPE p, VTYPE q) {
    int pRoot = this->findUF(this, p);
    int qRoot = this->findUF(this, q);

    if (pRoot == qRoot)
        return;

    this->id[pRoot] = qRoot;

    this->count--;
}

/*********quick-union算法*********/

UFPtr newUF() {
    UFPtr uf= (UFPtr)malloc(sizeof(UF));
    memset(uf, 0, sizeof(uf));
    assert(uf != NULL);
    uf->count = MAXNUM;
    for (int i = 0; i < MAXNUM; i++) {
        uf->id[i] = i;
    }

    uf->countUF = countUF;
    uf->connectedUF = connectedUF;
    uf->findUF = findUF;
    uf->unionUF = unionUF;
    return uf;
}



void main() {
    // 3,4,8,9
    // 6,5,0
    // 2,1
    int e[10][2] = {
        { 4, 3 },
        { 3, 8 },
        { 6, 5 },
        { 9, 4 },
        { 2, 1 },
        { 8, 9 },
        { 5, 0 },
        { 7, 2 },
        { 6, 1 },
        { 1, 0 },
    };
    const int e_length_1 = 10;
    const int e_length_2 = 2;

    UFPtr uf = newUF();
    for (int i = 0; i < e_length_1; i++) {
        int p = e[i][0]; int q = e[i][1];
        if (uf->connectedUF(uf, p, q) == TRUE) {
            continue;
        }
        uf->unionUF(uf, p, q);
    }
    uf->countUF(uf);
    free(uf);
}

猜你喜欢

转载自blog.csdn.net/fpk2014/article/details/80624311