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