前言:手機太爛不好意思在地鐵上拿出來玩,於是看了會演算法與資料結構,想看看以前在學校沒好好學的一些東西,於是乎今天看了集合這一塊,以前沒好好學,工作後也沒用到,最近有個想法想做個東西出來,貌似要用到集合。不多說,講正題。(歡迎轉載,轉載請註明出處。謝謝。) 一、基本概念 這裡集合的概念與我們數學中所學的集合一樣,主要運算也是並、交、差、子、相等。數學中怎麼理解後面相關概念就怎麼理解,不懂得回去讀高中。二、集合的抽象資料類型ADT Set isoperations Set createEmptySet();//建立一個空集合 int member(set A,DataType x);//當x屬於A時返回真值,否則返回假值 int insert(Set A,DataType x);//使x成為A的一個成員,如果x本來就是A的成員,則A不變 int delete(Set A,DataType x);//將x從A中刪除,如果x本來就不在A中,則A不變 int union(Set A,Set B,Set C);//求集合A和B的並集,結果放在集合C中 int intersection(Set A,Set B,Set C);//求集合A與B的交集,結果放在C中 int difference(Set A,Set B,Set C);//求集合A與B的差集,結果放在C中 int subset(Set A,Set B);//若且唯若A是B的子集時,函數才為真end ADT Set三、集合的位向量表示 位向量即用一個二進位位來表示一個元素存不存在某個集合中,當所表示的集合存在某個不太大的公用超集時,採用位向量的方式來表示這種集合往往很有效。 一個二進位位只有兩種狀態,是0或者是1,他能夠表示的資訊非常簡單。例如能夠表示一扇門開或者關,一個條線路的通路或者斷路。同樣,也可以用一個位來表示某個東西存在或不存在。在位向量裡每個二進位位都有一個固定的位置,不同的位置的二進位位可以用來表示不同的東西。 假設需要表示的集合的公用超集中,共有n個不同的元素(n是一個不大的正整數),為敘述方便,可以將這n個元素與整數0,1,2,···,n-1建立一一對應的關係。每個集合可以用有n位的位向量來表示。若整數i是這個集合的一個元素,則位向量中的下標為i的位為1(真),否則為0(假)。這種表示使得元素的整數值就不需要存放了,大大節省了空間。 在C語言中無法直接定義位元組。於是我們採用長度為n/8的字元數組表示長度為n的字元數組。一個字元佔8位二進位編碼。 假設n是位向量的位元,因為n不一定是8的整數倍,所以用(n+7)/8的值來決定能容下所有位向量的最少位元組數。位向量表示的儲存結構typedef struct{ int size; /*字元數組長度*/ char* array; /*位向量空間,每一數組元素儲存8位*/ }BitSet; 還有一個細節需要考慮:在一個字元空間中,位向量的下標應該如何排列?一種自然的想法是,字元的8位從左自右下標遞增排列。但這種排列給集合類型許多操作帶來不便,所以選擇了相反的排列。 圖1(a)給出了一個公用超集是從0到9的整數集合,採用位向量表示的儲存結構從途中可以看出每個整數所對應的二進位的位置。當集合S={1,3,5,7,9}時,它的實際儲存狀態1(b)所示。圖1(a)
圖1(b)
用位向量表示集合時,所佔空間大小與公用超集的大小n成正比,而與要表示的集合大小無關。演算法的實現演算法1. 建立空集合BitSet* createEmptySet(int n){ /*建立n位的位向量 000...0*/ int i; BitSet* s=(BitSet*)malloc(sizeof(Bitset)); if(s!=NULL){ s->size = (n+7)/8; s->array = (char*)malloc(s-<size * sizeof(char)); if(s->array != NULL){ for(i=0;i<s->size;i++)s->array[i] = '\0'; return s; } } return NULL;} 演算法2. 將整數index的元素插入集合int insert(BitSet* s,int index){ if(index >=0 && index>>3 < s->size) {s->array[index>>3] |= (1<< (index & 7) );return 1} return 0;} 演算法3. 將整數index的元素從集合中刪除int delete(BitSet* s,int index){ if(index>=0 && index>>3 <s->size) {s->array[index >> 3] & =~(1 << (index & 7));return 1} return 0;} 演算法4. 判斷整數index的元素是否屬於集合int member(BitSet* s,int index){ if( index>=0 && index>>3 <s->size && (s->array[index>>3] & (1<<(index&7) ) )) return 1; return 0;} 演算法5. 集合與集合的並int union(BitSet* s0,BitSet* s1,BitSet* s2){ int i; if(s0->size != s1->size || s2->size != s1->size)return 0; for(i =0 ;i<s1->size;i++) s2->array[i] = s0->array[i] | s1->array[i]; return 1;} 演算法6. 集合與集合的交int intersection(BitSet* s0, BitSet *s1, BitSet *s2){ int i; if(s0->size != s1->size || s2->size != s1->size)return 0; for(i =0 ;i<s1->size;i++)
s2->array[i] = s0->array[i] & s1->array[i]; return 1;} 演算法7. 集合與集合的差int difference(BitSet* s0, BitSet *s1, BitSet *s2){ int i; if(s0->size != s1->size || s2->size != s1->size)return 0; for(i =0 ;i<s1->size;i++)
s2->array[i] = s0->array[i] & ~s1->array[i]; return 1;} 四、集合的單鏈表表示 用單鏈表來表示集合時我們每個節點存放元素實際的值,而不是是否屬於集合的標記。 儲存結構struct Node;typedef struct Node* PNode;struct Node{ DataType info; PNode link;};typedef struct Node* LinkSet; 因為我們討論的是有序集,如果將所有元素按"<"關係排序構造有序鏈表,會給某些運算帶來方便。演算法8. 求單鏈表表示集合的交集int intersectionLink(LinkSet s0,LinkSet s1,LinkSet s2){ PNode x; if(s0 == NULL || s1 == NULL || s2 ==NULL){printf("no head node error");return 0;} s2->link =NULL; s0=s0->link;s1=s1->link; while(s0!NULL && s1 !=NULL) if(s0->info < s1->info)s1 = s1->link; else if(s0->info == s1->info)s0 = s0->link; else if(s0->info == s1->info) { x = (PNode)malloc(sizeof(struct Node)); if(x==NULL){printf("Out of space!");return 0;} x->info = s0->info;x->link = NULL; s2=s2->link; } return 1;} 演算法9. 集合的賦值int assignLink(LinkSet s0,LinkSet s1){ PNode x; if(s0 == NULL || s1 == NULL ){printf("no head node error");return 0;} s0->link =NULL; s1=s1->link; while(s1!=NULL){ x = (PNode)malloc(sizeof(struct Node));
if(x==NULL){printf("Out of space!");return 0;} x->info = s1->info;x->link = NULL; s0->link=x; s1=s1->link; s0=s0->link; } return 1;} 演算法10. 有序鏈表表示的集合中的插入操作int insetLink(LinkSet s0, DataType x){ PNode temp; if(s0 == NULL ){printf("no head node error");return 0;} temp = (PNode)malloc(sizeof(struct Node)); if(temp == NULL)){printf("Out of space!");return 0;} while(s0->link!=NULL){
if(s0->link->info == x){printf("data already exist !");return 1;} else if(s0->link->info < x)s0 = s0->link; else if(s0->link->info > x){ temp->info =x; temp->link = s0->link; s0->link =temp;return 1; } if(s0->link==NULL){ temp->info =x; temp->link = s0->link;
s0->link =temp;return 1; } }} //THE END好晚了,睡覺覺了。