Upload
dinhminh
View
216
Download
0
Embed Size (px)
Citation preview
이진 트리 순회와 트리 반복자
트리 순회(tree traversal) 트리에 있는 모든 노드를 한 번씩만 방문 순회 방법 : LVR, LRV, VLR, VRL, RVL, RLV
L : 왼쪽 이동, V : 노드방문, R : 오른쪽 이동
왼쪽을 오른쪽보다 먼저 방문(LR) LVR : 중위(inorder) 순회 VLR : 전위(preorder) 순회 LRV : 후위(postorder) 순회
산술식의 이진트리 표현 +
*
/
B
C
A
D
E
*
1
이진 트리 순회와 트리 반복자
=============================================== 1 template <class T> 2 void Tree<T>::Inorder() 3 {// Driver calls workhorse for traversal of entire tree. The driver is 4 // declared as a public member function of Tree. 5 Inorder(root); 6 } 7 template <class T> 8 void Tree<T>::Inorder(TreeNode<T> *currentNode) 9 {// Workhorse traverses the subtree rooted at currentNode. 10 // The workhorse is declared as a private member function of Tree. 11 if (currentNode) { 12 Inorder(currentNode->leftChild); 13 Visit(currentNode); 14 Inorder(currentNode->rightChild); 15 } 16 } ===============================================
2
Inorder traversal (중위 순회)
호출
Driver 1 2 3 4 5 4 6 3 7 8 7 9 2
+ * * / A 0 A 0 / B 0 B 0 *
cout<<‘A’
cout<<‘/’
cout<<‘B’
cout<<‘*’
currentNode의 값 조치 호출
10 11 10 12 1
13 14 13 15
Driver 16 17 16 18
C 0 C 0 * D 0 D 0 + E 0 E 0
cout<<‘C’
cout<<‘*’
cout<<‘D’
cout<<‘+’
cout<<‘E’
currentNode의 값 조치
출력 : A/B*C*D+E
+
*
/
B
C
A
D
E
*
3
Preorder Traversal (전위 순회)
출력 : +**/ABCDE
+
*
/
B
C
A
D
E
*
4
Program 5.2:Preorder traversal of a binary tree =============================================== 1 template <class T> 2 void Tree<T>::Preorder() 3 {// Driver. 4 Preorder(root); 5 } 6 template <class T> 7 void Tree<T>::Preorder(TreeNode<T> *currentNode) 8 {// Workhorse. 9 if (currentNode) { 10 Visit(currentNode); 11 Preorder(currentNode->leftChild); 12 Preorder(currentNode->rightChild); 13 } 14 } ===============================================
Postorder Traversal (전위 순회)
출력 : AB/C*D*E+
+
*
/
B
C
A
D
E
*
5
=============================================== 1 template <class T> 2 void Tree<T>::Postorder() 3 {// Driver. 4 Postorder(root); 5 } 6 template <class T> 7 void Tree<T>::Postorder(TreeNode<T> *currentNode) 8 {// Workhorse. 9 if (currentNode) { 10 Postorder(currentNode->leftChild); 11 Postorder(currentNode->rightChild); 12 Visit(currentNode); 13 } 14 } ===============================================
비순환 중위 순회
=============================================== 1 template <class T> 2 void Tree<T>::NonrecInorder() 3 {// Nonrecursive inorder traversal using a stack. 4 Stack<TreeNode<T>*> s; // declare and initialize stack 5 TreeNode<T> *currentNode = root; 6 while(1) { 7 while (currentNode) { // move down leftChild fields 8 s.Push(currentNode); // add to stack 9 currentNode = currentNode->leftChild; 10 } 11 if (s.IsEmpty()) return; 12 currentNode = s.Top(); 13 s.Pop(); // delete from stack 14 Visit(currentNode); 15 currentNode = currentNode->rightChild; 16 } 17 } ===============================================
6
Level Order Traversal(레벨 순서 순회)
큐 사용
루트 방문->왼쪽 자식 방문->오른쪽 자식 방문
+ * E * D / C A B
template <class T> void Tree<T>::LevelOrder() {//이진 트리의 레벨 순서 순회 Queue<TreeNode<T>*> q; TreeNode<T> * currentNode = root; while(currentNode){ Visit(currentNode); if(currentNode->leftChild) q.Push(currentNode->leftChild); if(currentNode->rightChild) q.Push(currentNode->rightChild); if(q.IsEmpty()) return; currentNode = q.Front(); q.Pop(); } }
+
*
/
B
C
A
D
E
*
7
스택 없는 순회
각 노드에 parent (부모)필드 추가 스택을 사용하지 않아도 루트 노드로 올라갈 수 있음
스레드(thread)이진 트리로 표현 각 노드마다 두 비트 필요 leftChild필드와 rightChild 필드를 루트로 돌아갈 수 있는 경로를 유지하도록 사용
경로 상의 주소 스택은 리프 노드에 저장
A
root
B
E 0 D
0 H 0 0 I 0
C
0 G 0 0 F 0
A
B
D
H I
E
C
F G
root
8
이진트리의 추가 연산
복사 : 프로그램 5.9 동일성 검사 : 프로그램 5.10 재귀 함수로 구현
만족성 문제 변수 x1, x2 , … , xn 과 연산자 ∧, ∨, ¬으로 이루어진 식 변수 = {참, 거짓} 규칙
(1) 변수도 하나의 식 (2) x, y가 식일때, ¬x, x∧y, x∨y 도 식 (3) 연산순서는 ¬, ∧, ∨ 순, 괄호 사용
명제 해석식(formula of propositional calculus) 위 규칙을 이용해서 구성한 식
)( 321 xxx ¬∧∨
9
Program 5.9:Copying a binary tree =============================================== template <class T> Tree<T>::Tree(const Tree<T>& s) // driver {// Copy constructor root = Copy(s.root); } template <class T> TreeNode<T>* Tree<T>::Copy(TreeNode<T> *origNode) // Workhorse {// Return a pointer to an exact copy of the binary tree rooted at origNode. if (!origNode) return 0; else return new TreeNode<T>(origNode->data, Copy(origNode->leftChild), Copy(origNode->rightChild)); } template <class T> Tree<T>::Tree(T data, TreeNode<T> *lChild, TreeNode<T> * rChild) : data(d), leftChild(lChild), rightChild(rChild) { } ===============================================
Program 5.10:Binary tree equivalence =============================================== template <class T> bool Tree<T>::operator==(const Tree& t) const { return Equal(root, t.root); } template <class T> bool Tree<T>::Equal(TreeNode<T> *a, TreeNode<T> *b) {// Workhorse. if ((!a) && (!b)) return true; // both a and b are 0 else return (a && b // both a and b are non-zero && (a->data == b->data) // data is the same && Equal(a->leftChild, b->leftChild) // left subtrees equal && Equal(a->rightChild, b->rightChild)); // right subtrees equal } ===============================================
만족성 문제 (1)
명제식의 만족성(satisfiability) 문제 식의 값이 true가 되도록, 변수에 값을 지정할 수 있는 방법이 있는가?
33121 )()( xxxxx ¬∨∧¬∨¬∧
∨
∨
∧
¬
x3
x1 ¬
∧
¬ x3
x2 x1
12
만족성 문제 (2)
가능한 모든 true와 false의 조합을 대입 : O(g 2n) g : 식을 계산하는데 필요한 시간 전체 식이 하나의 값이 될 때까지 서브 트리를 계산하면서 트리 후위 순회
x1 x2 x3 formular T T T ? T T F ? T F T ? T F F ? F T T ? F T F ? F F T ? F F F ?
13
∨
∨
∧
¬
x3
x1 ¬
∧
¬ x3
x2 x1
∨¬∨∧¬∧¬ 33121 xxxxx
만족성 문제 (3)
후위 순회 계산 Tree 템플릿 클래스를 T=pair<Operator, bool>로 인스턴스화 enum Operator { Not, And, Or, True, False};
for n개 변수에 대한 2n개의 가능한 참값 조합 { 다음 조합을 생성; 그들의 값을 변수에 대입; 명제식을 나타내는 트리를 후위 순회로 계산; if(formula.Data().second()){cout << current combination; return;} } cout <<“no satisfiable combination”;
// visit the node pointed at by p switch (p->data.first) { case Not: p->data.second = !p->rightChild->data.second; break; case And: p->data.second = p->leftChild->data.second && p->rightChild->data.second; break; case Or: p->data.second = p->leftChild->data.second || p->rightChild->data.second; break; case True: p->data.second = true; break; case False: p->data.second = false; } 14
Thread (1)
n 노드 이진 트리의 연결 표현 총 링크의 수 : 2n null 링크의 수 : n+1 > null이 아닌 링크 수 n-1
A
root
B
0 E 0 D
0 H 0 0 I 0
C
0 G 0 0 F 0
15
Thread (2)
스레드(Thread) 0 링크 필드를 다른 노드를 가리키는 포인터로 대치 if p->rightChild == 0,
p->rightChild = p의 중위 후속자에 대한 포인터 if p->leftChild = 0,
p->leftChild = p의 중위 선행자에 대한 포인터
A
B
D
H I
E
C
F G
root
16
순회 : H D I B E A F C G
Thread (3)
노드 구조: leftThread와 rightChild의 tag 필드를 사용 leftThread == false : leftChild ← 포인터
== true : leftChild ← 스레드 rightThread == false : rightChild ← 포인터
== true : rightChild ← 스레드
헤드 노드 연결되지 않은 스레드 제거
leftThread leftChild data rightChild rightThread
TRUE FALSE
17
스레드 이진 트리의 메모리 표현
f - f
f A f
f C f f B f
f D f t E t t F t t G t
t I t t H t
f = false; t = true
root
18
스레드 이진 트리의 중위 순회
스택을 이용하지 않고 중위 순회 가능
중위 순회의 후속자 x->rightThread == true : x->rightChild
== false : 오른쪽 자식의 왼쪽 자식 링크를 따라 가서 LeftThread==true인 노드
스레드 이진 트리에서 중위 후속자를 찾는 함수 T* ThreadedInorderIterator::Next() {//스레드 이진 트리에서 currentNode의 중위 후속자를 반환 ThreadedNode<T> *temp = currentNode->rightChild; if(!currentNode->rightThread) while(!temp->leftThread) temp = temp->leftChild; currentNode = temp; if(currentNode == root) return 0; else return ¤tNode->data; }
19
스레드 이진 트리에서의 노드 삽입
s의 오른쪽 자식으로 r을 삽입
20
21
Program 5.14:Inserting r as the right child of s =============================================== template <class T> void ThreadedTree<T>::InsertRight(ThreadedNode<T> *s, ThreadedNode<T> *r) {// Insert r as the right child of s. r->rightChild = s->rightChild; r->rightThread = s->rightThread; r->leftChild = s; r->leftThread = true; // leftChild is a thread s->rightChild = r; s->rightThread = false; if (! r->rightThread) { ThreadedNode<T> *temp = InorderSucc(r); // returns the inorder successor of r temp->leftChild = r; } } ===============================================