【0】README
0.1)本文總結于 數據結構與算法分析, 但源代碼均為原創,旨在實現 不相交集ADT的兩個操作:合并集合union+查找集合find;
0.2) 不相交集ADT 的 Introduction , 參見 http://blog.csdn.net/PacosonSWJTU/article/details/49716905
【1】靈巧求并算法——按集合大小求并
1.1)大小求并法定義:上面的Union執行是相當任意的, 通過使第二棵樹 成為第一棵樹的子樹而完成合并;對其的改進是借助任意的方法打破現有關系, 使得總讓較小的樹成為較大樹的子樹,我們把這種方法叫做 大小求并法;
1.2)可以看到, 如果Union 操作都是按照大小求并的話,那么任何節點的深度均不會超過 logN;
1.3)首先注意節點的深度為0, 然后它的深度隨著一次 Union 的結果而增加的時候,該節點則被置于至少是 它以前所在樹兩倍大的一棵樹上;因此,它的深度最多可以增加 logN次;
- 1.3.2) Find 操作 的運行時間為 O(logN), 而連續M次操作則花費 O(MlogN);
- 1.3.3) 下圖指出在16次Union操作后可能得到這種最壞的樹;而且如果所有的Union都對相等大小的樹進行, 那么這樣的樹是會得到的;
1.4)為了實現這種方法, 我們需要記住每個樹的大小。由于我們實際上只使用一個數組,因此可以讓每個根的數組元素包含它 的樹的大小的負值;
1.5)已經證明:若使用按大小求并則連續 M次運算需要 O(M)平均時間, 這是因為 當隨機的Union執行時, 整個算法一般只有一些很小的集合(通常是一個元素)與 大 集合 合并;
1.6)souce code + printing
- 1.6.1)download source code :
https://github.com/pacosonTang/dataStructure-algorithmAnalysis/blob/master/chapter8/p203_unionBySize.c - Source Code Statements:
- S1)顯然,本源代碼只對元素的size進行了加,沒有減;因為我想的話, 元素只能合并一次,也即是元素C起初合并到了集合A,就不能再次合并到集合B, 元素C就一直屬于集合A的子集了;
- S2)當然,這個代碼只是 大致上實現了按大小求并的思想,如果元素C還可以再次合并到其他集合的話,這就涉及到集合根元素的size的加減問題了;需要的話,添加之即可;
- 1.6.2)souce code at a glance
#include <stdio.h>
#include <malloc.h>#define ElementType int
#define Error(str) printf("\n error: %s \n",str) struct UnionSet;
typedef struct UnionSet* UnionSet;
struct UnionSet
{
int parent;
int size;ElementType value;
};UnionSet makeEmpty();
UnionSet* initUnionSet(
int size, ElementType* data);
void printSet(UnionSet*
set,
int size);
void printArray(ElementType data[],
int size);
int find(ElementType index, UnionSet*
set);
UnionSet* initUnionSet(
int size, ElementType* data)
{UnionSet*
set;
int i;
set = (UnionSet*)
malloc(size *
sizeof(UnionSet));
if(!
set){Error(
"out of space, from func initUnionSet");
return NULL;}
for(i=
0; i<size; i++){
set[i] = makeEmpty();
if(!
set[i])
return NULL;
set[i]->value = data[i];}
return set;
}
UnionSet makeEmpty()
{UnionSet temp;temp = (UnionSet)
malloc(
sizeof(
struct UnionSet));
if(!temp){Error(
"out of space, from func makeEmpty!");
return NULL;}temp->parent = -
1;temp->size =
1;
return temp;
}
void setUnion(UnionSet*
set,
int index1,
int index2)
{
if(index1 != -
1)index1 = find(index1,
set);
if(index2 != -
1)index2 = find(index2,
set);
if(
set[index1]->size >
set[index2]->size){
set[index2]->parent = index1;
set[index1]->size +=
set[index2]->size;}
else{
set[index1]->parent = index2;
set[index2]->size +=
set[index1]->size;}
}
int find(ElementType index, UnionSet*
set)
{UnionSet temp;
while(
1){temp =
set[index];
if(temp->parent == -
1)
break;index = temp->parent;}
return index;
}
int main()
{
int size;UnionSet* unionSet;ElementType data[] = {
110,
245,
895,
658,
321,
852,
147,
458,
469,
159,
347,
28};size =
12;
printf(
"\n\t====== test for union set by size ======\n");
printf(
"\n\t=== the init union set are as follows ===\n");unionSet = initUnionSet(size, data); printSet(unionSet, size);
printf(
"\n\t=== after union(1,5) + union(2,5) + union(3,4) + union(4,5) ===\n");setUnion(unionSet,
1,
5);setUnion(unionSet,
2,
5);setUnion(unionSet,
3,
4);setUnion(unionSet,
4,
5);printSet(unionSet, size);
printf(
"\n\t=== after union(9,8) + union(7,6) + union(3,6) ===\n");setUnion(unionSet,
9,
8);setUnion(unionSet,
7,
6);setUnion(unionSet,
3,
6); printSet(unionSet, size);
return 0;
}
void printArray(ElementType data[],
int size)
{
int i;
for(i =
0; i < size; i++)
printf(
"\n\t data[%d] = %d", i, data[i]);
printf(
"\n\n");
}
void printSet(UnionSet*
set,
int size)
{
int i;UnionSet temp;
for(i =
0; i < size; i++){ temp =
set[i];
printf(
"\n\t parent[%d] = %d", i, temp->parent); }
printf(
"\n");
}
【2】靈巧求并算法——按集合高度求并
2.1)按高度求并定義: 另外一種方法是按照高度求并(按照高度求并是按大小求并的簡單修改)(推薦);
2.2)它同樣保證所有的樹的深入最多是 O(logN)。我們使得 淺的樹 成為深 的樹的子樹,這是一種平緩算法, 因為只有當兩顆相等深度的樹求并時樹的高度才會增加(此時樹的高度增加1)。
2.3)source code + printing result
#include <stdio.h>
#include <malloc.h>#define ElementType int
#define Error(str) printf("\n error: %s \n",str) struct UnionSet;
typedef struct UnionSet* UnionSet;
struct UnionSet
{
int parent;
int height;ElementType value;
};UnionSet makeEmpty();
UnionSet* initUnionSet(
int depth, ElementType* data);
void printSet(UnionSet*
set,
int depth);
void printArray(ElementType data[],
int depth);
int find(ElementType index, UnionSet*
set);
UnionSet* initUnionSet(
int size, ElementType* data)
{UnionSet*
set;
int i;
set = (UnionSet*)
malloc(size *
sizeof(UnionSet));
if(!
set){Error(
"out of space, from func initUnionSet");
return NULL;}
for(i=
0; i<size; i++){
set[i] = makeEmpty();
if(!
set[i])
return NULL;
set[i]->value = data[i];}
return set;
}
UnionSet makeEmpty()
{UnionSet temp;temp = (UnionSet)
malloc(
sizeof(
struct UnionSet));
if(!temp){Error(
"out of space, from func makeEmpty!");
return NULL;}temp->parent = -
1;temp->height =
0;
return temp;
}
void setUnion(UnionSet*
set,
int index1,
int index2)
{
if(index1 != -
1)index1 = find(index1,
set);
if(index2 != -
1)index2 = find(index2,
set);
if(
set[index1]->height >
set[index2]->height)
set[index2]->parent = index1;
else if(
set[index1]->height <
set[index2]->height)
set[index1]->parent = index2;
else{
set[index1]->parent = index2;
set[index2]->height++; }
}
int find(ElementType index, UnionSet*
set)
{UnionSet temp;
while(
1){temp =
set[index];
if(temp->parent == -
1)
break;index = temp->parent;}
return index;
}
int main()
{
int size;UnionSet* unionSet;ElementType data[] = {
110,
245,
895,
658,
321,
852,
147,
458,
469,
159,
347,
28};size =
12;
printf(
"\n\t====== test for union set by depth ======\n");
printf(
"\n\t=== the init union set are as follows ===\n");unionSet = initUnionSet(size, data); printSet(unionSet, size);
printf(
"\n\t=== after union(0, 1) + union(2, 3) + union(4, 5) + union(6, 7) + union(8, 9) + union(10 ,11) ===\n");setUnion(unionSet,
0,
1);setUnion(unionSet,
2,
3);setUnion(unionSet,
4,
5);setUnion(unionSet,
6,
7);setUnion(unionSet,
8,
9); setUnion(unionSet,
10,
11); printSet(unionSet, size);
printf(
"\n\t=== after union(1, 3) + union(5, 7) + union(9, 11) ===\n");setUnion(unionSet,
1,
3);setUnion(unionSet,
5,
7);setUnion(unionSet,
9,
11);printSet(unionSet, size);
printf(
"\n\t=== after union(3, 7) + union(7, 11) ===\n");setUnion(unionSet,
3,
7);setUnion(unionSet,
7,
11); printSet(unionSet, size);
return 0;
}
void printArray(ElementType data[],
int size)
{
int i;
for(i =
0; i < size; i++)
printf(
"\n\t data[%d] = %d", i, data[i]);
printf(
"\n\n");
}
void printSet(UnionSet*
set,
int size)
{
int i;UnionSet temp;
for(i =
0; i < size; i++){ temp =
set[i];
printf(
"\n\t parent[%d] = %d", i, temp->parent); }
printf(
"\n");
}
總結
以上是生活随笔為你收集整理的不相交集的求并算法(按集合大小求并+按高度求并)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。