이진 검색 트리 확인

  1. 이진 트리가 이진 검색 트리인지 확인하는 알고리즘
  2. 이진 트리를 확인하는 알고리즘의 구현이 이진 검색 트리입니다
  3. 복잡성 분석
이진 검색 트리 확인

이진 트리는 비선형 데이터 구조입니다. 각 노드에는 최대 두 개의 자식이 있기 때문에 이진 트리라고합니다. 이 아이들을 왼쪽 아이들과 오른쪽 아이들이라고 부릅니다. 이진 트리가 BST가 되려면 다음 속성을 충족해야합니다.

  • 왼쪽 하위 트리의 모든 노드가 루트 노드보다 작습니다.
  • 오른쪽 하위 트리의 모든 노드가 루트 노드보다 큽니다.
  • 왼쪽 및 오른쪽 하위 트리도 이진 검색 트리 여야합니다.

이진 트리가 이진 검색 트리인지 확인하는 알고리즘

알고리즘 1

이 접근 방식에서는 모든 노드를 하위 트리의 루트로 간주하여 왼쪽 하위 트리에 루트 값보다 큰 요소가 포함되어 있는지, 오른쪽 하위 트리에 루트 값보다 작은 요소가 포함되어 있는지 확인합니다. 최대 및 최소 요소를 찾으려면getMin()getMax()라는 두 개의 개별 함수를 사용해야합니다.

getMin()

  • temproot로 초기화합니다.
  • templeft가있는 동안 다음을 수행합니다.
    • temptemp->left로 설정합니다. 즉, 가장 작은 요소를 찾으려면 왼쪽으로 이동합니다.
  • 하위 트리 내의 최소값으로temp->val을 반환합니다.

getMax()

  • temproot로 초기화합니다.
  • tempright가있는 동안 다음을 수행합니다.
    • temptemp->right로 설정합니다. 즉, 가장 큰 요소를 찾으려면 오른쪽으로 이동합니다.
  • temp->val을 하위 트리 내의 최대 값으로 반환합니다.

isBST(root)

  • rootNULL이면true를 반환합니다.
  • getMax(root->left)를 호출하여 왼쪽 하위 트리에서 최대 요소maxm을 찾습니다.
  • getMin(root->right)를 호출하여 오른쪽 하위 트리에서 최소 요소minm을 찾습니다.
  • 루트 요소가maxm보다 작거나minm보다 크면 false를 반환합니다.
  • isBST(root->left)isBST(root->right)를 호출하여 모든 노드를 재귀 적으로 확인합니다. 두 재귀 호출이 모두 true를 반환하면 트리는 BST이고 그렇지 않으면 false를 반환합니다.

위의 알고리즘은 트리가 BST인지 아닌지를 알려주지 만 매우 느린 지 여부를 알려줍니다. 함수getMin()getMax()O(n)의 최악의 시간 복잡도를 가지며n노드에 대해 호출되어 총 시간 복잡도를 O(n2).

알고리즘 2 :

이 알고리즘은 반복 계산을 수행하지 않음으로써 이전 알고리즘을 향상시킵니다. 모든 노드에 대해getMin()getMax()라고하는 이전 접근 방식입니다. 이 접근 방식은 노드를 통과 할 때 허용되는 최소 및 최대 값을 추적함으로써 위의 접근 방식을 개선합니다.

isBST(root)

  • 두 변수minINT_MIN으로,maxINT_MAX로 초기화합니다.
  • isBST(root, min, max)를 호출합니다.

isBST(루트, 최소, 최대)

  • rootNULL이면true를 반환합니다.
  • min>root->data가 BST 속성을 위반하면 false를 반환합니다.
  • max<root->data이면 BST 속성을 위반하면 false를 반환합니다.
  • isBST(root->left, min, root->data-1)를 호출하여 왼쪽 하위 트리를 재귀 적으로 확인합니다 (인수가 유효한 값을 변경함에 따라minroot->data-1전달). 왼쪽 하위 트리의 BST 범위) 및isBST(root->right, root->data + 1, max)를 호출하여 오른쪽 하위 트리를 선택합니다 (인수로root->data + 1max전달). 오른쪽 하위 트리의 BST 범위).
  • 두 재귀 호출이 모두true를 반환하면 트리는 BST이고true를 반환합니다.

