ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 알고리즘...44
    일지 2021. 8. 31. 01:28

    AVL 트리 구현

    AVLTree.h

    #pragma once
    #include "../Common.h"
    
    /// <summary>
    /// AVL 트리에 사용할 노드
    /// </summary>
    struct AVLNode
    {
    	AVLNode() : data{ 0 }, bf{ 0 }, parent{ nullptr },
    		left{ nullptr }, right{ nullptr } {}
    	AVLNode(int data) : data{ data }, bf{ 0 }, parent{ nullptr },
    		left{ nullptr }, right{ nullptr } {}
    
    	void Clear()
    	{
    		data = 0;
    		parent = nullptr;
    		left = nullptr;
    		right = nullptr;
    	}
    
    	bool HasBalanceProblem()
    	{
    		return bf < -1 || 1 < bf;
    	}
    
    	int data;
    	int bf;
    	AVLNode* parent;
    	AVLNode* left;
    	AVLNode* right;
    };
    
    /// <summary>
    /// AVL 트리에서 노드의 재활용을 위한 매니저
    /// </summary>
    class AVLNodeManager
    {
    public:
    	~AVLNodeManager();
    
    	void Push(AVLNode* node);
    	AVLNode* Pop();
    
    private:
    	AVLNode* nodes;
    };
    
    /// <summary>
    /// 연결 자료구조를 이용한 AVL 트리
    /// </summary>
    class AVLTree
    {
    public:
    	~AVLTree();
    
    	bool Exists(int data);
    	const AVLNode& Search(int data);
    	void Insert(int data);
    	void Delete(int data);
    
    private:
    	void Insert(AVLNode* parent, int data);
    	void Delete(AVLNode* node);
    
    	AVLNode* GetNode(int data);
    
    	bool IsLeftNode(AVLNode* node);
    	bool IsRightNode(AVLNode* node);
    
    	AVLNode* RotateLeft(AVLNode* node);
    	AVLNode* RotateRight(AVLNode* node);
    
    	int CalculateBalaceFactor(AVLNode* node);
    
    	int GetNodeDepth(AVLNode* node, int depth = 0);
    
    	bool IsLLCase(AVLNode* c, AVLNode* c2);
    	bool IsRRCase(AVLNode* c, AVLNode* c2);
    	bool IsLRCase(AVLNode* c, AVLNode* c2);
    	bool IsRLCase(AVLNode* c, AVLNode* c2);
    
    private:
    	AVLNode* _root;
    	AVLNodeManager _nodeManager;
    };

     

    AVLTree.cpp

    #include "AVLTree.h"
    
    #pragma region 노드 매니저
    /// <summary>
    /// 종료 전 생성하 노드 제거
    /// </summary>
    AVLNodeManager::~AVLNodeManager()
    {
    	while (nodes != nullptr)
    	{
    		AVLNode* temp{ nodes };
    		nodes = nodes->left;
    		delete temp;
    	}
    }
    
    /// <summary>
    /// 사용 완료한 노드를 매니저에 저장
    /// </summary>
    /// <param name="node">사용후 반환할 노드</param>
    void AVLNodeManager::Push(AVLNode* node)
    {
    	node->left = nodes;
    	nodes = node;
    }
    
    /// <summary>
    /// 노드가 필요한 경우 매니저에서 반환
    /// </summary>
    /// <returns>사용할 수 있는 노드</returns>
    AVLNode* AVLNodeManager::Pop()
    {
    	AVLNode* node{ nodes };
    
    	if (node != nullptr)
    	{
    		nodes = node->left;
    		node->Clear();
    	}
    	else
    	{
    		node = new AVLNode();
    	}
    
    	return node;
    }
    #pragma endregion
    
    #pragma region AVL트리
    /// <summary>
    /// 종료 전 남은 노드 제거 처리
    /// </summary>
    AVLTree::~AVLTree()
    {
    	while (_root != nullptr)
    	{
    		Delete(_root);
    	}
    }
    
    /// <summary>
    /// AVL 트리에서 특정 값을 가지는 노드가 존재하는지 여부 확인
    /// </summary>
    /// <param name="data">찾을 값</param>
    /// <returns>존재 여부</returns>
    bool AVLTree::Exists(int data)
    {
    	AVLNode* node{ _root };
    
    	while (node != nullptr)
    	{
    		if (node->data == data)
    		{
    			return true;
    		}
    		else if (node->data > data)
    		{
    			node = node->left;
    		}
    		else
    		{
    			node = node->right;
    		}
    	}
    
    	return false;
    }
    
    /// <summary>
    /// AVL 트리에서 주어진 값을 가진 노드를 반환
    /// </summary>
    /// <param name="data">찾을 값</param>
    /// <returns>값을 가진 노드, 없으면 nullptr</returns>
    const AVLNode& AVLTree::Search(int data)
    {
    	return *GetNode(data);
    }
    
    /// <summary>
    /// AVL 트리에 값을 가지는 노드를 삽입
    /// </summary>
    /// <param name="data">삽입할 값</param>
    void AVLTree::Insert(int data)
    {
    	if (Exists(data))
    	{
    		return;
    	}
    
    	Insert(_root, data);
    	CalculateBalaceFactor(_root);
    }
    
    /// <summary>
    /// AVL 트리에서 해당 값을 가지는 노드를 제거
    /// </summary>
    /// <param name="data">제거할 값</param>
    void AVLTree::Delete(int data)
    {
    	if (!Exists(data))
    	{
    		return;
    	}
    
    	Delete(GetNode(data));
    	CalculateBalaceFactor(_root);
    }
    
    /// <summary>
    /// AVL 트리 삽입 처리
    /// </summary>
    /// <param name="parent">삽입해야 할 노드의 부모</param>
    /// <param name="data">삽입할 값</param>
    void AVLTree::Insert(AVLNode* parent, int data)
    {
    	if (parent == nullptr)
    	{
    		AVLNode* node{ _nodeManager.Pop() };
    		node->data = data;
    		_root = node;
    	}
    	else if (parent->data > data)
    	{
    		if (parent->left == nullptr)
    		{
    			AVLNode* node{ _nodeManager.Pop() };
    			node->data = data;
    			node->parent = parent;
    			parent->left = node;
    		}
    		else
    		{
    			Insert(parent->left, data);
    		}
    	}
    	else
    	{
    		if (parent->right == nullptr)
    		{
    			AVLNode* node{ _nodeManager.Pop() };
    			node->data = data;
    			node->parent = parent;
    			parent->right = node;
    		}
    		else
    		{
    			Insert(parent->right, data);
    		}
    	}
    }
    
    /// <summary>
    /// AVL 트리 제거 처리
    /// </summary>
    /// <param name="node">제거할 노드</param>
    void AVLTree::Delete(AVLNode* node)
    {
    	AVLNode* parent{ node->parent };
    
    	if (node->left == nullptr && node->right == nullptr)
    	{
    		if (IsLeftNode(node))
    		{
    			parent->left = nullptr;
    		}
    		else if (IsRightNode(node))
    		{
    			parent->right = nullptr;
    		}
    		else
    		{
    			_root = nullptr;
    		}
    
    		_nodeManager.Push(node);
    	}
    	else if (node->left != nullptr && node->right == nullptr ||
    		node->left == nullptr && node->right != nullptr)
    	{
    		AVLNode* child{ node->left };
    		if (child == nullptr)
    		{
    			child = node->right;
    		}
    
    		if (IsLeftNode(node))
    		{
    			parent->left = child;
    		}
    		else if (IsRightNode(node))
    		{
    			parent->right = child;
    		}
    		else
    		{
    			_root = child;
    		}
    		child->parent = parent;
    
    		_nodeManager.Push(node);
    	}
    	else
    	{
    		AVLNode* child{ node->left };
    		while (child->right != nullptr)
    		{
    			child = child->right;
    		}
    		node->data = child->data;
    		Delete(child);
    	}
    }
    
    /// <summary>
    /// 주어진 값을 가진 노드의 포인터를 반환한다.
    /// </summary>
    /// <param name="data">찾으려는 값</param>
    /// <returns>노드의 포인터</returns>
    AVLNode* AVLTree::GetNode(int data)
    {
    	AVLNode* node{ _root };
    
    	while (node != nullptr)
    	{
    		if (node->data == data)
    		{
    			break;
    		}
    		else if (node->data > data)
    		{
    			node = node->left;
    		}
    		else
    		{
    			node = node->right;
    		}
    	}
    
    	return node;
    }
    
    /// <summary>
    /// 해당 노드가 부모 노드의 왼쪽 자식인지 여부
    /// </summary>
    /// <param name="node">확인할 노드</param>
    /// <returns>왼쪽 자식인지 여부</returns>
    bool AVLTree::IsLeftNode(AVLNode* node)
    {
    	return node->parent != nullptr && node->parent->left == node;
    }
    
    /// <summary>
    /// 해당 노드가 부모 노드의 오른쪽 자식인지 여부
    /// </summary>
    /// <param name="node">확인할 노드</param>
    /// <returns>오른쪽 자식인지 여부</returns>
    bool AVLTree::IsRightNode(AVLNode* node)
    {
    	return node->parent != nullptr && node->parent->right == node;
    }
    
    /// <summary>
    /// 주어진 노드를 기준으로 왼쪽으로 회전한다.
    /// </summary>
    /// <param name="node">기준 노드</param>
    AVLNode* AVLTree::RotateLeft(AVLNode* node)
    {
    	AVLNode* x{ node };
    	AVLNode* c{ x->right };
    
    	c->left = x;
    	c->parent = x->parent;
    	x->parent = c;
    	x->right = nullptr;
    
    	return c;
    }
    
    /// <summary>
    /// 주어진 노드를 기준으로 오른쪽으로 회전한다.
    /// </summary>
    /// <param name="node">기준 노드</param>
    AVLNode* AVLTree::RotateRight(AVLNode* node)
    {
    	AVLNode* x{ node };
    	AVLNode* c{ x->left };
    
    	c->right = x;
    	c->parent = x->parent;
    	x->parent = c;
    	x->left = nullptr;
    
    	return c;
    }
    
    /// <summary>
    /// 주어진 노드의 BF를 구하여 반환한다.
    /// </summary>
    /// <param name="node">타겟 노드</param>
    int AVLTree::CalculateBalaceFactor(AVLNode* node)
    {
    	if (node == nullptr)
    	{
    		return 0;
    	}
    
    	CalculateBalaceFactor(node->left);
    	CalculateBalaceFactor(node->right);
    
    	node->bf = GetNodeDepth(node->left) - GetNodeDepth(node->right);
    
    	// 밸런스가 무너진 경우
    	if (node->HasBalanceProblem())
    	{
    		AVLNode* x{ node };
    		AVLNode* c{ x->left != nullptr ? x->left : x->right };
    		AVLNode* c2{ c->left != nullptr ? c->left : c->right };
    
    		if (IsLLCase(c, c2))
    		{
    			node = RotateRight(x);
    		}
    		else if (IsRRCase(c, c2))
    		{
    			node = RotateLeft(x);
    		}
    		else if (IsLRCase(c, c2))
    		{
    			RotateRight(c);
    			node = RotateLeft(x);
    		}
    		else if (IsRLCase(c, c2))
    		{
    			RotateLeft(c);
    			node = RotateRight(x);
    		}
    
    		node->bf = GetNodeDepth(node->left) - GetNodeDepth(node->right);
    	}
    
    	return node->bf + (node != _root ? 1 : 0);
    }
    
    /// <summary>
    /// 주어진 노드의 깊이를 구하여 반환한다.
    /// </summary>
    /// <param name="node">시작 노드</param>
    /// <returns>시작 노드의 최대 깊이</returns>
    int AVLTree::GetNodeDepth(AVLNode* node, int depth)
    {
    	if (node == nullptr)
    	{
    		return depth;
    	}
    
    	int leftDepth{ GetNodeDepth(node->left, depth + 1) };
    	int rightDepth{ GetNodeDepth(node->right, depth + 1) };
    
    	return (leftDepth > rightDepth ? leftDepth : rightDepth);
    }
    
    /// <summary>
    /// 주어진 노드의 배치가 LL케이스인지 여부를 반환한다.
    /// </summary>
    /// <param name="c">문제 노드의 자식</param>
    /// <param name="c2">c의 자식</param>
    /// <returns>LL케이스인지 여부</returns>
    bool AVLTree::IsLLCase(AVLNode* c, AVLNode* c2)
    {
    	if (IsLeftNode(c) && IsLeftNode(c2))
    	{
    		return true;
    	}
    	return false;
    }
    
    /// <summary>
    /// 주어진 노드의 배치가 RR케이스인지 여부를 반환한다.
    /// </summary>
    /// <param name="c">문제 노드의 자식</param>
    /// <param name="c2">c의 자식</param>
    /// <returns>RR케이스인지 여부</returns>
    bool AVLTree::IsRRCase(AVLNode* c, AVLNode* c2)
    {
    	if (IsRightNode(c) && IsRightNode(c2))
    	{
    		return true;
    	}
    	return false;
    }
    
    /// <summary>
    /// 주어진 노드의 배치가 LR케이스인지 여부를 반환한다.
    /// </summary>
    /// <param name="c">문제 노드의 자식</param>
    /// <param name="c2">c의 자식</param>
    /// <returns>LR케이스인지 여부</returns>
    bool AVLTree::IsLRCase(AVLNode* c, AVLNode* c2)
    {
    	if (IsLeftNode(c) && IsRightNode(c2))
    	{
    		return true;
    	}
    	return false;
    }
    
    /// <summary>
    /// 주어진 노드의 배치가 RL케이스인지 여부를 반환한다.
    /// </summary>
    /// <param name="c">문제 노드의 자식</param>
    /// <param name="c2">c의 자식</param>
    /// <returns>RL케이스인지 여부</returns>
    bool AVLTree::IsRLCase(AVLNode* c, AVLNode* c2)
    {
    	if (IsRightNode(c) && IsLeftNode(c2))
    	{
    		return true;
    	}
    	return false;
    }
    #pragma endregion

    댓글

Designed by Tistory.