《演算法》第四版algs4:union-find並查集C++實現
阿新 • • 發佈:2018-11-06
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