不相交集是种用于合并的数据结合,在kruskal算法中有用到。它用到的两个技术挺有意思的,一是按秩合并;二是路径压缩;这两种技术都是用来控制树的高度的。因为如果树的高度过高,那么搜索一个元素所花费的时间就会增加。 #ifndef __DISJOINTSET_H__ #define __DISJOINTSET_H__ #include <assert.h> class DisjointSet { public: struct Node; typedef struct Node Node; typedef int Item; struct Node { Node* m_parent; // 父节点 int m_rank; // 秩 Item m_item; // 表示序号 Node() { m_parent = 0; m_rank = 0; } Node(int rank, Node* parent = 0) { m_parent = parent; m_rank = rank; } }; DisjointSet(); DisjointSet(Node* nodeSet, int size); ~DisjointSet(); Node* Find(Node* pNd); void Union(Node* pNd1, Node* pNd2); inline Node* GetNode(int i) const { assert(i>=0 && i<m_size); return &m_nodeSet[i]; } inline void SetData(Node* nodeSet, int size) { m_nodeSet = nodeSet; m_size = size; }; protected: Node* m_nodeSet; // 数组的下标代表节点的序号(m_item) int m_size; // the size of disjoint set }; #endif 实现文件 #include "DisjointSet.h" ////////////////////////////////////////////////////////////////////////// // constructor/destructor DisjointSet::DisjointSet() { m_nodeSet = 0; m_size = 0; } DisjointSet::DisjointSet(Node* nodeSet, int size):m_nodeSet(nodeSet), m_size(size) { } DisjointSet::~DisjointSet() { } /************************************************************************/ /* 输入:某个节点 /* 输出:该节点所在树的根的指针 /* 说明:执行路径压缩,以缩短每个节点到其根节点的距离,加快后续的寻找速度*/ /************************************************************************/ DisjointSet::Node* DisjointSet::Find(Node* pNd) { Node* root; Node* parent = pNd; // 寻找根节点(根节点的parent为0) while (parent->m_parent) { parent = parent->m_parent; } root = parent; // 对非根节点(parent非0)执行路径压缩 Node* temp = pNd; while (temp->m_parent) { parent = temp->m_parent; temp->m_parent = root; temp = parent; } return root; } /************************************************************************/ /* 输入:节点nd1、节点nd2 输出:合并nd1所在的集合(或树)和nd2所在的集合(或树) 说明:按秩合并措施,以缩短合并之后树的高度 */ /************************************************************************/ void DisjointSet::Union(Node* pNd1, Node* pNd2) { Node* root1 = Find(pNd1); Node* root2 = Find(pNd2); // 执行按秩合并 if (root1->m_rank <= root2->m_rank) { root1->m_parent = root2; if (root1->m_rank == root2->m_rank) { root2->m_rank += 1; } } else { root2->m_parent = root1; } } 测试文件 #include <iostream> #include "DisjointSet.h" using namespace std; typedef DisjointSet::Node Node; int main() { int const size = 5; Node node[size]; int index = 0; while (index < size) { node[index].m_item = index++; } //DisjointSet disjointSet; //disjointSet.SetData(node, size); DisjointSet disjointSet(node, size); index = 1; while (index < size) { disjointSet.Union(disjointSet.GetNode(index-1), disjointSet.GetNode(index)); index++; } index = 0; Node* root = 0; while(index < size) { cout << index << ": " << node[index].m_rank << " "; root = disjointSet.Find(node + index); if (root) { cout << root->m_item << endl; } else { cout << "root /n"; } index++; } return 0; }