Data Structure/자료구조

[자료구조] 트리 - 분리 집합

lumana 2024. 6. 15. 18:38

분리 집합(Disjoint Set)

  • 집합의 정의 : 특정 조건에 맞는 원소의 모임
  • 분리 집합(Disjoint Set) : 서로 공통된 원소를 갖지 않는, 즉 교집합을 갖지 않는 복수의 집합
    • 분리 집합의 개념은 2개 이상의 집합을 일컬을 때만 사용할 수 있음
  • 분리 집합은 교집합을 허락하지 않기 때문에 소속 관계가 분명해야 하는 데이터를 다룰 때 아주 유용함
    • ex) 도서 판매 관리 프로그램에서 일반 도서 집합과 베스트셀러 집합을 만들고, 베스트셀러들의 BookPrice가 베스트셀러 집합의 원소가 되도록 함
  • 이처럼 분리 집합은 원소 또는 개체가 '어느 집합에 소속되어 있는가?'라는 정보를 바탕으로 무언가를 하는 알고리즘에 응용할 수 있음

분리 집합 표현

 

  • 보통의 트리와 이진 트리는 부모가 자식을 가리키는 포인터를 갖고 있음
  • 분리 집합은 이와 반대로 자식이 부모를 가리킴
  • 뿌리 노드는 집합 그 자체이고, 뿌리 노드 자신을 포함한 트리 내의 모든 노드는 그 집합에 소속됨
    • 연결 리스트에서 헤드 노드가 연결리스트를 나타낸다는 점을 떠올려 이해해보면 도움이 됨
  • 분리 집합 노드의 구조체
    • 자식 노드에 대한 포인터는 존재하지 않음
    • 부모 노드에 대한 포인터만 있음
    • 뿌리 노드는 부모 노드가 없으므로 Parent가 NULL임
    • Data 필드를 void* 형으로 선언한 이유는 어떤 자료형의 데이터든 입력 받을 수 있게 하기 위해서임
typedef struct tagDisjointSet {
    struct tagDisjointSet* Parent;
    void*                  Data;
} DisjointSet;

분리 집합의 기본 연산

  • '합집합'과 '집합 탐색 연산'을 기억하자
    • 분리 집합의 목적은 원소가 어느 집합에 귀속되어 있는지 쉽게 알아내는 데 있음

합집합 연산

  • 합집합(Union) : 두 집합을 더하는 연산
  • 한 집합의 뿌리 노드를 다른 집합의 뿌리노드의 자식으로 만들면 됨
void DS_UnionSet( DisjointSet* Set1, DisjointSet* Set2 ) {
    Set2 = DS_FindSet(Set2);
    Set2->Parent = Set1;
}

집합 탐색 연산

  • 분리 집합의 탐색(Find)은 집합에서 원소를 찾는 것이 아니라 원소가 속한 집합을 찾는 연산임.
  • 집합 내 어떤 노드에게든 트리의 최상위에 있는 뿌리 노드가 곧 자신이 속한 집합을 나타내므로, 원소(노드)가 어떤 집합에 속해 있는지 알려면 이 원소가 속한 트리의 뿌리 노드를 찾으면 됨
  • 각 노드는 '부모' 노드를 가리키는 포인터를 가지고 있기 때문에, 이 포인터를 타고 쭉 올라가면 부모가 NULL인 뿌리 노드를 만날 수 있음
    • 이 뿌리 노드는 곧 집합을 나타내므로, 이것을 반환하면 해당 노드가 소속된 집합을 반환하게 되는 것
DisjointSet* DS_FindSet( DisjointSet* Set ) {
    while ( Set->Parent != NULL )
    {
        Set = Set->Parent;
    }

    return Set;
}

집합 생성/소멸

  • 집합 생성
DisjointSet* DS_MakeSet( void* NewData ) {
    DisjointSet* NewNode = (DisjointSet*)malloc(sizeof(DisjointSet));
    NewNode->Data   = NewData;
    NewNode->Parent = NULL;

    return NewNode;
}
  • 집합 소멸
void DS_DestroySet( DisjointSet* Set ) {
    free( Set );
}

분리 집합 예제 프로그램

int main( void ) {
        int a=1, b=2, c=3, d=4;
        DisjointSet* Set1 = DS_MakeSet(&a);
        DisjointSet* Set2 = DS_MakeSet(&b);
        DisjointSet* Set3 = DS_MakeSet(&c);
        DisjointSet* Set4 = DS_MakeSet(&d);

    printf("Set1 == Set2 : %d \n", DS_FindSet( Set1 ) == DS_FindSet( Set2 ) );

        DS_UnionSet( Set1, Set3 );
    printf("Set1 == Set3 : %d \n", DS_FindSet( Set1 ) == DS_FindSet( Set3 ) );

    DS_UnionSet( Set3, Set4 );
    printf("Set3 == Set4 : %d \n", DS_FindSet( Set3 ) == DS_FindSet( Set4 ) );

        return 0;
}

참조) 박상현, 『이것이 자료구조+알고리즘이다 with C언어』, 한빛미디어(2022)

'Data Structure > 자료구조' 카테고리의 다른 글

[자료구조] 다양한 트리 구조(BST)  (0) 2024.06.18
[자료구조] 비선형 문제  (0) 2024.06.18
[자료구조] 수식 트리  (0) 2024.06.15
[자료구조] 이진 트리  (0) 2024.06.15
[자료구조] 트리 ADT  (0) 2024.06.15