《算法》第四版algs4:union-find并查集C++实现

github地址:https://github.com/Nwpuer/algs4-in-cpp
QuickFindUF实现(在文件"quick_find_uf"中)

#pragma once 
#include <vector>
#include <string> 
#include <stdexcept>
#include <iostream>


class QuickFindUF {
private:
    std::vector<size_t> id;
    size_t count;
public: 
    QuickFindUF(size_t n):count(n) {
        id.reserve(n);//improve the performance
        for (size_t i = 0; i < n; ++i)
            id.push_back(i);
    }

    size_t Count() const {
        return count;
    }

    bool Connected(size_t p, size_t q) const {
        return Find(p) == Find(q);
    }

    size_t Find(size_t p) const {
        Validate(p);
        return id[p];
    }

    void Union(size_t p, size_t q) {
        Validate(p);
        Validate(q);

        auto pID = id[p];
        auto qID = id[q];

        if (pID == qID) return;

        for (size_t i = 0; i < id.size(); ++i) 
            if (id[i] == pID) 
                id[i] = qID;
        --count;
    }

private: 
    void Validate(size_t p) const {
        if (p >= id.size())
            throw std::out_of_range("index out of range");
    }

public:
    static void MainTest() {
        size_t n;
        std::cin >> n;
        QuickFindUF uf(n);
        size_t p, q;
        while (std::cin >> p >> q) {
            if (uf.Connected(p, q)) continue;
            uf.Union(p, q);
            std::cout << p << " " << q << std::endl;
        }
        std::cout << uf.Count() << " components" << std::endl;
    }
};

QuickUnionUF实现(在文件"quick_union_uf"中)

#pragma once 
#include <vector>
#include <string> 
#include <stdexcept>
#include <iostream>


class QuickUnionUF {
private:
    std::vector<size_t> id;
    size_t count;
public: 
    QuickUnionUF(size_t n):count(n) {
        id.reserve(n);//improve the performance
        for (size_t i = 0; i < n; ++i)
            id.push_back(i);
    }
    
    size_t Count() const {
        return count;
    }

    bool Connected(size_t p, size_t q) const {
        return Find(p) == Find(q);
    }

    size_t Find(size_t p) const {
        Validate(p);
        while (p != id[p])
            p = id[p];
        return p;
    }

    void Union(size_t p, size_t q) {
        Validate(p);
        Validate(q);

        auto pRoot = Find(p);
        auto qRoot = Find(q);

        if (pRoot == qRoot) return;

        id[pRoot] = qRoot;
        --count;
    }

private: 
    void Validate(size_t p) const {
        if (p >= id.size())
            throw std::out_of_range("index out of range");
    }

public:
    static void MainTest() {
        size_t n;
        std::cin >> n;
        QuickUnionUF uf(n);
        size_t p, q;
        while (std::cin >> p >> q) {
            if (uf.Connected(p, q)) continue;
            uf.Union(p, q);
            std::cout << p << " " << q << std::endl;
        }
        std::cout << uf.Count() << " components" << std::endl;
    }
};

WeightedQuickUnionUF实现(在文件"weighted_quick_union_uf"中)

#pragma once 
#include <vector>
#include <string> 
#include <stdexcept>
#include <iostream>


class WeightedQuickUnionUF {
private:
    std::vector<size_t> id;
    size_t count;
    std::vector<size_t> sz;
public: 
    WeightedQuickUnionUF(size_t n):count(n) {
        id.reserve(n);//improve the performance
        for (size_t i = 0; i < n; ++i)
            id.push_back(i);
        sz.reserve(n);
        for (size_t i = 0; i < n; ++i)
            sz.push_back(1);
    }

    size_t Count() const {
        return count;
    }

    bool Connected(size_t p, size_t q) const {
        return Find(p) == Find(q);
    }

    size_t Find(size_t p) const {
        Validate(p);
        while (p != id[p])
            p = id[p];
        return p;
    }

    void Union(size_t p, size_t q) {
        Validate(p);
        Validate(q);

        auto pRoot = Find(p);
        auto qRoot = Find(q);

        if (pRoot == qRoot) return;

        if (sz[pRoot] < sz[qRoot]) {
            id[pRoot] = qRoot;
            sz[pRoot] += sz[qRoot];
        }
        else {
            id[qRoot] = pRoot;
            sz[pRoot] += sz[qRoot];
        }
        --count;
    }

private: 
    void Validate(size_t p) const {
        if (p >= id.size())
            throw std::out_of_range("index out of range");
    }

public:
    static void MainTest() {
        size_t n;
        std::cin >> n;
        WeightedQuickUnionUF uf(n);
        size_t p, q;
        while (std::cin >> p >> q) {
            if (uf.Connected(p, q)) continue;
            uf.Union(p, q);
            std::cout << p << " " << q << std::endl;
        }
        std::cout << uf.Count() << " components" << std::endl;
    }
};

测试代码(文件"uf_test.cpp")

#include <iostream>
#include <fstream>
#include "quick_find_uf.h"
#include "quick_union_uf.h"
#include "weighted_quick_union_uf.h"

int main() {
    std::ifstream in("../data/tinyUF.txt");
    std::cin.rdbuf(in.rdbuf());//重定向cin

    //QuickFindUF::MainTest();
    //QuickUnionUF::MainTest();
    WeightedQuickUnionUF::MainTest();
}

代码实现的时候的几个注意点:
1.将接口的首字母大写,因为接口union()与C++关键字union冲突。为防止以后还出现这种情况,以后接口的首字母都大写。
2.id_中的数据使用size_t而不用int的原因:
size_t是一个sizeof()返回的类型,是一个无符号数,大小足以容纳任何序列的长度,也就是如论你序列有多长,它的大小都可以用size_t来表示。具有跨平台的特性。这里将id里面的数声明为size_t是因为在类的初始化成员函数中,每个位置的值都是它所在的索引,所以值是与vector的大小相关的。用int不太合适,因为可能会溢出,用size_t更好。
size_t其实就是size_type,是一个表示大小,任何大小都可以表示,当有数数儿的行为的时候,并且确保不为负数,适合用它。
3.这里添加了一个Validate()函数,防止越界。JAVA中数组越界会自动被检测出来,所以书中源代码不需要检测;而C++中不会,所以需要我们额外关注。

在了解完如何实现一个并查集后,你也许想要实践一下,不如看看:
https://blog.csdn.net/weixin_43462819/article/details/83628052

猜你喜欢

转载自blog.csdn.net/weixin_43462819/article/details/83626022