본문 바로가기
C/알고리즘

[C] AVL TREE (코드 보완)

by 덤더리덤떰 2024. 2. 12.

1. AVL TREE 이전 게시물

2023.12.10 - [C/알고리즘] - [C] AVL TREE

 

[C] AVL TREE

1. AVL Tree : 자세한 설명은 아래 글 참조 2023.12.07 - [C++/자료구조] - [C++]AVL Tree [C++]AVL Tree 1. 균형이진탐색트리 (Adelson-Velskii&Landis) : 균형인수(Balance Factor:BF)를 이용하여 트리가 비균형 상태로 되면

growingupis.tistory.com

 

2. AVL TREE 코드보완

(1) bst delete node 함수

 

1) 공백 트리인 경우 
: 그냥 return

if (*node == NULL) {
	printf("삭제할 노드가 존재하지 않습니다\n");
	return;
}

 

2) *node==NULL이 아닌 경우 TREENODE * cur= *node, TREENODE * pre = NULL;로 초기화한 후 , 해당 값을 찾을 때까지 두 노드포인터 순회시킨다

TREENODE* cur = *node;
TREENODE* pre=NULL;
while (cur->data != key) {
	pre = cur;
	if (cur->data < key) {
		cur = cur->right;
	}
	else {
		cur = cur->left;
	}
}

 

3) 이때, cur==NULL인 경우(해당 값이 존재하지 않는 경우) 

: 그냥 return

if (cur == NULL) {
	printf("해당 노드는 존재하지 않습니다\n");
	return;
}

 

4) cur!=NULL인 경우 세 가지 케이스로 분류

⇒ 루트 노드의 주소를 바꾸어야하는 경우와 아닌 경우로 세부케이스를 또 나눈다 

 

4-1) 삭제할 노드가 단말노드인 경우

  • pre!=NULL인 경우
  • pre==NULL인 경우(루트 노드의 주소를 바꾸어야 하는 경우)
if (cur->left == NULL && cur->right == NULL) {
	if (pre != NULL) {
		if (pre->right == cur) {
			pre->right = NULL;
		}
		else {
			pre->left = NULL;
		}
	}
	else {
		*node = NULL;
	}
	free(cur);
	cur = NULL;
}

 

4-2) 삭제할 노드의 자식노드가 2개인 경우

: 이 경우엔 삭제노드를 진짜 메모리상에서 삭제하는 것이 아닌 후계자의 노드의 데이터를 복사해주고 후계자의 노드를 삭제하는 것이기에 루트 노드의 주소를 바꾸어야 하는 경우는 존재하지 않는다

	else if (cur->left != NULL && cur->right!=NULL) {
		TREENODE* succ = cur;
		TREENODE* succ_parent = cur;
		succ = succ->right;
		while (succ->left != NULL) {
			succ_parent = succ;
			succ = succ->left;
		}
		if (succ_parent->right == succ) {
			cur->data = succ->data;
			succ_parent->right = succ->right;
			free(cur);
			cur = NULL;
		}
		else {
			cur->data = succ->data;
			succ_parent->left = succ->right;
			free(cur);
			cur = NULL;
		}
	}

 

4-3) 삭제할 노드의 자식노드가 1개인 경우

  • pre!=NULL인 경우
  • pre==NULL인 경우(루트 노드의 주소를 바꾸어야 하는 경우)
else {
	TREENODE* child;
	if (cur->left == NULL) {
		child = cur->right;
	}
	else {
		child = cur->left;
	}
	if (pre != NULL) {
		
		if (pre->left == NULL) {
			pre->right = child;
		}
		else {
			pre->left = child;
		}
	}
	else {
		*node = child;
	}
}

 

(2) avl delete node 함수

1) *root==NULL인 경우 ( 삭제할 노드가 존재하지않는 경우)

: 그냥 return

if (*root == NULL) {
	printf("삭제할 노드가 존재하지 않습니다\n");
	return;
}

 

2) *root!=NULL인 경우

 

2-1) (*root)->data== key인 경우 (삭제할 노드를 찾은 경우)

: bst delete node함수 수행

: 위의 함수를 수행하고 나면 삭제 노드에는 삭제 노드의 자식노드가 존재할 것 ( 없는 경우도 존재)

