추천글

2025 타임지 세계 영향력 100인에 포함된 한국인

  이재명 (지도자 부문) 로제 (Rosé) (개척자 부문) 1. 이재명 (지도자 부문) 배경 : 이재명은 대한민국의 야당 지도자이자 더불어민주당 전 대표로, 차기 대통령 선거의 유력 후보로 평가받고 있습니다. 농부 가정에서 태어나 어려운 어린 시절을 보냈으며, 공장에서 일하다 손목 부상을 당한 경험을 가지고 있습니다. 그는 성남시장과 경기도지사를 역임했으며, 2022년 대통령 선거에서 윤석열에게 근소한 차이로 패배했습니다. 최근 활동 : 2024년 1월 목에 칼에 찔리는 공격을 견뎌냈고, 같은 해 12월 윤석열 대통령의 계엄령 선언 이후 탄핵을 주도했습니다. 특히, 경찰 봉쇄를 뚫고 국회 울타리를 넘는 장면이 생중계되며 큰 주목을 받았습니다. 영향력 : 타임지는 이재명의 정치적 저항력과 리더십을 높이 평가하며, 그가 대통령에 당선될 경우 북한의 위협과 글로벌 무역 전쟁 등 복잡한 과제에 직면할 것이라고 언급했습니다. 인용구 : “세상을 배우는 방법은 많지만, 직접 살아보고 경험하는 것은 다르다” (2022년 타임 인터뷰). 작성자 : Charlie Campbell (타임 편집장 대행). 2. 로제 (Rosé, 개척자 부문) 배경 : 로제(본명: Roseanne Park)는 세계적인 K-팝 걸그룹 블랙핑크의 멤버로, 뉴질랜드에서 태어나 호주에서 자란 한국계 아티스트입니다. 블랙핑크는 전 세계적으로 가장 성공한 걸그룹 중 하나로, 로제는 팀 활동뿐 아니라 솔로 아티스트로서도 두각을 나타내고 있습니다. 최근 활동 : 2024년 10월, 브루노 마스(Bruno Mars)와의 협업 곡 “APT.”를 발표하며 글로벌 차트에서 큰 성공을 거두었습니다. 이 곡은 빌보드 글로벌 200 1위, 미국 빌보드 핫 100 8위(최고 순위 3위), 한국 써클 디지털 차트 1위를 기록하며 전 세계적으로 화제가 되었습니다. 유튜브 뮤직비디오는 1월에 10억 뷰를 돌파하며 역대 가장 빠른 기록 중 하나를 세웠습니다. 2024년 12월, 첫 솔로 정규...

기술면접 - 이진 검색 트리 유효성 검사 (Validate Binary Search Tree)

 

중위 순회(Inorder Traversal)와 범위 검사(Range Check)를 활용한 C 언어 구현


이진 검색 트리(BST)란?

이진 검색 트리(BST)는 각 노드의 왼쪽 서브트리 값이 현재 노드보다 작고, 오른쪽 서브트리 값이 현재 노드보다 큰 규칙을 따르는 트리입니다. BST는 다음과 같은 성질을 만족합니다:

  • 왼쪽 서브트리: 현재 노드보다 작은 값만 포함.
  • 오른쪽 서브트리: 현재 노드보다 큰 값만 포함.
  • 재귀적 성질: 모든 서브트리도 BST여야 함.

이 규칙을 위반하면 유효한 BST가 아니므로, 이를 확인하는 알고리즘이 필요합니다. 이번 포스트에서는 중위 순회와 범위 검사 두 가지 방법을 C 언어로 구현해 봅니다.

1. 중위 순회(Inorder Traversal) 방법

개념

BST의 중위 순회는 노드를 오름차순으로 방문합니다. 즉, 중위 순회 중 이전 노드의 값보다 현재 노드의 값이 작거나 같으면 BST 규칙을 위반한 것입니다.

장점

  • 구현이 간단하고 직관적.
  • 추가 메모리 사용이 최소화됨.

단점

  • 재귀 호출로 인해 트리의 높이에 비례하는 스택 공간 필요.

C 언어 구현

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

// 트리 노드 구조체 정의
typedef struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
} TreeNode;

// 이전 노드 값을 저장하는 전역 변수
int prev = INT_MIN;

// 중위 순회로 BST 유효성 검사
int isValidBST_inorder(TreeNode* root) {
    if (root == NULL) {
        return 1; // 빈 트리는 유효
    }

    // 왼쪽 서브트리 검사
    if (!isValidBST_inorder(root->left)) {
        return 0;
    }

    // 현재 노드 값이 이전 값보다 작거나 같으면 BST 아님
    if (root->val <= prev) {
        return 0;
    }
    prev = root->val; // 이전 값 업데이트

    // 오른쪽 서브트리 검사
    return isValidBST_inorder(root->right);
}

