이진트리란 자식 노드를 최개 2개만 가질 수 있는 트리이다.
노드의 개수: n
높이: h
가질 수 있는 노드의 최대 ~ 최소 개수: h+1 ~ 2^(h+1)-1
노드의 번호는 레벨 단위로 왼쪽에서 오른쪽으로 번호를 부여한다.
트리의 각 레벨에 노드가 꽉 차 있는 이진 트리이다.
모든 레벨에서 노드가 왼쪽에서 오른쪽으로 순차적으로 채워져 있는 이진트리이다.
트리의 높이가 h라면 레벨 1부터 h-1까지는 노드가 모두 채워진다.
마지막 레벨 h에서는 노드가 왼쪽->오른쪽 방향으로 순서대로 채워진다.
포화 이진트리는 완전 이진 트리라고 할 수 있다!
BinaryNode 클래스: 노드는 왼쪽 자식 노드를 가리키는 포인터인 left, 오른쪽 자식 노드를 가리키는 포인터인 right, 데이터를 저장하는 data 변수로 구성된다.
BinaryTree 클래스: 루트 노드를 설정한다.
#include <iostream>
using namespace std;
class BinaryNode {
protected:
int data;
BinaryNode* left;
BinaryNode* right;
public:
BinaryNode(int val=0, BinaryNode* l=NULL, BinaryNode* r=NULL): data(val), left(l), right(r) {}
~BinaryNode() {}
void setData(int val){ data = val; }
void setLeft(BinaryNode* l){ left = l; }
void setRight(BinaryNode* r){ right = r; }
int getData() {return data;}
BinaryNode* getLeft(){return left;}
BinaryNode* getRight(){return right;}
bool isLeaf(){ return left==NULL && right==NULL;}
};
class BinaryTree{
BinaryNode* root;
public:
BinaryTree(): root(NULL){}
~BinaryTree() {}
void setRoot(BinaryNode* node){ root=node; }
BinaryNode* getRoot() { return root; }
bool isEmpty() {return root==NULL;}
void display(){
cout << "Binary Tree:" << endl;
if (isEmpty()){
cout<< "Empty Tree." << endl;
}
else
display(root,0);
}
private:
void display(BinaryNode* node , int depth){
if (node==NULL)
return;
for (int i=0; i<depth; i++)
cout<<" ";
cout << "- " << static_cast<char>(node->getData()) << endl;
display(node->getLeft(), depth+1);
display(node->getRight(), depth+1);
}
};
int main(){
BinaryTree tree;
BinaryNode *d = new BinaryNode('D', NULL, NULL);
BinaryNode *e = new BinaryNode('E', NULL, NULL);
BinaryNode *b = new BinaryNode('B', d, e);
BinaryNode *f = new BinaryNode('F', NULL, NULL);
BinaryNode *c = new BinaryNode('C', f, NULL);
BinaryNode *a = new BinaryNode('A', b, c);
tree.setRoot(a);
tree.display();
}
전위순회(preorder traversal)
루트 -> 왼쪽 자식 -> 오른쪽 자식
(1 - 2 - 4 - 5 - 3 - 6)
중위순회(inorder traversal)
왼쪽 자식 -> 루트 -> 오른쪽 자식
(4 - 2 - 5 - 1 - 3 - 6)
후위순회(postorder traversal)
왼쪽 자식 -> 오른쪽 자식 -> 루트
(4 - 5 - 2 - 6 - 3 - 1)
이진 트리 구현 코드의 BinaryTree 클래스에 순회 알고리즘인 inorder, preorder, postorder 메소드를 추가한다.
#include <iostream>
using namespace std;
class BinaryNode {
protected:
int data;
BinaryNode* left;
BinaryNode* right;
public:
BinaryNode(int val=0, BinaryNode* l=NULL, BinaryNode* r=NULL): data(val), left(l), right(r) {}
~BinaryNode() {}
void setData(int val){ data = val; }
void setLeft(BinaryNode* l){ left = l; }
void setRight(BinaryNode* r){ right = r; }
int getData() {return data;}
BinaryNode* getLeft(){return left;}
BinaryNode* getRight(){return right;}
bool isLeaf(){ return left==NULL && right==NULL;}
};
class BinaryTree{
BinaryNode* root;
public:
BinaryTree(): root(NULL){}
~BinaryTree() {}
void setRoot(BinaryNode* node){ root=node; }
BinaryNode* getRoot() { return root; }
bool isEmpty() {return root==NULL;}
void display(){
cout << "Binary Tree:" << endl;
if (isEmpty()){
cout<< "Empty Tree." << endl;
}
else
display(root,0);
}
void inorder(){cout << "\n inorder: "; inorder(root);}
void inorder(BinaryNode *node){
if(node!=NULL){
inorder(node -> getLeft());
cout << "[" << static_cast<char>(node->getData()) << "] ";
inorder(node -> getRight());
}
}
void preorder() {cout << "\n preorder: "; preorder(root);}
void preorder(BinaryNode *node){
if(node!=NULL){
cout << "[" << static_cast<char>(node ->getData()) << "] ";
preorder(node -> getLeft());
preorder(node -> getRight());
}
}
void postorder(){cout << "\n postorder: "; postorder(root);}
void postorder(BinaryNode *node){
if(node!=NULL){
postorder(node -> getLeft());
postorder(node -> getRight());
cout << "[" << static_cast<char>(node -> getData()) << "] ";
}
}
private:
void display(BinaryNode* node , int depth){
if (node==NULL)
return;
for (int i=0; i<depth; i++)
cout<<" ";
cout << "- " << static_cast<char>(node->getData()) << endl;
display(node->getLeft(), depth+1);
display(node->getRight(), depth+1);
}
};
int main(){
BinaryTree tree;
BinaryNode *d = new BinaryNode('D', NULL, NULL);
BinaryNode *e = new BinaryNode('E', NULL, NULL);
BinaryNode *b = new BinaryNode('B', d, e);
BinaryNode *f = new BinaryNode('F', NULL, NULL);
BinaryNode *c = new BinaryNode('C', f, NULL);
BinaryNode *a = new BinaryNode('A', b, c);
tree.setRoot(a);
tree.display();
tree.inorder();
tree.preorder();
tree.postorder();
return 0;
}
큐를 사용하여 구현한다.
큐에서 노드를 하나 꺼내서 방문 처리하고, 방문한 노드의 자식 노드를 큐에 순서대로 삽입하는 방법이다.
트리의 모든 노드를 방문할 때까지 반복한다.
queue.enque(root)
while(!queue.isEmpty()){
x = queue.dequeue() // 큐의 노드를 하나 꺼내 x에 넣어서 방문 처리
//dequeue() 메소드는 큐의 노드를 꺼내서 리턴한다.
if(x != NULL){
print(x)
queue.enqueue(LEFT(x)) // x의 왼쪽 노드를 큐에 삽입
queue.enqueue(RIGHT(x)) // x의 오른쪽 노드를 큐에 삽입
}
}
#include <iostream>
using namespace std;
class BinaryNode {
protected:
int data;
BinaryNode* left;
BinaryNode* right;
public:
BinaryNode(int val=0, BinaryNode* l=NULL, BinaryNode* r=NULL): data(val), left(l), right(r) {}
~BinaryNode() {}
void setData(int val){ data = val; }
void setLeft(BinaryNode* l){ left = l; }
void setRight(BinaryNode* r){ right = r; }
int getData() {return data;}
BinaryNode* getLeft(){return left;}
BinaryNode* getRight(){return right;}
bool isLeaf(){ return left==NULL && right==NULL;}
};
inline void error(char* str){
cerr << str << endl;
exit(1);
};
#define MAX_QUEUE_SIZE 100
class CircularQueue{
int front;
int rear;
BinaryNode* data[MAX_QUEUE_SIZE];
public:
CircularQueue(){
front = rear = 0;
}
~CircularQueue(){ }
bool isEmpty(){return front == rear;}
bool isFull(){return (rear+1) % MAX_QUEUE_SIZE == front;}
void enqueue(BinaryNode* val){
if(isFull()) error("포화상태\n");
else{
rear = (rear + 1) % MAX_QUEUE_SIZE;
data[rear] = val;
}
}
BinaryNode* dequeue(){
if(isEmpty()) error("공백상태\n");
else{
front = (front +1) % MAX_QUEUE_SIZE;
return data[front];
}
}
};
class BinaryTree{
BinaryNode* root;
public:
BinaryTree(): root(NULL){}
~BinaryTree() {}
void setRoot(BinaryNode* node){ root=node; }
BinaryNode* getRoot() { return root; }
bool isEmpty() {return root==NULL;}
void display(){
cout << "Binary Tree:" << endl;
if (isEmpty()){
cout<< "Empty Tree." << endl;
}
else
display(root,0);
}
void inorder(){
cout << "\n inorder: ";
inorder(root);
}
void inorder(BinaryNode *node){
if(node!=NULL){
inorder(node -> getLeft());
cout << "[" << static_cast<char>(node->getData()) << "] ";
inorder(node -> getRight());
}
}
void preorder() {
cout << "\n preorder: ";
preorder(root);
}
void preorder(BinaryNode *node){
if(node!=NULL){
cout << "[" << static_cast<char>(node ->getData()) << "] ";
preorder(node -> getLeft());
preorder(node -> getRight());
}
}
void postorder(){
cout << "\n postorder: ";
postorder(root);
}
void postorder(BinaryNode *node){
if(node!=NULL){
postorder(node -> getLeft());
postorder(node -> getRight());
cout << "[" << static_cast<char>(node -> getData()) << "] ";
}
}
void levelorder(){
cout << "\nlevelorder: ";
if(!isEmpty()){
CircularQueue q;
q.enqueue(root);
while(!q.isEmpty()){
BinaryNode* n = q.dequeue();
if(n!=NULL){
cout << "["<<static_cast<char>(n->getData()) << "] ";
q.enqueue(n->getLeft());
q.enqueue(n->getRight());
}
}
}
cout<<"\n";
}
private:
void display(BinaryNode* node , int depth){
if (node==NULL)
return;
for (int i=0; i<depth; i++)
cout<<" ";
cout << "- " << static_cast<char>(node->getData()) << endl;
display(node->getLeft(), depth+1);
display(node->getRight(), depth+1);
}
};
int main(){
BinaryTree tree;
BinaryNode *d = new BinaryNode('D', NULL, NULL);
BinaryNode *e = new BinaryNode('E', NULL, NULL);
BinaryNode *b = new BinaryNode('B', d, e);
BinaryNode *f = new BinaryNode('F', NULL, NULL);
BinaryNode *c = new BinaryNode('C', f, NULL);
BinaryNode *a = new BinaryNode('A', b, c);
tree.setRoot(a);
tree.display();
tree.inorder();
tree.preorder();
tree.postorder();
tree.levelorder();
return 0;
}