View
114
Download
4
Category
Preview:
DESCRIPTION
集合 等价类与并查集. 第七章 集合. 一、集合. A={a,b,c}, B={b,d}. 若干个 同一类型 互不相同 的以 一定次序排 列 的元素 整形 集合 (整数,字符,枚举,记录) 若干 离散 有序元素组成的集合 每个元素可以 对应 唯一一个整数 int(a) ; //a 对应的整数. 集合的运算 a∈A A∪B={a,b,c,d} A∩B={b} A-B={a,c}. 集合的实现. 用 数组 实现 用 指针 实现 用 链表 实现 用 位运算 实现 整形集合. - PowerPoint PPT Presentation
Citation preview
集合集合 等价类与并查集等价类与并查集
一、集合
若干个同一类型互不相同的以一定次序排列的元素
整形集合(整数,字符,枚举,记录)若干离散有序元素组成的集合每个元素可以对应唯一一个整数 int(a) ; //a 对应的整数
A={a,b,c}, B={b,d}
集合的运算 a A∈ A B={a,b,c,d} ∪ A∩B={b}
A-B={a,c}
集合的实现
用数组实现 用指针实现 用链表实现 用位运算实现整形集合
位运算 或 | 与 & 非 ~ 异或 ^ 右移位 >> 左移位 <<
——————————————————
x y ~x x|y x&y x^y
——————————————————
0 0 1 0 0 0
0 1 1 1 0 1
1 0 0 1 0 1
1 1 0 1 1 0
x=11100011 y=01110110
x|y 11100011
01110110
11110111
x&y 11100011
01110110
01100010
~x = 00011100
x^y 11100011 01110110 10010101
unsigned short x=10, y=13,z;//2 字节 16 位 //x=1010, y=1101
z=x|y; //z=15z=x&y; //z=8z=x^y; //z=7z=~0<<2; //z=65532z=~0&(y>>2); //z=3
将 n 个元素固定成一列,每个下标代表一个元素每个元素 elt 的下标可以由 int(elt) 或用一个公式
算出
用一个 01 数组存储集合每一位写 0 或 1
0 代表某个元素不在集合中, 1 代表某个元素在集合中,n 个元素最少用多长的数组呢?
用 01 数组存储 n 个整形元素的集合
一个 unsigned short 整数占两个字节 16 位k 个 unsigned short 整数占两个字节 k*16 位
k*16=n, k=(n+15)/16, k=(n+15)>>4.
存储 n 个元素只要 k 个 unsigned short 整数
只要一个二进制位就可以存储 0 ,1
unsigned short *member;
member=new unsigned short[k];
14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 30 29 28 27 26 25 24 23 22 21 20 19 18 17 1615 31
1 1 1 1 1
A={a1,a7,a13,a18,a25}
确定一个元素在哪一个字节第几位
第 18 号元素 a18, 在 member[1] 2 号位
设第 s 号元素 , 在 member[i] j 号位
i=s/16=s>>4;
j=s%16=1 << (s & 15);
两集合 A,B 的并 按对应字节求或 | for(i=0;i<k;i++) C.member[i]= A.member[i] | B.member[i] ;
两集合的交 按对应字节求与 &for(i=0;i<k;i++)C.member[i]= A.member[i] & B.member[i] ;
x∈A 只要 A∩{x} 非空A.member[i] & (1<<j); //x 在 member[i] j 号
位
#ifndef SET_CLASS#define SET_CLASS#include <iostream.h>#include <stdlib.h>enum ErrorType{ InvalidMember, ExpectRightBrace, MissingValue, MissingComma, InvalidChar, MissingLeftBrace, InvalidInputData, EndOfFile, OutOfMemory, InvalidMemberRef, SetsDifferentSize};
template <class T>
class Set
{ private:
int setrange; // max number of elements in the set
int arraysize;
unsigned short *member;
void Error(ErrorType n) const;
int ArrayIndex(const T& elt) const;
unsigned short BitMask(const T& elt) const; public: Set(int sz); Set(const Set<T>& x);
~Set(void);
Set<T>& operator= (const Set<T>& rhs);
int IsMember(const T& elt);
int operator== (const Set<T>& x) const;
Set operator+ (const Set<T>& x) const; // union
Set operator* (const Set<T>& x) const;
void Insert(const T& elt); // set insertion
void Delete(const T& elt); //deletion operations
friend istream& operator>> (istream& istr, Set<T>& x);
friend ostream& operator<<(ostream&ostr, const Set<T>& x);
};
template <class T>void Set<T>::Error (ErrorType n) const{ cout << endl; switch(n) { case InvalidMember: cerr << "Invalid set member"; break; case ExpectRightBrace: cerr << "Expect right brace '}'"; break; case MissingValue: cerr << "Missing a value after a comma"; break; case MissingComma: cerr << "Separate members with a comma";break; case InvalidChar: cerr << "Invalid set character"; break;
case MissingLeftBrace: cerr << "Missing left brace '{'"; break; case InvalidInputData: cerr << "Invalid input data element"; break; case EndOfFile: cerr << "Premature end of file"; break; case OutOfMemory: cerr << "Memory allocation failure"; break; case InvalidMemberRef: cerr << "Invalid member reference"; break; case SetsDifferentSize: cerr << "Sets are not the same size"; break; } cout << endl; exit(1);}
template <class T>int Set<T>::ArrayIndex(const T& elt) const{ // convert elt to int and shift return int(elt) >> 4;}
template <class T> unsigned short Set<T>::BitMask(const T& elt) const{ // use & to find remainder after dividing by // 16. 0 stays in right-most bit, 15 goes on far left return 1 << (int(elt) & 15);}
// constructor. create an empty set
template <class T>
Set<T>::Set(int sz): setrange(sz)
{// number of unsigned shorts needed to hold set elements
arraysize = (setrange+15) >> 4;
// allocate the array
member = new unsigned short [arraysize];
if (member == NULL)
Error(OutOfMemory);
// create an empty set by setting all bits to 0
for (int i = 0; i < arraysize; i++)
member[i] = 0;
}
template <class T>Set<T>::Set(const Set<T>& x){ setrange = x.setrange; arraysize = x.arraysize; member = new unsigned short [arraysize]; if (member == NULL) Error(OutOfMemory); // copy set elements from x for (int i = 0; i < arraysize; i++) member[i] = x.member[i];}
template <class T>Set<T>::~Set(void){ delete [] member;}
template <class T>Set<T>& Set<T>::operator= (const Set<T>& rhs){ if (setrange != rhs.setrange) Error(SetsDifferentSize); // copy set elements from rhs for (int i = 0; i < arraysize; i++) member[i] = rhs.member[i]; return *this;}
// determine whether elt is in the set
template <class T>
int Set<T>::IsMember(const T& elt)
{
// is int(elt) in range 0 to setrange-1 ?
if (int(elt) < 0 || int(elt) >= setrange)
Error(InvalidMemberRef);
// return the bit corresponding to elt
return member[ArrayIndex(elt)] & BitMask(elt);
}
template <class T>int Set<T>::operator= = (const Set<T>& x) const
{ int retval = 1;// the sets must have the same range
if (setrange != x.setrange) Error(SetsDifferentSize);
for(int i=0;i < arraysize;i++)if (member[i] != x.member[i]){
retval = 0;break;
}return retval;
}
template <class T>Set<T> Set<T>::operator+ (const Set<T>& x) const{ // the sets must have the same range if (setrange != x.setrange) Error(SetsDifferentSize);
// form the union in tmp Set<T> tmp(setrange);
// each array element of tmp is the bitwise// OR of the current object and x
for (int i = 0; i < arraysize; i++) tmp.member[i] = member[i] | x.member[i]; // return the union return tmp;}
template <class T>Set<T> Set<T>::operator* (const Set<T>& x) const{ // the sets must have the same range if (setrange != x.setrange) Error(SetsDifferentSize);
// form the intersection in tmp Set<T> tmp(setrange);
// each array element of tmp is the bitwise// AND of the current object and x
for (int i = 0; i < arraysize; i++) tmp.member[i] = member[i] & x.member[i]; // return the intersection return tmp;}
// insert elt into the set
template <class T>
void Set<T>::Insert(const T& elt)
{
// is int(elt) in range 0 to setrange-1 ?
if (int(elt) < 0 || int(elt) >= setrange)
Error(InvalidMemberRef);
// set bit corresponding to elt
member[ArrayIndex(elt)] |= BitMask(elt);
}
// delete elt from the settemplate <class T>void Set<T>::Delete(const T& elt){ // is int(elt) in range 0 to setrange-1 ? if (int(elt) < 0 || int(elt) >= setrange) Error(InvalidMemberRef);
// clear the bit corresponding to elt. note // that ~BitMask(elt) has a 0 in the bit // we are interested in an 1 in all others member[ArrayIndex(elt)] &= ~BitMask(elt);}
template <class T>istream& operator>> (istream& istr, Set<T>& x){ char c; int haveComma = 0, needComma = 0; T elt; int i; for (i = 0; i < x.arraysize; i++) x.member[i] = 0; c = ' '; // skip leading white space while (c == ' ' || c == '\t' || c == '\n') if (istr.get(c) == 0) x.Error(EndOfFile); if (c != '{') x.Error(MissingLeftBrace); if (istr.get(c) == 0) x.Error(EndOfFile);
while (c != '}') { switch(c) { case ' ': case '\t': case '\n': break; case '{': x.Error(ExpectRightBrace); break; case ',': if (haveComma == 1) x.Error(MissingValue); else { haveComma = 1; needComma = 0; } break;
default: if (needComma) x.Error(MissingComma); istr.putback(c); if(istr >> elt == 0) x.Error(InvalidInputData); if (int(elt) < 0 || int(elt) >= x.setrange) x.Error(InvalidInputData); x.member[x.ArrayIndex(elt)] |= x.BitMask(elt); needComma = 1; haveComma = 0; break; }
if (istr.get(c) == 0) x.Error(EndOfFile); } if (haveComma == 1) x.Error(MissingValue); return istr;}
template <class T>ostream& operator<< (ostream& ostr, const Set<T>
& x){ int i, j, setElt; int needComma = 0; T elt; ostr << "{"; for (setElt = 0; setElt < x.setrange; setElt++) { if (x.member[x.ArrayIndex(T(setElt))] & x.BitMask(T(setElt))) { elt = T(setElt); if (needComma == 1) ostr << ", " << elt; else { ostr << elt; needComma = 1; } } } ostr << "} "; return ostr; }
#endif // SET_CLASS
打印素数
#include <iostream.h>
#include <iomanip.h>
#pragma hdrstop
#include "set.h" // use the Set class
void PrintPrimes(int n){ Set<int> S(n+1);
int m, k, count;for(m=2; m <= n; m++) S.Insert(m);for( m=2;m*m <= n; m++)
if( S.IsMember(m)) for( k=m+m; k<= n; k += m)
if (S.IsMember(k)) S.Delete(k);count = 1;for(m=2;m <= n;m++)
if (S.IsMember(m)){ cout << setw(3) << m << " "; if (count++ % 10 == 0) cout << endl;}
cout << endl;}
void main(void){
int n;
cout << "Enter n: ";cin >> n;cout << endl;
PrintPrimes(n);}
二、等价类和并查集一个等价关系把一个集合划分成互不相交的等价类 设 S={0,1,2,3,4,5,6,7,8,9,10,11}0≡4 , 3≡1 , 6≡10 , 8≡9 , 7≡4 , 6≡8 , 3≡5 , 2≡11 , 11≡0则 S={0,2,4,7,11} {1,3,5} {6,8,9,10}∪ ∪
怎样用一个算法实现
用集合运算
先把 S 的每个元素都做成单点集再把有关系的集合做并 :
每读入一对等价元素 a≡b
查找 a,b 所在的集合,如不同则做并。
用双亲表示法的树结构表示集合
双亲表示法树表示集合树根同时作集合名
A
B C D
E F
0
1
2
3
4
5
6
7
8
9
A -1
B 0
C 0
D 0
E 1
F 1
不交集合的并只要连接两颗树
A
B C D
E F
G
H I J
G
H I J
双亲表示法结点定义#define MAX_TREE_SIZE 100template <class T>class PNode { T data; int Parent; public: PNode(T item, int pr); T GetData( ); int GetParent( ); }}
const int defaultsize=15;template <class T>class UFSet // 并查集的类{ PNode<T> *nodes; int size; int Find(int i);/// 找结点 i 所在集合的根 public: UFset(int sz=defaultsize ); ~UFSet( ){delete[ ] nodes;} void Union(T item1, T item2); int Find(T item);// 找 item 所在集合的根 void WeightedUnion(T item1, T item2); int CollapsingFind(T item);};
template <class T>int UFSet<T>::Find( int i){if(i<0||i>=size)return -1; for(int j=i; nodes[j].Parent>=0;j= nodes[j].Parent) ; return j;}template <class T> UFSet<T>::UFSet( int sz){ nodes=new PNode<T>[sz]; size=sz; for(int i=0;i<size;i++) nodes[i].Parent=-1;}
template <class T>
int UFSet<T>:: Find(T item)
{ int i=0;
while(nodes[i].Getdata( )!=item)i++;
return Find(i) ;
}
template <class T>
void UFSet<T>:: Union( T item1, T item2)
{ int root1, root2;
if( root1=Find(item1)!=( root2=Find(item2))
nodes[root1].Parent=root2;}
Union 的性能分析
设 S={0,1,2,…,n} , 0≡1≡2≡…≡n-1≡n
作 Union(0,1), Union(1,2), …, Union(n-1,n)
得到 n
n-1
2
1
0
…
每个元查找复杂度 O(n)
总复杂度 O(n2)
改进 Union 为 WeightUnion
改根结点的权值为集合中元素个数的 相反数 -t
两树结合 元素少的树联到元素多的树的根 再将两树根的权相加(两树元素个数相
加)
template <class T>
void UFSet<T>::WeightedUnion(T item1, T item2)
{int root1=Find(item1), root2=Find( item2);
int temp= nodes[root1].Parent+nodes[root2].Parent;
if(nodes[root2].Parent<nodes[root1].Parent)
{nodes[root1].Parent=root2;
nodes[root2].Parent =temp;}
else{nodes[root2].Parent=root1;
nodes[root1].Parent =temp;}
}
WeightUnion 的性能分析设 S={0,1,2,…,n} , 0≡1≡2≡…≡n-1≡n
作 WeightedUnion(0,1), WeightedUnion(1,2), …, WeightedUnion(n-1,n)
变为
每个元查找复杂度 O(log2n)
总复杂度 O(nlog2n)
n
n-1
2
1
0
…
nn-12
1
0 …
压缩路径
template<class T>int UFSet<T>::CollapsingFind(int i){int j=Find(i); while(i!=j) { int temp=nodes[i].Parent; nodes[i].Parent=j; i=temp; } return j;}
压缩路径UFSet<char> u;…………… u.CollapsingFind(H);
A
B C D
E F
G H
A
B C D
E
F
G
H
Recommended