일지

알고리즘...50

niamdank 2021. 9. 8. 01:25

이진 검색 트리 출력 함수 제작

노드의 깊이와 넓이의 관계를 파악하기 위해 1, 4 를 추가한다.

 

main.cpp

#include "Common.h"
#include "검색트리/BinarySearchTree.h"

int main()
{
	int n = 9;
	int* arr;

	// 동작 테스트를 위한 값
	//arr = new int[n]{ 2, 4, 6, 8, 10, 9, 7, 5, 3, 1 };
	arr = new int[n]{ 10, 5, 20, 3, 7, 15, 25, 1, 4 };

	BinarySearchTree tree;
	for (int i = 0; i < n; i++)
	{
		tree.Insert(arr[i]);
	}
	tree.PrintBinarySearchTree();

	//tree.Delete(5);
	//tree.PrintBinarySearchTree();

	// 출력하고 싶은 모양
	std::cout << "         10\n";
	std::cout << "    ┌────┴────┐\n";
	std::cout << "    5         20\n";
	std::cout << "  ┌─┴─┐     ┌─┴─┐\n";
	std::cout << "  5   20    5   20\n";
	std::cout << "┌─┴─┐\n";
	std::cout << "1   4\n";

	delete[] arr;
}

 

실행결과

       10
┌──────┴──────┐
     5       20
┌────┴────┐┌─┴─┐
  3  71525
┌─┴─┐


         10
    ┌────┴────┐
    5         20
  ┌─┴─┐     ┌─┴─┐
  5   20    5   20
┌─┴─┐
1   4

 

엔터 처리가 잘못됐다. 항상 가득 찬 상태의 이진 검색 트리로 처리하다 보니 잘못 생각한 부분이 있었다.

이 문제를 처리하기 위해 map을 도입했다.

 

BinarySearchTree.h

#pragma once
#include "../Common.h"
#include <string>
#include <queue>
#include <map>

using std::string;
using std::queue;
using std::map;

/// <summary>
/// 이진 검색 트리에 사용할 노드
/// </summary>
struct BinarySearchNode
{
	BinarySearchNode() : data{ 0 }, parent{ nullptr }, 
		left{ nullptr }, right{ nullptr } {}
	BinarySearchNode(int data) : data{ data }, parent{ nullptr }, 
		left{ nullptr }, right{ nullptr } {}

	void Clear()
	{
		data = 0;
		parent = nullptr;
		left = nullptr;
		right = nullptr;
	}

	int GetMaxDepth()
	{
		int leftMaxDepth{ left != nullptr ? left->GetMaxDepth() : 0 };
		int rightMaxDpth{ right != nullptr ? right->GetMaxDepth() : 0 };
		return (leftMaxDepth > rightMaxDpth ? leftMaxDepth : rightMaxDpth) + 1;
	}

	int GetCurDepth()
	{
		return (parent != nullptr ? parent->GetCurDepth() : 0) + 1;
	}

	bool HasLeftChild()
	{
		return left != nullptr;
	}

	bool HasRightChild()
	{
		return right != nullptr;
	}

	int data;
	BinarySearchNode* parent;
	BinarySearchNode* left;
	BinarySearchNode* right;
};

/// <summary>
/// 이진 검색 트리에서 노드의 재활용을 위한 매니저
/// </summary>
class BinarySearchNodeManager
{
public:
	~BinarySearchNodeManager();

	void Push(BinarySearchNode* node);
	BinarySearchNode* Pop();

private:
	BinarySearchNode* nodes;
};

/// <summary>
/// 연결 자료구조를 이용한 이진 검색 트리
/// </summary>
class BinarySearchTree
{
public:
	~BinarySearchTree();

	bool Exists(int data);
	const BinarySearchNode& Search(int data);
	void Insert(int data);
	void Delete(int data);

	void PrintBinarySearchTree();

private:
	void Insert(BinarySearchNode* parent, int data);
	void Delete(BinarySearchNode* node);

	void PrintBinarySearchTree(BinarySearchNode* node);

	BinarySearchNode* GetNode(int data);

	bool IsLeftNode(BinarySearchNode* node);
	bool IsRightNode(BinarySearchNode* node);

	int GetTreeMaxDepth();

private:
	BinarySearchNode* _root;
	BinarySearchNodeManager _nodeManager;
	queue<BinarySearchNode*> _queue;
	map<int, string> _numberMap;
	map<int, string> _stickMap;
};

 

BinarySearchTree.cpp

/// <summary>
/// 이진 검색 트리를 출력한다.
/// </summary>
void BinarySearchTree::PrintBinarySearchTree()
{
	if (_root == nullptr)
	{
		std::cout << "EMPTY\n";
		return;
	}

	int depth{ _root->GetMaxDepth() };

	for (int i = 1; i <= depth; i++)
	{
		_numberMap[i] = "";
		_stickMap[i] = "";
	}

	_queue.push(_root);
	while (!_queue.empty())
	{
		BinarySearchNode* node{ _queue.front() };
		_queue.pop();

		PrintBinarySearchTree(node);

		if (node->left != nullptr)
		{
			_queue.push(node->left);
		}
		if (node->right != nullptr)
		{
			_queue.push(node->right);
		}
	}

	for (int i = 1; i <= depth; i++)
	{
		std::cout << _numberMap[i] << '\n';
		std::cout << _stickMap[i] << '\n';
	}
	std::cout << "\n\n";
}

/// <summary>
/// 이진 검색 트리를 출력한다.
/// </summary>
/// <param name="node">현재 출력할 노드</param>
void BinarySearchTree::PrintBinarySearchTree(BinarySearchNode* node)
{
	int targetDepth{ node->GetCurDepth() };
	int depth{ node->GetMaxDepth() };
	int width{ (depth - 1) * 5 };
	int center{ width / 2 };

	string& numberStr{ _numberMap[targetDepth] };
	string& stickStr{ _stickMap[targetDepth] };

	for (int i = 0; i < width; i++)
	{
		numberStr.push_back(' ');
	}
	numberStr.append(std::to_string(node->data));
	for (int i = 0; i < width; i++)
	{
		numberStr.push_back(' ');
	}

	for (int i = 0; i < center; i++)
	{
		stickStr.push_back(' ');
	}
	if (node->HasLeftChild())
	{
		stickStr.append("┌");
		for (int i = 1; i < center; i++)
		{
			stickStr.append("─");
		}
	}
	else
	{
		for (int i = 0; i < width; i++)
		{
			stickStr.push_back(' ');
		}
	}

	if (node->HasLeftChild() || node->HasRightChild())
	{
		stickStr.append("┴");
	}

	if (node->HasRightChild())
	{
		for (int i = 1; i < center; i++)
		{
			stickStr.append("─");
		}
		stickStr.append("┐");
	}
	else
	{
		for (int i = 0; i < width; i++)
		{
			stickStr.push_back(' ');
		}
	}
}

 

실행결과

               10
       ┌──────┴──────┐
          5               20
     ┌────┴────┐  ┌─┴─┐
     3     71525
  ┌─┴─┐
14



         10
    ┌────┴────┐
    5         20
  ┌─┴─┐     ┌─┴─┐
  5   20    5   20
┌─┴─┐
1   4

 

엔터 처리는 설정이 되었으나 여전히 간격이 적절하지 못하다.