이 알고리즘의 시간 복잡도는O(n)이며 이는 이전 방법에 비해 상당히 개선 된 것입니다.

알고리즘 3 :

이 알고리즘은 위의 알고리즘에서INT_MININT_MAXlr두 개의 포인터로 대체하여 사용하지 않도록합니다.

isBST(root)

  • 두 노드lrNULL로 초기화합니다.
  • isBST(root, l, r)를 호출합니다. (오버로드 된 함수 호출)

isBST(루트, l, r)

  • rootNULL이면true를 반환합니다.
  • lNULL이 아니고l->data> =root->data가 아니면 BST 속성이 위반되면 false를 반환합니다.
  • rNULL이 아니고r->data<=root->data가 아니면 BST 속성이 위반되면 false를 반환합니다.
  • isBST(root->left, left, root)(루트를 세 번째 인수로 전달하면 하위 트리의 최소값 제한이 변경됨)를 호출하여 왼쪽 하위 트리를 재귀 적으로 확인하고isBST(root)를 호출하여 오른쪽 하위 트리를 재귀 적으로 확인합니다. ->오른쪽, 루트, 오른쪽)(두 번째 인수로 루트를 전달하면 하위 트리의 최대 값 제한이 변경됨).
  • 두 재귀 호출이 모두true를 반환하면 트리는 BST이고true를 반환합니다.

알고리즘 4 :

이진 검색 트리의 inorder traversal은 정렬 된 순서로 요소를 반환합니다. 이 속성을 사용하여 이진 트리가 BST인지 확인할 수 있습니다. inorder traversal의 모든 요소가 오름차순이 아니면 주어진 트리는 이진 검색 트리가 아닙니다.

isBST(root)

  • 변수prevINT_MIN으로 초기화합니다. prev는 현재 노드가prev보다 크므로 정렬 된 순서를 따르는 지 확인하는 데 사용됩니다.
  • isBST(root, prev)를 호출합니다. (오버로드 된 함수 호출).

isBST(루트, 이전)

  • rootNULL이면true를 반환합니다.
  • isBST(root->left, prev)로 왼쪽 서브 트리를 재귀 적으로 확인합니다. false를 반환하면 false를 반환합니다.
  • root->data<=prev인 경우. 오름차순이 위반되었습니다. false를 반환합니다.
  • 이전->데이터루트->데이터로 업데이트합니다.
  • isBST(root->right, prev)로 오른쪽 서브 트리를 재귀 적으로 확인합니다. false를 반환하면 false를 반환합니다.
  • 그렇지 않으면 true를 반환합니다.

이진 트리를 확인하는 알고리즘의 구현이 이진 검색 트리입니다

알고리즘 1

#include <iostream>
using namespace std;

class Node {
 public:
  int data;
  Node *left, *right;
  Node(int x) {
    this->data = x;
    this->left = this->right = NULL;
  }
};
int getMin(Node* root) {
  while (root->left) {
    root = root->left;
  }

  return root->data;
}
int getMax(Node* root) {
  while (root->right) {
    root = root->right;
  }

  return root->data;
}
bool isBST(Node* root) {
  if (root == NULL) return true;

  if (root->left != NULL && getMax(root->left) > root->data) return false;

  if (root->right != NULL && getMin(root->right) < root->data) return false;

  if (!isBST(root->left) || !isBST(root->right)) return false;

  return true;
}
int main() {
  Node* root = new Node(6);
  root->left = new Node(3);
  root->right = new Node(9);
  root->left->left = new Node(1);
  root->left->right = new Node(5);
  root->right->left = new Node(7);
  root->right->right = new Node(11);
  if (isBST(root)) {
    cout << "This binary tree is a BST." << endl;
  } else {
    cout << "This binary tree is not a BST." << endl;
  }
  return 0;
}

알고리즘 2

#include <iostream>
using namespace std;