// 테스트용 메인 함수
int main() {
    // 트리 예시: 유효한 BST
    //     2
    //    / \
    //   1   3
    TreeNode* root = (TreeNode*)malloc(sizeof(TreeNode));
    root->val = 2;
    root->left = (TreeNode*)malloc(sizeof(TreeNode));
    root->right = (TreeNode*)malloc(sizeof(TreeNode));
    root->left->val = 1;
    root->right->val = 3;
    root->left->left = NULL;
    root->left->right = NULL;
    root->right->left = NULL;
    root->right->right = NULL;

    prev = INT_MIN; // prev 초기화
    if (isValidBST_inorder(root)) {
        printf("유효한 BST입니다.\n");
    } else {
        printf("유효하지 않은 BST입니다.\n");
    }

    // 메모리 해제 (생략)
    return 0;
}

코드 설명

  • TreeNode 구조체: 트리 노드를 정의하며, 값(val)과 왼쪽/오른쪽 자식 포인터를 가짐.
  • prev 변수: 중위 순회 중 이전 노드 값을 저장. 초기값은 INT_MIN.
  • isValidBST_inorder 함수:
    • 빈 트리면 1 반환.
    • 왼쪽 서브트리 재귀 호출.
    • 현재 노드 값이 prev보다 작거나 같으면 0 반환.
    • prev를 현재 값으로 업데이트 후 오른쪽 서브트리 검사.
  • 메인 함수: 간단한 BST를 만들어 테스트.

2. 범위 검사(Range Check) 방법

개념

각 노드에 허용되는 값의 범위(minmax)를 설정하고, 노드 값이 이 범위 내에 있는지 확인합니다. 루트는 전체 범위를 가지며, 자식 노드로 갈수록 범위가 좁아집니다.

장점

  • 한 번의 방문으로 검사 가능.
  • BST 성질을 명확히 반영.

단점

  • 범위 관리가 약간 복잡.

C 언어 구현

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

// 트리 노드 구조체 정의
typedef struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
} TreeNode;

// 범위 검사로 BST 유효성 확인
int isValidBST_range(TreeNode* root, long min, long max) {
    if (root == NULL) {
        return 1; // 빈 트리는 유효
    }

    // 현재 노드 값이 범위를 벗어나면 BST 아님
    if (root->val <= min || root->val >= max) {
        return 0;
    }

    // 왼쪽 서브트리: 최대값은 현재 노드 값
    if (!isValidBST_range(root->left, min, root->val)) {
        return 0;
    }

    // 오른쪽 서브트리: 최소값은 현재 노드 값
    if (!isValidBST_range(root->right, root->val, max)) {
        return 0;
    }

    return 1;
}

// 초기 호출용 함수
int isValidBST(TreeNode* root) {
    return isValidBST_range(root, LONG_MIN, LONG_MAX);
}

// 테스트용 메인 함수
int main() {
    // 트리 예시: 유효하지 않은 BST
    //     5
    //    / \
    //   1   4
    //      / \
    //     3   6
    TreeNode* root = (TreeNode*)malloc(sizeof(TreeNode));
    root->val = 5;
    root->left = (TreeNode*)malloc(sizeof(TreeNode));
    root->right = (TreeNode*)malloc(sizeof(TreeNode));
    root->left->val = 1;
    root->right->val = 4;
    root->left->left = NULL;
    root->left->right = NULL;
    root->right->left = (TreeNode*)malloc(sizeof(TreeNode));
    root->right->right = (TreeNode*)malloc(sizeof(TreeNode));
    root->right->left->val = 3;
    root->right->right->val = 6;
    root->right->left->left = NULL;
    root->right->left->right = NULL;
    root->right->right->left = NULL;
    root->right->right->right = NULL;

    if (isValidBST(root)) {
        printf("유효한 BST입니다.\n");
    } else {
        printf("유효하지 않은 BST입니다.\n");
    }

    // 메모리 해제 (생략)
    return 0;
}

코드 설명

  • isValidBST_range 함수:
    • 빈 트리면 1 반환.
    • 노드 값이 min과 max 범위를 벗어나면 0 반환.
    • 왼쪽 서브트리는 max를 현재 값으로, 오른쪽 서브트리는 min을 현재 값으로 설정해 재귀 호출.
  • isValidBST 함수: 초기 범위를 LONG_MIN과 LONG_MAX로 설정.
  • 메인 함수: 유효하지 않은 BST(4가 5의 오른쪽에 있지만 3은 5보다 작음)를 테스트.

두 방법 비교

기준중위 순회범위 검사
복잡도O(n)O(n)
추가 공간O(h) (h는 트리 높이)O(h) (재귀 스택)
구현 난이도쉬움약간 복잡
직관성BST 성질 활용범위로 명확히 확인

결론

중위 순회와 범위 검사 모두 BST 유효성을 확인하는 데 효과적입니다. 중위 순회는 간단하고 BST의 오름차순 성질을 잘 활용하며, 범위 검사는 각 노드의 값이 규칙을 따르는지 명확히 확인합니다. 상황에 따라 적합한 방법을 선택하면 됩니다.

위 코드는 테스트 예시를 포함해 실제로 동작하는 형태로 제공되었으니, 여러분의 프로젝트나 학습에 활용해 보세요! 구글 블로그에 이 내용을 업로드하여 많은 사람들과 공유할 수 있습니다.

댓글