비선형 자료구조
트리는 계층적 관계를 표현하는 자료구조이다
가지를 늘려가며 뻗어나간다
[의사 결정 트리]
단말 노드는 잎사귀 노드(leaf node) 라고도 불리며,
내부 노드는 단말 노드가 아니라고 하여 비단말 노드(noninternal node) 라고도 불린다
Ex)
공집합(empty node)노드는 이진트리의 판단에 있어서 노드로 인정한다
위에서 아래로, 왼쪽에서 오른쪽의 순서대로 채워진다
트리를 표현하기에는 연결 리스트가 더 유연하다
하지만 트리가 완성된 이후 매우 빈번한 탐색이 이루어지는 트리일 경우 배열로 구현한다. 탐색이 매우 용이하고 빠르기 때문이다
#ifndef __BINARY_TREE_H__
#define __BINARY_TREE_H__
typedef int BData;
typedef struct _bTreeNode
{
BTdata data;
struct _bTreeNode * left;
struct _bTreeNode * right;
} BTreeNode;
BTreeNode * MakeBTreeNode(void);
BTData GetData(BTreeNode *bt);
void SetData(BTreeNode *bt, BTData data);
BTreeNode * GetLeftSubTree(BTreeNode * bt);
BTreeNode * GetRightSubTree(BTreeNode * bt);
void MakeLeftSubTree(BTreeNode * main, BTreeNode * sub);
void MakeRightSubTree(BTreeNode * main, BTreeNode * sub);
#endif
BTreeNode * MakeBTreeNode(void);
: 노드의 생성BTData GetData(BTreeNode * bt);
: 노드에 저장된 데이터를 반환void SetData(BTreeNode * bt, BTData data);
: 노드에 데이터를 저장BTreeNode * GetLeftSubTree(BTreeNode * bt);
: 왼쪽 서브 트리 주소 값 반환BTreeNode * GetRightSubTree(BTreeNode * bt);
: 오른쪽 서브 트리 주소 값 반환이진 트리 자료구조의 ADT
BTreeNode * MakeBTreeNode(void);
- 이진 트리 노드를 생성하여 그 주소 값을 반환한다
BTData GetData(BTreeNode * bt);
- 노드에 저장된 데이터를 반환한다
void SetData(BTreeNode * bt, BTData data);
- 노드에 데이터를 저장한다. Data로 전달된 값을 저장한다
BTreeNode * GetLeftSubTree(BTreeNode * bt);
- 왼쪽 서브 트리의 주소 값을 반환한다
BTreeNode * GetRightSubTree(BTreeNode * bt);
- 오른쪽 서브 트리의 주소 값을 반환한다
void MakeLeftSubTree(BTreeNode * main, BTreeNode * sub);
- 왼쪽 서브 트리를 연결한다
void MakeRightSubTree(BTreeNode * main, BTreeNode * sub);
- 오른쪽 서브 트리를 연결한다
#include <stdio.h>
#include <stdlib.h>
#include "BinaryTree.h"
BTreeNode * MakeBTreeNode(void)
{
BTreeNode *nd = (BTreeNode*)malloc(sizeof(BTreeNode));
nd->left = NULL;
nd->right = NULL;
return nd;
}
BTData GetData(BTreeNode * bt)
{
return bt->data;
}
void SetData(BTreeNode * bt, BTData data)
{
bt->data = data;
}
BTreeNode * GetLeftSubTree(BTreeNode * bt)
{
return bt->left;
}
BTreeNode * GetRightSubTree(BTreeNode * bt)
{
return bt->right;
}
void MakeLeftSubTree(BTreeNode * main, BTreeNode * sub)
{
if(main->left != NULL)
free(main->left);
main->left = sub;
}
void MakeRightSubTree(BTreeNode * main, BTreeNode * sub)
{
if(main->right != NULL)
free(main->right);
main->right = sub;
}
void InorderTraverse(BTreeNode * bt) // 이진 트리 전체를 중위 순회하는 함수
{
InorderTraverse(bt->left); // 1단계 왼쪽 서브 트리의 순회
printf(“%d \n”, bt->data); // 2단계 루트 노드의 방문
InorderTraverse(bt->right); // 3단계 오른쪽 서브 트리의 순회
}
재귀의 탈출 조건이 정의되어 있지 않다
노드의 방문이 그저 데이터의 출력이다
재귀의 탈출 조건
void InorderTraverse(BTreeNode * bt) // 이진 트리 전체를 중위 순회하는 함수
{
if(bt == NULL) // bt가 NULL이면 재귀 탈출!
return;
InorderTraverse(bt->left); // 1단계 왼쪽 서브 트리의 순회
printf(“%d \n”, bt->data); // 2단계 루트 노드의 방문
InorderTraverse(bt->right); // 3단계 오른쪽 서브 트리의 순회
}
전위 순회
void PreorderTraverse(BTreeNode * bt)
{
if(bt == NULL)
return;
printf(“%d \n”, bt->data); // 전위 순회이므로 루트 노드 먼저 방문
PreorderTraverse(bt->left);
PreorderTraverse(bt->right);
}
후위 순회
void PostorderTraverse(BTreeNode * bt)
{
if(bt == NULL)
return;
PostorderTraverse(bt->left);
PostorderTraverse(bt->right);
printf(“%d \n”, bt->data); // 후위 순회이므로 루트 노드 나중에 방문!
}
루트 노드에 저장된 연산자의 연산을 하되, 두 개의 자식 노드에 저장된 두 피연산자를 대상으로 연산을 한다
중위 표기법의 수식 -> 후위 표기법의 수식 -> 수식 트리
#ifndef __EXPRESSION_TREE_H__
#define __EXPRESSION_TREE_H__
#include "BinaryTree2.h"
BTreeNode * MakeExpTree(char exp[]); // 수식 트리 구성
int EvaluateExpTree(BTreeNode * bt); // 수식 트리 계산
void ShowPrefixTypeExp(BTreeNode * bt); //전위 표기법 기반 출력
void ShowInfixTypeExp(BTreeNode * bt); // 중위 표기법 기반 출력
void ShowPostfixTypeExp(BTreeNode * bt); //후위 표기법 기반 출력
#endif
후위 표기법
수식트리를 구성하는 방법
BTreeNode * MakeExpTree(char exp[])
{
Stack stack;
BTreeNode * pnode;
int expLen = strlen(exp);
int i;
StackInit(&stack);
for(i = 0; i < expLen; i++)
{
pnode = MakeBTreeNode();
if(isdigit(exp[i])) // 피연산자라면 ...
{
SetData(pnode, exp[i]-'0'); //문자를 정수로 바꿔서 저장
}
else // 연산자라면...
{
MakeRightSubTree(pnode, SPop(&stack));
MakeLeftSubTree(pnode, SPop(&stack));
SetData(pnode, exp[i]);
}
SPush(&stack, pnode);
}
return SPop(&stack);
}
void ShowPrefixTypeExp(BTreeNode * bt) // 전위 표기법의 수식으로
{
PreorderTraverse(bt, ShowNodeData);
}
void ShowInfixTypeExp(BTreeNode * bt) // 중위 표기법의 수식으로
{
InorderTraverse(bt, ShowNodeData);
}
void ShowPostfixTypeExp(BTreeNode * bt) // 후위 표기법의 수식으로
{
PostorderTraverse(bt, ShowNodeData);
}
int EvaluateExpTree(BTreeNode * bt)
{
int op1, op2;
if(GetLeftSubTree(bt) == NULL && GetRightSubTree(bt) == NULL) // 단말 노드라면
return GetData(bt);
op1 = GetData(GetLeftSubTree(bt)); // 첫 번째 피연산자
op2 = GetData(GetRightSubTree(bt)); // 두 번째 피연산자
switch(GetData(bt)) // 연산자를 확인하여 연산을 진행
{
case ‘+’ :
return op1+op2;
case ‘-‘ :
return op1-op2;
case ‘*’ :
return op1*op2;
case ‘/‘ :
return op1/op2;
}
return 0;
}