<aside>
#include <stdio.h>
#include <stdlib.h>
#define MAX_NODES 1000
#define NOT_EXIST -1
// 배열 형태로 구현
int bst[MAX_NODES];
// 초기화
void initBST() {
for (int i = 0; i < MAX_NODES; i++) {
bst[i] = NOT_EXIST;
}
}
/// <summary>
/// root => 0
/// root->left => 1
/// root->right => 2
/// root->left->left => 3
/// root->left->right => 4
/// root->right->left => 5
/// root->right->right => 6
/// </summary>
int leftChild(int nodeIndex) {
return nodeIndex * 2 + 1;
}
int rightChild(int nodeIndex) {
return nodeIndex * 2 + 2;
}
// ----------------------------//
int hasEntry(int nodeIndex) {
// nodeInex값이 -1로, 즉 값이 없으면 return 0을 반환
// 즉 값이 없는 배열까지 쭉 이동
return (nodeIndex < MAX_NODES && bst[nodeIndex] != NOT_EXIST);
}
void insertNode(int key) {
int curNodeIndex = 0; // rootNode의 인덱스
while (hasEntry(curNodeIndex)) {
// 현재 bst 인덱스의 값보다 key가 더 크면 오른쪽, 작으면 왼쪽
if (key < bst[curNodeIndex])
{
curNodeIndex = leftChild(curNodeIndex);
}
else
{
curNodeIndex = rightChild(curNodeIndex);
}
}
bst[curNodeIndex] = key;
}
void deleteNodeByIndex(int nodeIndex) {
// nodeindex의 자식 index를 지정
int leftChildIndex = leftChild(nodeIndex);
int rightChildIndex = rightChild(nodeIndex);
// 둘 다 노드가 없는 경우
if (!hasEntry(leftChildIndex) && !hasEntry(rightChildIndex))
{
bst[nodeIndex] = NOT_EXIST;
}
// 왼쪽 노드만 있는 경우
else if (hasEntry(leftChildIndex) && !hasEntry(rightChildIndex))
{
bst[nodeIndex] = bst[leftChildIndex];
deleteNodeByIndex(leftChildIndex);
}
// 오른쪽 노드만 있는 경우
else if (!hasEntry(leftChildIndex) && hasEntry(rightChildIndex))
{
bst[nodeIndex] = bst[rightChildIndex];
deleteNodeByIndex(rightChildIndex);
}
// 양쪽 노드 존재하는 경우
else
{
int successorIndex = rightChildIndex;
while (hasEntry(leftChild(successorIndex)))
{
successorIndex = leftChild(successorIndex);
}
bst[nodeIndex] = bst[successorIndex];
deleteNodeByIndex(successorIndex);
}
}
// 인덱스로 삭제
// key로 찾은 뒤 재귀함수로 자식 노드로 가져옴
void deleteNode(int key) {
int curNodeIndex = 0;
while (hasEntry(curNodeIndex)) {
if (key < bst[curNodeIndex])
{
curNodeIndex = leftChild(curNodeIndex);
}
else if (key > bst[curNodeIndex])
{
curNodeIndex = rightChild(curNodeIndex);
}
else if (key == bst[curNodeIndex]) break;
}
// 찾는 값의 index를 넘김
deleteNodeByIndex(curNodeIndex);
}
void inorder(int nodeIndex) {
if (!hasEntry(nodeIndex)) return;
inorder(leftChild(nodeIndex));
printf("%d@%d ", bst[nodeIndex], nodeIndex);
inorder(rightChild(nodeIndex));
}
void printInorder() {
inorder(0);
printf("\\n\\n");
}
int main()
{
initBST();
insertNode(5);
insertNode(2);
insertNode(3);
insertNode(1);
insertNode(8);
insertNode(10);
insertNode(9);
insertNode(6);
printInorder();
printf("\\n");
deleteNode(2);
printInorder();
printf("\\n");
deleteNode(5);
printInorder();
printf("\\n");
}
</aside>
Detail
<aside>
// 양쪽 노드 존재하는 경우
else
{
int successorIndex = rightChildIndex;
while (hasEntry(leftChild(successorIndex)))
{
successorIndex = leftChild(successorIndex);
}
bst[nodeIndex] = bst[successorIndex];
deleteNodeByIndex(successorIndex);
}
-----------------
BST 핵심 규칙
- 왼쪽 서브트리의 모든 값 < 현재 노드
- 오른쪽 서브트리의 모든 값 > 현재 노드
==>
2가지 방법 선택지
- predecessor(전임자) : 왼쪽 서브트리에서 가장 큰 값
- successor(후임자) : 오른쪽 서브트리에서 가장 작은 값
위 방식은 후임자 방식을 사용하여 while문으로 leftchild가 가장 작은 곳까지 이동하여 successorIndex 값을 지정, 이후 삭제할 nodeIndex 값을 해당 successorIndex 값으로 변경해줘서 균형을 맞춤
EX)
10
/ \\
5 15
/
12
/
11
10 삭제 가정
11
/ \\
5 15
/
12
가장 작은 11 값을 삭제될 INDEX 자리로 이동 시켜 균형을 맞춤
</aside>