1. 개요
이진 트리는 비선형 자료구조의 일종인데, 하나의 부모 노드에 두 개의 자식 노드가 연결된 형태의 트리(tree)이다. 일단 트리가 뭔지 살펴보고, 이진 트리가 어떤 장점이 있는지를 살펴보자. 그리고 이진 트리를 만들면서 동시에 이진 트리와 스택(stack)을 이용한 간단한 계산기를 구현해보자.2. 이진 트리를 왜 쓰는가
우선 트리는 그래프의 일종인데, 회로가 없고 서로 다른 두 노드를 잇는 길이 하나만 존재한다. 최상위 노드는 루트 노드라고 하며, 직접 연결된 상위 노드를 부모 노드, 하위 노드를 자식 노드라고 한다.한 부모 노드에 두 개의 자식 노드만 연결된 트리를 이진 트리라고 부른다. 그런데 자식 노드에는 또 다시 다른 자식 노드들이 있을 수 있다. 자식 노드가 없는 노드도 있을텐데 그런 노드를 말단 노드 혹은 잎 노드(leaf node)라고 부른다.
자식 노드가 또 자식 노드를 가지는 특성 때문에 이진 트리는 재귀적으로 구현한다. 아래의 코드를 보면 재귀적이다.
3. 데이터의 저장과 삭제
이진 트리에 데이터를 저장하고 삭제하는 것은4. 이진 트리의 순회
데이터를 저장하고 또 삭제했으니, 이진 트리에 있는 데이터를 탐색해보자. 트리의 데이터들을 한번 쭉 보려면 이 트리를 순회해야 하는데, 그 방법은 세 가지가 있다. 전위 순회(Preorder), 중위 순회(Inorder), 후위 순회(Postorder) 세 가지인데, 각각은 루트 노드를 언제 방문하느냐가 다르다. 전위는 처음, 중위는 중간, 후위는 마지막이다.이걸 이용해서 간단한 계산기를 만들 수 있다. 구현 연습용으로 좋은 것 같다. 윤성우의 <열혈 자료구조>에 소개된 내용이다.
윤성우 책의 예시에는 이진트리 헤더/실행 파일과 스택 헤더/실행 파일, 그리고 이진트리를 이용한 수식계산 헤더/실행 파일 + 메인파일까지 해서 파일이 7개나 된다. 너무 많아서 귀찮지만 한번 복붙해본다.
C 소스코드
1. 이진트리 헤더파일
#ifndef __BINARY_TREE_H__
#define __BINARY_TREE_H__
typedef int Data;
typedef struct _Node{
Data data;
struct _Node* left;
struct _Node* right;
} Node;
Node* createNode(void);
Data getData(Node* bt);
void setData(Node* bt, Data data);
Node* getLeftSub(Node* bt);
Node* getRightSub(Node* bt);
void makeLeftSub(Node* mainbt, Node* subbt);
void makeRightSub(Node* mainbt, Node* subbt);
typedef void Visit(int data);
void PreorderTraverse(Node* bt, Visit act);
void InorderTraverse(Node* bt, Visit act);
void PostorderTraverse(Node* bt, Visit act);
void deleteTree(Node* bt);
#endif
| cs |
#include <stdio.h>
#include <stdlib.h>
#include "BinaryTree.h"
Node* createNode(void){
Node* node = (Node*)malloc(sizeof(Node));
node->left = NULL;
node->right = NULL;
return node;
}
Data getData(Node* bt){
return bt->data;
}
void setData(Node* bt, Data data){
bt->data = data;
}
Node* getLeftSub(Node* bt){
return bt->left;
}
Node* getRightSub(Node* bt){
return bt->right;
}
void makeLeftSub(Node* mainbt, Node* subbt){
if(mainbt->left != NULL){
free(mainbt->left);
}
mainbt->left = subbt;
}
void makeRightSub(Node* mainbt,Node* subbt){
if(mainbt->right != NULL){
free(mainbt->right);
}
mainbt->right = subbt;
}
void PreorderTraverse(Node* bt, Visit act){
if(bt == NULL)
return;
act(bt->data);
PreorderTraverse(bt->left, act);
PreorderTraverse(bt->right, act);
}
void InorderTraverse(Node* bt, Visit act){
if(bt == NULL)
return;
InorderTraverse(bt->left, act);
act(bt->data);
InorderTraverse(bt->right, act);
}
void PostorderTraverse(Node* bt, Visit act){
if(bt == NULL)
return;
PostorderTraverse(bt->left, act);
PostorderTraverse(bt->right, act);
act(bt->data);
}
void deleteTree(Node* bt){
if(bt == NULL)
return;
deleteTree(bt->left);
deleteTree(bt->right);
printf("%d를 담은 노드 삭제\n", bt->data);
free(bt);
}
| cs |
위의 두 코드는 이진트리의 헤더 및 실행파일이다.
3. 스택 헤더파일
#ifndef __STACK_H__
#define __STACK_H__
#define TRUE 1
#define FALSE 0
#include "BinaryTree.h"
typedef Node* NodeData;
typedef struct _StackNode{
NodeData data;
struct _StackNode* next;
} StackNode;
typedef struct _Stack{
StackNode* head;
} Stack;
void StackInit(Stack* pstack);
int StackIsEmpty(Stack* pstack);
void StackPush(Stack* pstack, NodeData data);
NodeData StackPop(Stack* pstack);
NodeData StackPeek(Stack* pstack);
#endif
| cs |
4. 스택 실행파일
#include <stdio.h>
#include <stdlib.h>
#include "Stack.h"
void StackInit(Stack* pstack){
pstack->head = NULL;
}
int StackIsEmpty(Stack* pstack){
if(pstack->head == NULL)
return TRUE;
else
return FALSE;
}
void StackPush(Stack* pstack, NodeData data){
StackNode* newNode = (StackNode*)malloc(sizeof(StackNode));
newNode->data = data;
newNode->next = pstack->head;
pstack->head = newNode;
}
NodeData StackPop(Stack* pstack){
NodeData popdata;
StackNode* popnode;
if(StackIsEmpty(pstack)){
printf("스택이 텅 빔");
exit(-1);
}
popdata = pstack->head->data;
popnode = pstack->head;
pstack->head = pstack->head->next;
free(popnode);
return popdata;
}
NodeData StackPeek(Stack* pstack){
StackNode* popnode;
if(StackIsEmpty(pstack)){
printf("스택이 텅 빔");
exit(-1);
}
return pstack->head->data;
}
| cs |
5. 수식트리 헤더파일
#include <stdio.h>
#include <stdlib.h>
#include "ExpressionTree.h"
int main(void){
char exp[] = "12+7*";
Node* expTree = createExpTree(exp);
printf("prefix : ");
ShowPrefixExp(expTree);
printf("\n");
printf("infix : ");
ShowInfixExp(expTree);
printf("\n");
printf("postfix : ");
ShowPostfixExp(expTree);
printf("\n");
printf("result : %d\n", EvaluateExpTree(expTree));
return 0;
}
| cs |
6. 수식트리 실행파일
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "BinaryTree.h"
#include "Stack.h"
Node* createExpTree(char exp[]){
Stack stack;
Node* pnode;
int expLen = strlen(exp);
int i;
StackInit(&stack);
for(i=0; i<expLen; i++){
pnode = createNode();
if(isdigit(exp[i])){
setData(pnode, exp[i] - '0');
}
else{
makeRightSub(pnode, StackPop(&stack));
makeLeftSub(pnode, StackPop(&stack));
setData(pnode, exp[i]);
}
StackPush(&stack, pnode);
}
return StackPop(&stack);
}
int EvaluateExpTree(Node* bt){
int op1, op2;
if(getLeftSub(bt) == NULL && getRightSub(bt) == NULL)
return getData(bt);
op1 = EvaluateExpTree(getLeftSub(bt));
op2 = EvaluateExpTree(getRightSub(bt));
if(op2 == 0){
switch(getData(bt)){
case '+':
return op1 + op2;
case '-':
return op1 - op2;
case '*':
return op1 * op2;
case '/':
printf("ERROR - divide by 0\n");
exit(-1);
}
}
else{
switch(getData(bt)){
case '+':
return op1 + op2;
case '-':
return op1 - op2;
case '*':
return op1 * op2;
case '/':
return op1 / op2;
}
}
return 0;
}
void ShowNodeData(int data){
if(0<=data && data<=9)
printf("%d ", data);
else
printf("%c ", data);
}
void ShowPrefixExp(Node* bt){
PreorderTraverse(bt, ShowNodeData);
}
void ShowInfixExp(Node* bt){
InorderTraverse(bt, ShowNodeData);
}
void ShowPostfixExp(Node* bt){
PostorderTraverse(bt, ShowNodeData);
}
| cs |
7. 수식트리 메인함수 있는 파일
//postfix calculator using Binary Tree
#include <stdio.h>
#include <stdlib.h>
#include "ExpressionTree.h"
int main(void){
char exp[] = "12+7*";
Node* expTree = createExpTree(exp);
printf("prefix : ");
ShowPrefixExp(expTree);
printf("\n");
printf("infix : ");
ShowInfixExp(expTree);
printf("\n");
printf("postfix : ");
ShowPostfixExp(expTree);
printf("\n");
printf("result : %d\n", EvaluateExpTree(expTree));
return 0;
}
| cs |
참고
윤성우.(2012).열혈 자료구조.오렌지미디어
댓글 없음:
댓글 쓰기