表格线识别通用库文档
载入中...
搜索中...
未找到
disjoint_set.hpp
浏览该文件的文档.
1/*
2 * @Description: 并查集 头文件及其实现
3 * @Version:
4 * @Autor: dreamy-xay
5 * @date: 2023-12-31
6 * @LastEditors: dreamy-xay
7 * @LastEditTime: 2024-03-06
8 */
9
10#ifndef COMMON_DISJOINT_SET_HPP
11#define COMMON_DISJOINT_SET_HPP
12
13#include <iostream>
14#include <unordered_map>
15#include <vector>
16
17#include "common/base/list.hpp"
18#include "common/enum.h"
19#include "common/macro.h"
20#include "common/type.h"
21
22namespace cm {
23
33template <typename T>
35 private:
36 std::vector<T> data; // 原始数据
37 std::vector<size_t> parent; // 指定索引原始所在的集合的根节点数组
38 std::vector<size_t> count; // 以指定索引为根所对应的集合的大小数组
39
40 T* data_ptr; // 原始数据指针(加速访问)
41 size_t* parent_ptr; // 根节点数组指针(加速访问)
42 size_t* count_ptr; // 集合大小数组指针(加速访问)
43
44 public:
46 explicit DisjointSet(const std::vector<T>& list);
47 template <typename ITERATOR>
48 explicit DisjointSet(ITERATOR start_iterator, ITERATOR end_iterator);
49 DisjointSet(const std::initializer_list<T>& inital_list);
51 DisjointSet(const DisjointSet& disjoint_set) = default;
53
54 DisjointSet& Reserve(size_t size);
55 DisjointSet& Resize(size_t size);
56 DisjointSet& Assign(const std::vector<T>& list);
57 template <typename ITERATOR>
58 DisjointSet<T>& Assign(ITERATOR start_iterator, ITERATOR end_iterator);
59 DisjointSet& Swap(DisjointSet<T>& disjoint_set);
61 size_t Size() const;
62 T* Data();
63 const T* Data() const;
64
65 size_t RootIndex(size_t index);
66 bool IsUnion(size_t index1, size_t index2);
67 DisjointSet& Union(size_t index1, size_t index2);
68 size_t CollectionSize(size_t index);
69 size_t CollectionsSize();
70 template <typename FUNC>
71 DisjointSet<T>& UnionAll(const FUNC& is_union);
73};
74
82template <typename T>
83inline DisjointSet<T>::DisjointSet() : data_ptr(nullptr), parent_ptr(nullptr), count_ptr(nullptr) {}
84
94template <typename T>
95inline DisjointSet<T>::DisjointSet(const std::vector<T>& list) : data_ptr(nullptr), parent_ptr(nullptr), count_ptr(nullptr) {
96 this->Assign(list);
97}
98
111template <typename T>
112template <typename ITERATOR>
113inline DisjointSet<T>::DisjointSet(ITERATOR start_iterator, ITERATOR end_iterator) : data_ptr(nullptr), parent_ptr(nullptr), count_ptr(nullptr) {
114 this->Assign(start_iterator, end_iterator);
115}
116
128template <typename T>
129inline DisjointSet<T>::DisjointSet(const std::initializer_list<T>& inital_list) : data_ptr(nullptr), parent_ptr(nullptr), count_ptr(nullptr) {
130 this->Assign(inital_list.begin(), inital_list.end());
131}
132
140template <typename T>
142
165template <typename T>
167 data.reserve(size);
168 parent.reserve(size);
169 count.reserve(size);
170
171 return *this;
172}
173
201template <typename T>
203 data.resize(size);
204 parent.resize(size);
205 count.resize(size);
206
207 return *this;
208}
209
231template <typename T>
232inline DisjointSet<T>& DisjointSet<T>::Assign(const std::vector<T>& list) {
233 this->Clear(); // 如果存在数据则清空原来数据
234
235 this->Resize(list.size());
236
237 int list_len = list.size();
238
239 // 加速索引
240 const T* list_ptr = list.data();
241
242 // 初始化原始数据指针
243 data_ptr = data.data();
244 parent_ptr = parent.data();
245 count_ptr = count.data();
246
247 // 初始化所有值
248 for (size_t i = 0; i < list_len; ++i) {
249 data_ptr[i] = list_ptr[i];
250 parent_ptr[i] = i;
251 count_ptr[i] = 1;
252 }
253
254 return *this;
255}
256
284template <typename T>
285template <typename ITERATOR>
286inline DisjointSet<T>& DisjointSet<T>::Assign(ITERATOR start_iterator, ITERATOR end_iterator) {
287 this->Clear(); // 如果存在数据则清空原来数据
288
289 // 初始化所有值
290 for (size_t i = 0; start_iterator < end_iterator; ++i, ++start_iterator) {
291 data.emplace(*start_iterator);
292 parent.emplace_back(i);
293 count.emplace_back(1);
294 }
295
296 // 初始化原始数据指针
297 data_ptr = data.data();
298 parent_ptr = parent.data();
299 count_ptr = count.data();
300
301 return *this;
302}
303
326template <typename T>
328 data.swap(disjoint_set.data);
329 parent.swap(disjoint_set.parent);
330 count.swap(disjoint_set.count);
331
332 return *this;
333}
334
344template <typename T>
346 data.clear();
347 parent.clear();
348 count.clear();
349
350 return *this;
351}
352
362template <typename T>
363inline size_t DisjointSet<T>::Size() const {
364 return data.size();
365}
366
376template <typename T>
378 return data.data();
379}
380
390template <typename T>
391inline const T* DisjointSet<T>::Data() const {
392 return data.data();
393}
394
413template <typename T>
414inline size_t DisjointSet<T>::RootIndex(size_t index) {
415 if (index != parent_ptr[index])
416 parent_ptr[index] = this->RootIndex(parent_ptr[index]); // 路径压缩
417
418 return parent_ptr[index];
419}
420
442template <typename T>
443inline bool DisjointSet<T>::IsUnion(size_t index1, size_t index2) {
444 return this->RootIndex(index1) == this->RootIndex(index2);
445}
446
466template <typename T>
467inline DisjointSet<T>& DisjointSet<T>::Union(size_t index1, size_t index2) {
468 // 获取 指定索引数据项 所对应的集合 的根节点数据索引
469 size_t index1_root = this->RootIndex(index1);
470 size_t index2_root = this->RootIndex(index2);
471
472 // 如果不在同一个集合中,则合并
473 if (index1_root != index2_root) {
474 parent_ptr[index1_root] = index2_root;
475 count_ptr[index1_root] += 1; // 更新集合大小
476 }
477
478 return *this;
479}
480
499template <typename T>
500inline size_t DisjointSet<T>::CollectionSize(size_t index) {
501 return count_ptr[this->RootIndex(index)];
502}
503
519template <typename T>
521 size_t size = 0; // 并查集集合数量
522
523 // 先根据每个集合的根节点创建集合列表
524 for (int i = int(data.size()) - 1; i >= 0; --i)
525 size += this->RootIndex(i) == i;
526
527 return size;
528}
529
557template <typename T>
558template <typename FUNC>
559inline DisjointSet<T>& DisjointSet<T>::UnionAll(const FUNC& is_union) {
560 // 数据长度
561 int data_len = data.size();
562
563 // 遍历全部数据项组合(一对数据项)
564 for (size_t i = 0; i < data_len; ++i)
565 for (size_t j = i + 1; j < data_len; ++j)
566 if (is_union(data_ptr[i], data_ptr[j]))
567 this->Union(i, j); // 合并数据项
568
569 return *this;
570}
571
606template <typename T>
608 List<List<T>> all_collections; // 所有集合列表
609 std::unordered_map<size_t, size_t> collection_index; // 每个集合根节点数据索引 在 all_collections 中对应的集合索引
610
611 // 数据长度
612 int data_len = data.size();
613
614 // 先根据每个集合的根节点创建集合列表
615 for (int i = 0; i < data_len; ++i)
616 if (this->RootIndex(i) == i) {
617 collection_index[i] = all_collections.size();
618 all_collections.push_back(std::vector<T>({data_ptr[i]}));
619 }
620
621 // 再在每个集合中添加集合非根节点数据项
622 for (int i = 0; i < data_len; ++i)
623 if (parent_ptr[i] != i)
624 all_collections[collection_index[parent_ptr[i]]].emplace_back(data_ptr[i]);
625
626 // 返回所有集合列表
627 return std::move(all_collections);
628}
629
630} // namespace cm
631
632#endif
并查集类
List< List< T > > GetAllCollections()
获取所有集合数据
~DisjointSet()
并查集类的析构函数
DisjointSet & Assign(const std::vector< T > &list)
重新赋值并查集
DisjointSet & Resize(size_t size)
调整并查集对象的大小
DisjointSet & Reserve(size_t size)
重置并查集所对应的空间大小
DisjointSet & Clear()
清空所有数据
T * Data()
获取并查集类的数据指针
DisjointSet< T > & UnionAll(const FUNC &is_union)
根据提供的判断条件对并查集中所有的数据项进行两两合并
size_t Size() const
获取并查集类的数据大小
size_t CollectionSize(size_t index)
获取单个集合的大小
DisjointSet & Union(size_t index1, size_t index2)
合并两个指定索引数据项
bool IsUnion(size_t index1, size_t index2)
判断并查集中两个指定索引数据项是否在同一个集合中
size_t CollectionsSize()
获取集合的数量
DisjointSet(const DisjointSet &disjoint_set)=default
并查集类的拷贝构造函数
DisjointSet & Swap(DisjointSet< T > &disjoint_set)
交换并查集
size_t RootIndex(size_t index)
获取并查集根节点数据索引
DisjointSet()
并查集类的默认构造函数
列表类
Definition list.hpp:36