본문 바로가기
Computer Science/자료구조

[자료구조] ep4+) 집합 ADT 활용문제들

by 클레어몬트 2024. 5. 3.

문제1) 두 개의 집합 A와 B를 입력받아, A가 B의 부분집합인지를 검사하는 프로그램을 작성하라

1) 집합은 오름차순 양의 정수로 저장 및 출력되어야 한다.

2) 공집합은 공집합을 포함한 모든 집합의 부분집합이다.

​3) 입력: 프로그램은 두 개의 집합 A, B를 차례로 표준입력받는다. 한 개의 집합을 나타내는 두 개의 입력 라인은 다음과 같이 구성된다. 첫 번째 라인: 정수 n (집합 크기, 즉 집합 원소의 개수) 두 번째 라인: 집합의 원소들 (오름차순 양의 정수 수열). 공집합은 첫 번째 라인은 0, 두 번째 라인은 존재하지 않는다.

4) 출력: A ⊂ B이면 0을 출력하고, 그렇지 않으면 B에 속하지 않은 A의 가장 작은 원소를 표준 출력한다.

5) 모든 집합은 헤더 노드가 없는 단일연결리스트(singly-inked list) 형태로 구축되어야 한다.

 

다음 함수를 작성하여 사용하시오.

subset(A, B): 집합 A가 집합 B의 부분집합인지 여부 검사

- 인자: 양의 정수 집합 A, B (A, B는 각각 단일연결리스트의 헤드 노드)

- 반환값: 정수 (A ⊂ B면 0, 그렇지 않으면 B에 속하지 않은 A의 가장 작은 원소)

 

test case

 

 

 

 

 

 

 

(전체코드)

// 모든 집합은 헤더 노드가 없는 단일연결리스트로 구축해야 한다
#include <stdio.h>
#include <stdlib.h>
#pragma warning (disable : 4996)

typedef struct NODE {
    int val;
    struct NODE* next;
} NODE;

int subset(NODE* A, NODE* B);

int main() {
    int n;
    NODE* headA = (NODE*)malloc(1 * sizeof(NODE));
    headA->next = NULL;
    NODE* headB = (NODE*)malloc(1 * sizeof(NODE));
    headB->next = NULL;
    NODE* cur;
    int res;

    scanf("%d", &n);
    if (n != 0) { // 집합 A가 공집합이 아닌 경우
        cur = headA;
        for (int i = 0; i < n; i++) {
            NODE* newNode = (NODE*)malloc(1 * sizeof(NODE));
            newNode->next = NULL;

            scanf("%d", &newNode->val);
            cur->next = newNode;
            cur = newNode;
        }
    }
    scanf("%d", &n);
    if (n != 0) { // 집합 B가 공집합이 아닌 경우
        cur = headB;
        for (int i = 0; i < n; i++) {
            NODE* newNode = (NODE*)malloc(sizeof(NODE));
            newNode->next = NULL;

            scanf("%d", &newNode->val);
            cur->next = newNode;
            cur = newNode;
        }
    }

    res = subset(headA, headB);
    printf("%d\n", res);

    while (headA != NULL) {
        NODE* temp = headA;
        headA = headA->next;
        free(temp);
    }
    while (headB != NULL) {
        NODE* temp = headB;
        headB = headB->next;
        free(temp);
    }
    return 0;
}

int subset(NODE* A, NODE* B) {
    NODE* headA = A;
    NODE* headB = B;

    // A를 기준으로 A보다 큰 B원소가 나올 때 까지 돌린다, 나오면 headA = headA->next
    while (headA != NULL) {
        if (headB == NULL || headA->val < headB->val) { // 조건식은 A의 현재 요소가 B에 존재하지 않음을 의미
            return headA->val; // B에 속하지 않은 A의 가장 작은 원소
        }
        else if (headA->val > headB->val) {
            headB = headB->next;
        }
        else if (headA->val == headB->val) {
            headA = headA->next;
            headB = headB->next;
        }
    }
    return 0; // A는 B의 부분집합
}

 

 

 

 

 

 

문제2) 두 개의 집합을 입력받아, 합집합과 교집합을 구하는 프로그램을 작성하라

1) 모든 집합은 오름차순 양의 정수로 저장 및 출력되어야 한다.

2) 공집합 처리에 주의

3) 입력: 프로그램은 두 개의 집합 A, B를 차례로 표준입력받는다. 한 개의 집합을 나타내는 두 개의 입력 라인은 다음과 같이 구성된다. 첫 번째 라인: 정수 n (집합 크기, 즉 집합 원소의 개수) 두 번째 라인: 집합의 원소들 (오름차순 양의 정수 수열). 따라서 공집합은 첫 번째 라인은 0, 두 번째 라인은 존재하지 않는다.

4) 출력: 각 연산 결과는 두 개의 라인으로 표준출력한다. 첫 번째 라인은 합집합을, 두 번째 라인은 교집합을 나타낸다. 이때 공집합은 0으로 출력한다.

5) 모든 집합은 헤더(header) 노드가 추가된 단일연결리스트 형태로 구축되어야 한다.

 