⇒ 그 노드부터 다시 rebalancing을 수행해야하기에 (*root)= rebalance(root); 함수 수행

if ((*root)->data == key) {
	BST_DELETE_NODE(root, key);
	(*root) = rebalance(root);
}

 

2-2) (*root)->data < key인 경우 

: 해당 노드의 오른쪽 노드를 전달하며 avl delete node함수 수행

else if ((*root)->data < key) {
	AVL_DELETE_NODE(&((*root)->right), key);
	(*root) = rebalance(root);
}

 

2-3) (*root)->data > key인 경우

: 해당 노드의 왼쪽 노드를 전달하며 avl delete node함수 수행

else if ((*root)->data > key) {
	AVL_DELETE_NODE(&((*root)->left), key);
	(*root) = rebalance(root);
}

 

⇒ 이때, 2-2) 2-3) 수행을 통해 삭제 노드를 삭제하고 나면 삭제노드부터 루트노드까지 다시 거슬러 올라가며 rebalancing과정이 필요하기 때문에 해당 노드에 대해 (*root)= rebalance(root); 함수 수행

 

avl.h
#pragma once
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <memory.h>
#include <stdbool.h>
#define TRUE 1
#define FALSE 0
#define ONLY_REBALNACING true //리밸런싱만 해라
#define DELETE false 

typedef int NodeData;
#define MAX(a,b) a>b?a:b

typedef struct _NODEMAP_ {
	int flag;
	NodeData data;
}NODEMAP;

typedef struct _TREE_NODE_ {
	NodeData data;
	struct _TREE_NODE_* left;
	struct _TREE_NODE_* right;
}TREENODE;


int getMax(int a, int b) {
	return ((a > b) ? a : b);
}

int getHeight(TREENODE* root) {
	if (root == NULL) {
		return 0;
	}
	else {
		return 1 +max(getHeight(root->left), getHeight(root->right));
	}
}

int getBF(TREENODE* root) {
	if (root != NULL) {
		return getHeight(root->left) - getHeight(root->right);
	}
}

TREENODE* RR_TYPE(TREENODE* root) {
	TREENODE* child = root->right;
	root->right = child->left;
	child->left = root;

	return child;
}


TREENODE* LL_TYPE(TREENODE* root) {
	TREENODE* child = root->left;
	root->left = child->right;
	child->right = root;

	return child;
}

TREENODE* LR_TYPE(TREENODE* root) {
	TREENODE* child = root->left;
	root->left = RR_TYPE(child);
	return LL_TYPE(root);
}

TREENODE* RL_TYPE(TREENODE* root) {
	TREENODE* child = root->right;
	root->right = LL_TYPE(child);
	return RR_TYPE(root);
}

TREENODE* rebalance(TREENODE** root) {
	int BF = getBF(*root);
	if (BF == 2) {
		if (getBF((*root)->left) >= 0) {
			//LL유형
			*root = LL_TYPE(*root);
		}
		else {
			*root = LR_TYPE(*root);
		}
	}
	else if (BF == -2) {
		if (getBF((*root)->right)<=0) {
			//RR유형
			*root = RR_TYPE(*root);
		}
		else {
			*root = RL_TYPE(*root);
		}
	}

	return *root;
}



TREENODE* AVL_INSERT_NODE(TREENODE** root, int key) {
	
	if (*root == NULL) {
		*root = (TREENODE*)calloc(1, sizeof(TREENODE));
		assert(*root != NULL);
		(*root)->data = key;
		return *root;
	}
	else if ((*root)->data < key) {
		(*root)->right = AVL_INSERT_NODE(&((*root)->right), key);
		*root = rebalance(root);
	}
	else if ((*root)->data > key) {
		(*root)->left = AVL_INSERT_NODE(&((*root)->left), key);
		*root = rebalance(root);
	}
	else if ((*root)->data == key) {
		printf("\n해당 키는 이미 존재하기에 삽입할 수 없습니다\n");
		return;
	}

	return *root;
}

