49
集集 集集 集集集集集集集 集集集集集集集

集合 等价类与并查集

  • Upload
    aria

  • View
    107

  • Download
    4

Embed Size (px)

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

Page 1: 集合 等价类与并查集

集合集合 等价类与并查集等价类与并查集

Page 2: 集合 等价类与并查集

一、集合

若干个同一类型互不相同的以一定次序排列的元素

整形集合(整数,字符,枚举,记录)若干离散有序元素组成的集合每个元素可以对应唯一一个整数 int(a) ; //a 对应的整数

A={a,b,c}, B={b,d}

Page 3: 集合 等价类与并查集

集合的运算 a A∈ A B={a,b,c,d} ∪ A∩B={b}

A-B={a,c}

Page 4: 集合 等价类与并查集

集合的实现

用数组实现 用指针实现 用链表实现 用位运算实现整形集合

Page 5: 集合 等价类与并查集

位运算 或 | 与 & 非 ~ 异或 ^ 右移位 >> 左移位 <<

——————————————————

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

Page 6: 集合 等价类与并查集

x=11100011 y=01110110

x|y 11100011

01110110

11110111

x&y 11100011

01110110

01100010

~x = 00011100

x^y 11100011 01110110 10010101

Page 7: 集合 等价类与并查集

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

Page 8: 集合 等价类与并查集

将 n 个元素固定成一列,每个下标代表一个元素每个元素 elt 的下标可以由 int(elt) 或用一个公式

算出

用一个 01 数组存储集合每一位写 0 或 1

0 代表某个元素不在集合中, 1 代表某个元素在集合中,n 个元素最少用多长的数组呢?

用 01 数组存储 n 个整形元素的集合

Page 9: 集合 等价类与并查集

一个 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];

Page 10: 集合 等价类与并查集

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);

Page 11: 集合 等价类与并查集

两集合 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 号

Page 12: 集合 等价类与并查集

#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};

Page 13: 集合 等价类与并查集

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);

Page 14: 集合 等价类与并查集

~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);

};

Page 15: 集合 等价类与并查集

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;

Page 16: 集合 等价类与并查集

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);}

Page 17: 集合 等价类与并查集

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);}

Page 18: 集合 等价类与并查集

// 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;

}

Page 19: 集合 等价类与并查集

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];}

Page 20: 集合 等价类与并查集

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;}

Page 21: 集合 等价类与并查集

// 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);

}

Page 22: 集合 等价类与并查集

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;

}

Page 23: 集合 等价类与并查集

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;}

Page 24: 集合 等价类与并查集

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;}

Page 25: 集合 等价类与并查集

// 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);

}

Page 26: 集合 等价类与并查集

// 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);}

Page 27: 集合 等价类与并查集

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);

Page 28: 集合 等价类与并查集

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;

Page 29: 集合 等价类与并查集

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; }

Page 30: 集合 等价类与并查集

if (istr.get(c) == 0) x.Error(EndOfFile); } if (haveComma == 1) x.Error(MissingValue); return istr;}

Page 31: 集合 等价类与并查集

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; }

Page 32: 集合 等价类与并查集

#endif // SET_CLASS

Page 33: 集合 等价类与并查集

打印素数

#include <iostream.h>

#include <iomanip.h>

#pragma hdrstop

#include "set.h" // use the Set class

Page 34: 集合 等价类与并查集

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;}

Page 35: 集合 等价类与并查集

void main(void){

int n;

cout << "Enter n: ";cin >> n;cout << endl;

PrintPrimes(n);}

Page 36: 集合 等价类与并查集

二、等价类和并查集一个等价关系把一个集合划分成互不相交的等价类 设 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}∪ ∪

怎样用一个算法实现

Page 37: 集合 等价类与并查集

用集合运算

先把 S 的每个元素都做成单点集再把有关系的集合做并 :

每读入一对等价元素 a≡b

查找 a,b 所在的集合,如不同则做并。

Page 38: 集合 等价类与并查集

用双亲表示法的树结构表示集合

双亲表示法树表示集合树根同时作集合名

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

Page 39: 集合 等价类与并查集

不交集合的并只要连接两颗树

A

B C D

E F

G

H I J

G

H I J

Page 40: 集合 等价类与并查集

双亲表示法结点定义#define MAX_TREE_SIZE 100template <class T>class PNode { T data; int Parent; public: PNode(T item, int pr); T GetData( ); int GetParent( ); }}

Page 41: 集合 等价类与并查集

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);};

Page 42: 集合 等价类与并查集

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;}

Page 43: 集合 等价类与并查集

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;}

Page 44: 集合 等价类与并查集

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)

Page 45: 集合 等价类与并查集

改进 Union 为 WeightUnion

改根结点的权值为集合中元素个数的 相反数 -t

两树结合 元素少的树联到元素多的树的根 再将两树根的权相加(两树元素个数相

加)

Page 46: 集合 等价类与并查集

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;}

}

Page 47: 集合 等价类与并查集

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 …

Page 48: 集合 等价类与并查集

压缩路径

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;}

Page 49: 集合 等价类与并查集

压缩路径UFSet<char> u;…………… u.CollapsingFind(H);

A

B C D

E F

G H

A

B C D

E

F

G

H