다음 함수를 작성하여 사용하시오.

union(A, B): 합집합 연산

- 인자: 양의 정수 집합 A, B (A, B는 각각 헤더 단일연결리스트의 헤더 노드)

- 반환값: A∪B의 헤더 노드 주소 또는, 공집합인 경우 빈 리스트(즉, 헤더 노드만 존재)

intersect(A, B): 교집합 연산

- 인자: 양의 정수 집합 A, B (A, B는 각각 헤더 단일연결리스트의 헤더 노드)

- 반환값: A∩B의 헤더 노드 주소 또는, 공집합인 경우 빈 리스트(즉, 헤더 노드만 존재)

 

test case

 

 

 

 

 

 

(전체코드)

// 모든 집합은 헤더 노드가 추가된 단일연결리스트로 구축해야 한다
#include <stdio.h>
#include <stdlib.h>
#pragma warning (disable : 4996)

typedef struct NODE {
    int val;
    struct NODE* next;
} NODE;

NODE* insert(NODE* head, int val);
void printList(NODE* head);
NODE* ft_union(NODE* A, NODE* B);
NODE* intersect(NODE* A, NODE* B);

int main() {
    int n;
    NODE* A = NULL;
    NODE* B = NULL;
    int val;

    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &val);
        A = insert(A, val);
    }

    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &val);
        B = insert(B, val);
    }

    NODE* unionResult = ft_union(A, B);
    NODE* intersectResult = intersect(A, B);

    if (unionResult == NULL) {
        printf(" 0\n");
    }
    else {
        printList(unionResult);
    }
    if (intersectResult == NULL) {
        printf(" 0\n");
    }
    else {
        printList(intersectResult);
    }

    while (A != NULL) {
        NODE* temp = A;
        A = A->next;
        free(temp);
    }
    while (B != NULL) {
        NODE* temp = B;
        B = B->next;
        free(temp);
    }
    while (unionResult != NULL) {
        NODE* temp = unionResult;
        unionResult = unionResult->next;
        free(temp);
    }
    while (intersectResult != NULL) {
        NODE* temp = intersectResult;
        intersectResult = intersectResult->next;
        free(temp);
    }
    return 0;
}

NODE* insert(NODE* head, int val) {
    NODE* newNode = (NODE*)malloc(1 * sizeof(NODE));
    newNode->val = val;
    newNode->next = NULL;

    if (head == NULL) {
        head = newNode;
    }
    else {
        NODE* cur = head;
        while (cur->next != NULL) {
            cur = cur->next;
        }
        cur->next = newNode;
    }

    return head;
}

void printList(NODE* head) {
    while (head != NULL) {
        printf(" %d", head->val);
        head = head->next;
    }
    printf("\n");
}

NODE* ft_union(NODE* A, NODE* B) {
    NODE* res = NULL;
    NODE* cur;

    cur = res;
    while (A != NULL || B != NULL) {
        if (A == NULL) { // A가 공집합인 case
            cur = insert(cur, B->val);
            B = B->next;
        }
        else if (B == NULL) { // B가 공집합인 case
            cur = insert(cur, A->val);
            A = A->next;
        }
        else if (!(A == NULL && B == NULL)) { // 평상시 case
            if (A->val < B->val) {
                cur = insert(cur, A->val);
                A = A->next;
            }
            else if (A->val > B->val) {
                cur = insert(cur, B->val);
                B = B->next;
            }
            else if (A->val == B->val) {
                cur = insert(cur, A->val);
                A = A->next;
                B = B->next;
            }
        }

        if (res == NULL) { // 새로운 노드가 삽입되어 처음으로 res가 생성될 때! 이 경우에는 res가 NULL이므로 cur값을 대입해 줘서 첫 번째 헤드를 가리키게 한다
            res = cur;
        }
        else { // 평상시
            cur = cur->next;
        }
    }

    return res;
}

NODE* intersect(NODE* A, NODE* B) {
    NODE* res = NULL;
    NODE* cur;

    cur = res;
    while (A != NULL && B != NULL) {
        if (A->val < B->val) {
            A = A->next;
        }
        else if (A->val > B->val) {
            B = B->next;
        }
        else if (A->val == B->val) {
            cur = insert(cur, A->val);
            A = A->next;
            B = B->next;

            if (res == NULL) { // res가 여전히 NULL이면 발견된 첫 번째 공통 요소라는 의미이므로, res를 cur에 할당하여 res가 첫 번째 공통 노드를 가리키도록 한다
                res = cur;
            }
            else {
                cur = cur->next;
            }
        }
    }

    return res;
}

/*
입력 예시1)
6
3 7 45 88 99 101
4
7 10 15 45
출력 예시1)
 3 7 10 15 45 88 99 101
 7 45

입력 예시2)
0
3
9 20 77
출력 예시2)
 9 20 77
 0

입력 예시3)
0
0
출력 예시3)
 0
 0
*/

 

 

 

 

 

 

 

참고 및 출처: 데이터 구조 원리와 응용(국형준)