int countNode(TREENODE* node) {
	if (node == NULL) return 0;
	return 1 + countNode(node->left) + countNode(node->right);
}
void printGivenLevel(TREENODE* root, int level, NODEMAP* map, int pos)
{
	if (root == NULL)
	{
		return;
	}
	if (level == 1) {
		map[pos].data = root->data;
		map[pos].flag = TRUE;
	}
	else if (level > 1)
	{
		printGivenLevel(root->left, level - 1, map, pos * 2);
		printGivenLevel(root->right, level - 1, map, pos * 2 + 1);
	}
}

void showTree(TREENODE* node)
{
	int height = 0;
	int numOfNodes = 0;
	NODEMAP* treeArray = NULL;
	char** square = NULL;
	static int pos = 0;
	int cnt_i;
	int cnt_j;
	int position;
	int start, term, index;

	height = getHeight(node);
	if (height != 0) {
		numOfNodes = (1 << height);
	}
	treeArray = (NODEMAP*)calloc(numOfNodes, sizeof(NODEMAP));
	assert(treeArray != NULL);

	square = (char**)calloc(height, sizeof(char*));
	for (cnt_i = 0; cnt_i < height; cnt_i++)
	{
		square[cnt_i] = (char*)calloc(numOfNodes, sizeof(char));
		memset(square[cnt_i], '.', numOfNodes);
	}


	pos = 1;
	for (cnt_i = 1; cnt_i <= height; cnt_i++) {
		printGivenLevel(node, cnt_i, treeArray, pos);
	}


	for (cnt_i = 1; cnt_i <= numOfNodes; cnt_i++)
	{
		treeArray[cnt_i - 1] = treeArray[cnt_i];
	}

	pos = 0;
	start = (1 << (height - 1)) - 1;
	term = (1 << (height));
	index = (1 << (height - 2));
	for (cnt_i = 0; cnt_i < height; cnt_i++)
	{
		for (cnt_j = start; cnt_j < numOfNodes; cnt_j += term)
		{
			if (treeArray[pos].flag == TRUE) {
				if (treeArray[pos].data >= 0 && treeArray[pos].data <= 9) {
					square[cnt_i][cnt_j] = (treeArray[pos].data + '0');
				}
				else {
					square[cnt_i][cnt_j] = (treeArray[pos].data);
				}
			}
			else {
				square[cnt_i][cnt_j] = '.';
			}
			pos += 1;
		}
		term >>= 1;
		start -= index;
		index >>= 1;
	}

	printf("\n");
	for (cnt_i = 0; cnt_i < height; cnt_i++)
	{
		for (cnt_j = 0; cnt_j < numOfNodes; cnt_j++)
		{
			printf("%c", square[cnt_i][cnt_j]);
		}
		printf("\n");
	}

	if (treeArray != NULL) {
		free(treeArray);
	}
	if (square != NULL)
	{
		for (cnt_i = 0; cnt_i < height; cnt_i++)
		{
			if (square[cnt_i] != NULL)
			{
				free(square[cnt_i]);
			}
		}
		free(square);
	}
}


void displayInorder(TREENODE* root) {
	if (root != NULL) {
		displayInorder(root->left);
		printf("%d ", root->data);
		displayInorder(root->right);
	}
}

void BST_DELETE_NODE(TREENODE** node, int key) {
	if (*node == NULL) {
		printf("삭제할 노드가 존재하지 않습니다\n");
		return;
	}
	else {
		TREENODE* cur = *node;
		TREENODE* pre=NULL;
		while (cur->data != key) {
			pre = cur;
			if (cur->data < key) {
				cur = cur->right;
			}
			else {
				cur = cur->left;
			}
		}
		if (cur == NULL) {
			printf("해당 노드는 존재하지 않습니다\n");
			return;
		}
		else {
			if (cur->left == NULL && cur->right == NULL) {
				if (pre != NULL) {
					if (pre->right == cur) {
						pre->right = NULL;
					}
					else {
						pre->left = NULL;
					}
				}
				else {
					*node = NULL;
				}
				free(cur);
				cur = NULL;
			}
			else if (cur->left != NULL && cur->right!=NULL) {
				TREENODE* succ = cur;
				TREENODE* succ_parent = cur;
				succ = succ->right;
				while (succ->left != NULL) {
					succ_parent = succ;
					succ = succ->left;
				}
				if (succ_parent->right == succ) {
					cur->data = succ->data;
					succ_parent->right = succ->right;
					free(cur);
					cur = NULL;
				}
				else {
					cur->data = succ->data;
					succ_parent->left = succ->right;
					free(cur);
					cur = NULL;
				}
			}
			else {
				TREENODE* child;
				if (cur->left == NULL) {
					child = cur->right;
				}
				else {
					child = cur->left;
				}
				if (pre != NULL) {
					
					if (pre->left == NULL) {
						pre->right = child;
					}
					else {
						pre->left = child;
					}
				}
				else {
					*node = child;
				}
			}
		}
	}
}