class Node {
 public:
  int data;
  Node *left, *right;
  Node(int x) {
    this->data = x;
    this->left = this->right = NULL;
  }
};
bool isBST(Node* root, int min, int max) {
  if (root == NULL) return 1;
  if (root->data < min || root->data > max) return 0;

  return isBST(root->left, min, root->data - 1) &&
         isBST(root->right, root->data + 1, max);
}

bool isBST(Node* root) { return isBST(root, INT_MIN, INT_MAX); }
int main() {
  Node* root = new Node(6);
  root->left = new Node(3);
  root->right = new Node(9);
  root->left->left = new Node(1);
  root->left->right = new Node(5);
  root->right->left = new Node(7);
  root->right->right = new Node(11);
  if (isBST(root)) {
    cout << "This binary tree is a BST." << endl;
  } else {
    cout << "This binary tree is not a BST." << endl;
  }
  return 0;
}

알고리즘 3

#include <iostream>
using namespace std;

class Node {
 public:
  int data;
  Node *left, *right;
  Node(int x) {
    this->data = x;
    this->left = this->right = NULL;
  }
};
bool isBST(Node* root, Node* l, Node* r) {
  if (root == NULL) return true;

  if (l != NULL and root->data <= l->data) return false;
  if (r != NULL and root->data >= r->data) return false;

  return isBST(root->left, l, root) && isBST(root->right, root, r);
}
bool isBST(Node* root) {
  Node* l = NULL;
  Node* r = NULL;
  return isBST(root, l, r);
}
int main() {
  Node* root = new Node(6);
  root->left = new Node(3);
  root->right = new Node(9);
  root->left->left = new Node(1);
  root->left->right = new Node(5);
  root->right->left = new Node(7);
  root->right->right = new Node(11);
  if (isBST(root)) {
    cout << "This binary tree is a BST." << endl;
  } else {
    cout << "This binary tree is not a BST." << endl;
  }
  return 0;
}

알고리즘 4

#include <iostream>
using namespace std;

class Node {
 public:
  int data;
  Node *left, *right;
  Node(int x) {
    this->data = x;
    this->left = this->right = NULL;
  }
};
bool isBST(Node* root, int& prev) {
  if (!root) return true;

  if (!isBST(root->left, prev)) return false;

  if (root->data <= prev) return false;
  prev = root->data;

  return isBST(root->right, prev);
}

bool isBST(Node* root) {
  int prev = INT_MIN;
  return isBST(root, prev);
}
int main() {
  Node* root = new Node(6);
  root->left = new Node(3);
  root->right = new Node(9);
  root->left->left = new Node(1);
  root->left->right = new Node(5);
  root->right->left = new Node(7);
  root->right->right = new Node(11);
  if (isBST(root)) {
    cout << "This binary tree is a BST." << endl;
  } else {
    cout << "This binary tree is not a BST." << endl;
  }
  return 0;
}

복잡성 분석

시간 복잡성

  • 평균 사례

주어진 이진 트리가 BST인지 여부를 확인하려면 모든n노드를 통과해야합니다. 속성을 무시하는 단일 노드는 트리가 BST가 아닌 것으로 이어지기 때문입니다. 따라서 시간 복잡도는 [Big Theta] :O(n)의 순서입니다.

  • 베스트 케이스

최상의 경우 시간 복잡도는O(n)순서입니다. 평균 케이스 시간 복잡성과 동일합니다.

  • 최악의 경우

최악의 시간 복잡도는O(n)의 순서입니다. 최상의 경우 시간 복잡성과 동일합니다.

공간 복잡성

알고리즘의 공간 복잡성은 재귀 호출에 필요한 추가 공간으로 인해O(n)입니다.

튜토리얼이 마음에 드시나요? DelftStack을 구독하세요 YouTube에서 저희가 더 많은 고품질 비디오 가이드를 제작할 수 있도록 지원해주세요. 구독하다
Harshit Jindal avatar Harshit Jindal avatar

Harshit Jindal has done his Bachelors in Computer Science Engineering(2021) from DTU. He has always been a problem solver and now turned that into his profession. Currently working at M365 Cloud Security team(Torus) on Cloud Security Services and Datacenter Buildout Automation.

LinkedIn

관련 문장 - Data Structure

관련 문장 - Binary Tree

관련 문장 - Binary Search Tree