void AVL_DELETE_NODE(TREENODE** root, int key) {
	if (*root == NULL) {
		printf("삭제할 노드가 존재하지 않습니다\n");
		return;
	}
	
	if ((*root)->data == key) {
		BST_DELETE_NODE(root, key);
		(*root) = rebalance(root);
	}
	else if ((*root)->data < key) {
		AVL_DELETE_NODE(&((*root)->right), key);
		(*root) = rebalance(root);
	}
	else if ((*root)->data > key) {
		AVL_DELETE_NODE(&((*root)->left), key);
		(*root) = rebalance(root);
	}

}

void BST_INSERT_NODE(TREENODE** root, int key) {
	//공백 트리인 경우
	TREENODE* newNode = (TREENODE*)calloc(1, sizeof(TREENODE));
	assert(newNode != NULL);
	newNode->data = key;
	if (*root == NULL) {
		*root = newNode;
	}
	else {
		TREENODE* curNode = *root;
		TREENODE* preNode = NULL;
		while (curNode != NULL) {
			preNode = curNode;
			if (curNode->data < key) {
				curNode = curNode->right;
			}
			else if(curNode->data>key){
				curNode = curNode->left;
			}
			else if (curNode->data == key) {
				printf("\n해당 노드는 이미 존재하기때문에 삽입할 수 없습니다\n");
				return;
			}
		}
		if (preNode->right == NULL) {
			preNode->right = newNode;
		}
		else {
			preNode->left = newNode;
		}
	}
}​
main.c
#include "avl.h"

int main() {

	int i;
	int data;
	TREENODE* root_AVL = NULL;
	TREENODE* root_BST = NULL;

	printf("\n*************AVL트리 삽입******************\n");
	for (i = 0; i < 8; i++) {
		AVL_INSERT_NODE(&root_AVL, i);
		printf("\nInsert %d\n", i);
		showTree(root_AVL);
		getchar();
	}
	printf("\n ************AVL트리 출력*****************\n\n");
	displayInorder(root_AVL);

	printf("\n *************AVL트리 삭제***************\n\n");
	for (i = 0; i < 8; i++) {



		AVL_DELETE_NODE(&root_AVL, i);
		printf("\nDelete %d\n", i);
		showTree(root_AVL);
		getchar();
	}
	printf("\n ************AVL트리 출력*****************\n\n");
	displayInorder(root_AVL);
	



	printf("\n **************BST트리 삽입 **************\n\n");
	for (i = 0; i < 8; i++) {
		BST_INSERT_NODE(&root_BST, i);
		printf("\nInsert %d\n", i);
		showTree(root_BST);
		getchar();
	}
	printf("\n ************BST트리 출력****************\n\n");
	displayInorder(root_BST);

	printf("\n *************BST트리 삭제***************\n\n");
	for (i = 0; i < 8; i++) {
		BST_DELETE_NODE(&root_BST, i);
		printf("\nDelete %d\n", i);
		showTree(root_BST);
		getchar();
	}
	printf("\n ************BST트리 출력*****************\n\n");
	displayInorder(root_BST);







	getchar();
	return 0;
}​

 

'C > 알고리즘' 카테고리의 다른 글

[C] Prim Algorithm 코드 보완  (0) 2024.02.13
[C] 정렬 알고리즘  (0) 2024.02.12
[C] 이진 탐색 트리 (BST)  (0) 2024.02.08
[C] 이중 연결 리스트  (0) 2024.02.06
[C] AVL TREE  (0) 2023.12.10