1 / 92

자료구조

자료구조. 제 5 장 트리. 5.1 서론. 5.1 서론. ▶ 트리 트리 : 하나이상의 노드 (node) 로 이루어진 유한집합 . ① 하나의 루트 노드 (root node) ② 나머지 노드들은 n( ≥ 0) 개의 분리 집합 (disjoint set) T 1 , T 2 , … , T n 으로 분할 (T i : 서브트리 ) • 노드의 차수 (degree) : 노드의 서브트리 수 • 단말 (terminal) 노드 : 차수 = 0, leaf • 비단말 노드 : 차수  0

amina
Download Presentation

자료구조

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 자료구조 제 5 장 트리

  2. 5.1 서론

  3. 5.1 서론 • ▶ 트리 • 트리 : 하나이상의 노드(node)로 이루어진 유한집합. • ① 하나의 루트 노드 (root node) • ② 나머지 노드들은 n(≥0)개의 분리 집합(disjoint set) T1, T2,…, Tn으로 분할 (Ti : 서브트리) • •노드의 차수(degree) : 노드의 서브트리 수 • •단말(terminal) 노드 : 차수 = 0, leaf • •비단말 노드 : 차수 0 • •노드 레벨 : 루트-레벨1 • •트리의 차수 = max노드의 차수 • •자손(child), 형제(sibling) • •선조(ancestor) : 루트까지의 경로상에 있는 모든 노드 • •자손(descendants) : 한 노드의 서브트리에 • 존재하는 모든 노드 • •트리의 높이 (height, depth) = max노드 레벨

  4. 5.1 서론 • ancestor of M = { H, D, A } • descendentorof D = { H, I, J, M }

  5. 5.1 서론 • ▶ 트리 표현 • 트리 : (A(B(E(K,L),F),C(G),D(H(M),I,J))) • - 리스트 표현 : 차수가 k인 트리의 노드 구조 • - 보조정리 5.1 • T의 차수 : k, 노드수 : n 일때 nk개의 자식필드중 • n(k-1)+1개의 필드(n≥1)가 0이다.

  6. 5.1 서론 • 왼쪽자식-오른쪽 형제 표현 그림 5.6 : 그림 5.2 트리의 왼쪽자식-오른쪽 형제 표현

  7. 5.1 서론 • - 차수가 2인 트리표현 : 이진 트리(binary tree) • 오른쪽형제 포인터를 • 45° 시계방향으로 • 회전 : 이진 트리 • 그림 5.7: 그림 5.2 트리의 왼쪽자식-오른쪽자식 표현

  8. 5.1 서론 • 그림 5.8 트리표현

  9. 5.2 이진 트리(Binary tree)

  10. 5.2 이진 트리(Binary tree) • ▶ 추상 데이타 타입 • [정의] 노드의 유한 집합 • - 공백 • - 루트와 두개의 분리된 이진 트리 • (왼쪽 서브트리, 오른쪽 서브트리)

  11. 5.2 이진 트리(Binary tree) • ----------------------------------------- • template <class KeyType> • class BinaryTree{ • // objects: 공백이거나 루트 노드, 왼쪽 이진 트리, 오른쪽 • //이진 트리로 구성되는 노드들의 유한집합 • public: • BinaryTree();// 공백 이진 트리를 생성 • Boolean IsEmpty(); • // 이진 트리가 공백이면 TRUE(1) 반환; 그렇지 않으면 • // FALSE(0) 반환 • BinaryTree(BinaryTreebt1, Element<KeyType> item, • BinaryTreebt2);// 왼쪽 서브트리가 bt1, 오른쪽 서브트 • //리가 bt2, 루트 노드가 item을 갖는 이진트리를 생성 • BinaryTreeLchild(); • // IsEmpty()이면 에러 반환; 그렇지 않으면 *this의 왼쪽 • //서브트리 반환 • Element<KeyType> Data(); • // IsEmpty()이면 에러 반환; 그렇지 않으면 *this의 루트 • //노드의 데이타 반환 • BinaryTreeRchild(); • // IsEmpty()이면 에러 반환; 그렇지 않으면 *this의 오른 • //쪽 서브트리 반환 • }; • ----------------------------------------- • ADT5.1: 추상 데이타 타입 BinaryTree

  12. 5.2 이진 트리(Binary tree) • - 이진 트리와 일반 트리의 차이점 • •공백 이진 트리 존재 • •서브트리의 순서 중요 • 그림 5.9: 서로 다른 두 이진 트리 • 그림 5.10 : 편향 트리와 완전 이진 트리 • * 트리는 모두 2진 트리로 표현 가능

  13. 5.2 이진 트리(Binary tree) • ▶ 이진 트리의 특성 • - 보조정리 5.2[최대 노드수] • ⑴ 레벨 i에서의 최대 노드수 : 2i-1(i  1) • ⑵ 깊이가 k인 이진 트리가 가질수 있는 최대 노드수 • : 2k - 1(k  1) • - 보조정리 5.3 • [단말노드 수와 차수가 2인 노드 수와의 상관관계] • 공백이 아닌 모든 이진 트리 T에 대하여, • n0 : 단말 노드수 • n2 : 차수가 2인 노드 수 • n0 = n2 + 1 • ∵ n : 전체 노드수, B :전체 간선수(n1+2n2) • n1 : 차수가 1인 노드수 • n = n0 + n1+ n2 • - n = B + 1 = n1 + 2n2 +1 • ---------------------------- • n0 = n2 + 1

  14. 5.2 이진 트리(Binary tree) • - 포화 이진 트리(full binary tree) • •깊이가 K이고 • •노드수가 2K-1 인 이진 트리 • •노드 번호 1, ··· , 2k-1 까지 순차적 부여 가능 • 그림 5.11: 순차적 노드 번호를 붙인 깊이 4의 포화 이진 트리

  15. 5.2 이진 트리(Binary tree) • - 완전 이진 트리(Complete binary tree) • •이진 트리 (n 노드, 깊이 k) • •각 노드는 깊이가 k인 포화 이진 트리의 노드 번호 1부터 n까지 순차적으로 대응 • n 노드 완전 이진 트리의 높이 : log2(n+1)

  16. 5.2 이진 트리(Binary tree) • - 보조정리 5.4 • 완전이진트리(n), i: 노드번호, 트리깊이= log2(n+1) • ① PARENT(i) :i/2 if i 1 • ② LCHILD(i) : 2i if 2i n • otherwise no left child • ③ RCHILD(i) : 2i+1 if 2i+1 n • otherwise no right child

  17. 5.2 이진 트리(Binary tree) • ▶ 이진 트리의 표현 방법 • - 이진 트리의 배열 표현 • ① 완전 이진 트리 : 낭비 공간 없음 • ② 편향 이진 트리(깊이 k) : 2k-1중 k만 사용(최악의 경우)

  18. 5.2 이진 트리(Binary tree) • - 링크 표현 • 그림 5.13 : 노드 표현 • class Tree; //전방 선언 • class TreeNode { • friend class Tree; • private: • TreeNode*LeftChild; • char data; • TreeNode*RightChild; • }; • class Tree { • public: • // 트리 연산들 • ... • private: • TreeNode*root; • };

  19. 5.2 이진 트리(Binary tree) • 그림 5.14 : 그림 5.10의 이진 트리에 대한 링크 표현

  20. 5.3 이진 트리의 순회와 트리 반복자 • - 완전한 순회는 노드의 선형 순서를 생성. • L : 왼쪽 이동 • D : 노드방문(데이타 출력) • R : 오른쪽 이동 • •순회 방법 : LDR, LRD, DLR, DRL, RDL, RLD • •왼쪽을 오른쪽보다 먼저 방문(LR) • LDR(inorder) : infix • DLR(preorder) : prefix • LRD(postorder) : postfix • note : "Data"의 위치 • •산술식의 이진트리 표현 • 그림 5.16

  21. 5.3 이진 트리의 순회와 트리 반복자 • ▶ 중위 순회(Inordertraversal) • LDR • ① 왼쪽 서브트리 순회 • ② 루트 방문 (print root) • ③ 오른쪽 서브트리 순회 • ----------------------------------------- • 1 void Tree::inorder() • 2 // 전체 트리를 순회하는 Driver는 Workhorse를 호출하며 • 3 // Driver는 Tree 클래스의 공용 멤버 함수로 선언됨. • 4 { • 5 inorder(root); • 6 } • 7 void Tree::inorder(TreeNode*CurrentNode) • 8 // Workhorse는 이진 트리의 한 노드에 대한 포인터인 • 9 //CurrentNode가 루트인 서브 트리를 순회함. • //이 Workhorse는 Tree 클래스의 전용 멤버 함수로 선언 • 10 { • 11 if (CurrentNode) { • 12 inorder(CurrentNode->LeftChild); • 13 cout<< CurrentNode->data; • 14 inorder(CurrentNode->RightChild); • 15 } • 16 } • ----------------------------------------- • 프로그램 5.1: 이진 트리의 중위 순회

  22. 5.3 이진 트리의 순회와 트리 반복자 •  Output : A/B*C*D+E (수식의 중위 표기)

  23. 5.3 이진 트리의 순회와 트리 반복자 • ▶ 전위 순회(Preorder traversal) • DLR • ① 루트 방문 • ② 왼쪽 서브트리 순회 • ③ 오른쪽 서브트리 순회 • ----------------------------------------- • 1 void Tree::preorder() • 2 // 전체 트리를 순회하는 Driver는 Workhorse를 호출하며 • 3 // Driver는 Tree 클래스의 공용 멤버 함수로 선언됨. • 4 { • 5 preorder(root); • 6 } • 7 void Tree::preorder(TreeNode*CurrentNode) { • 8 // Workhorse는 CurrentNode(이진 트리의 한 노드에 대한 • 9 // 포인터)를 루트로하는 서브 트리를 순회한다. 이 • 10 // Workhorse는 Tree 클래스의 전용 멤버 함수로 선언됨. • 11 if (CurrentNode) { • 12 cout<< CurrentNode->data; • 13 preorder(CurrentNode->LeftChild); • 14 preorder(CurrentNode->RightChild); • 15 } • 16 } • ----------------------------------------- • 프로그램 5.2: 이진 트리의 전위 순회 • Output : +**/ABCDE(수식의 전위 표기)

  24. 5.3 이진 트리의 순회와 트리 반복자 • ▶ 후위 순회(Postorder traversal) • LRD • ① 왼쪽 서브트리 순회 • ② 오른쪽 서브트리 순회 • ③ 루트 방문 • ----------------------------------------- • 1 void Tree::postorder() • 2 // 전체 트리를 순회하는 Driver는 Workhorse를 호출하며 • 3 // Driver는 Tree 클래스의 공용 멤버 함수로 선언됨. • 4 { • 5 postorder(root); • 6 } • 7 void Tree::postorder(TreeNode*CurrentNode) • 8 // Workhorse는 CurrentNode(이진 트리의 한 노드에 대한 • 9 // 포인터)를루트로 하는 서브 트리를 순회한다. 이 • 10 // Workhorse는 Tree 클래스의 전용 멤버 함수로 선언됨. • 11 if (CurrentNode) { • 12 postorder(CurrentNode->LeftChild); • 13 postorder(CurrentNode->RightChild); • 14 cout<< CurrentNode->data; • 15 } • 16 } • ----------------------------------------- • 프로그램 5.3: 이진 트리의 후위 순회 •  Output : AB/C*D*E+ (수식의 후위 표기)

  25. 5.3 이진 트리의 순회와 트리 반복자 • ▶ 반복적 중위 순회 • •스택을 사용 • •링크로 표현된 이진 트리 • •알고리즘의 작성 방법 • ① recursive method • ~ an internal stack • ② non-recursive method • ~ an extenalstack • ③ non-recursive stacklessmethod • ~ parent field • ④ nonrecursivestacklessmethod • ~ thread, no parent field • ⑤ nonrecursivestacklessmethod • ~ unthreaded, no parent field

  26. 5.3 이진 트리의 순회와 트리 반복자 • 반복적 중위 순회 • recursive ------> iterative • ↑ • stack-based • ----------------------------------------- • 1 void Tree::NonrecInorder() • 2 // 스택을 이용한 비순환적 트리 순회 • 3 { • 4 Stack<TreeNode*> s; // 스택의 선언과 초기화 • 5 TreeNode*CurrentNode= root; • 6 while(1) { • 7 while(CurrentNode) { // 왼쪽 자식 필드로 이동 • 8 s.add(CurrentNode); // 스택에 삽입 • 9 CurrentNode= CurrentNode->LeftChild; • 10 } • 11 if (!s.IsEmpty()) { //* 스택이 공백이 아님 • 12 CurrentNode= *s.Delete(CurrentNode); // 스택에서 //의 삭제 • 13 cout<< CurrentNode->data << endl; • 14 CurrentNode= CurrentNode->RightChild; • 15 } • 16 else break; • 17 } • 18 } • ----------------------------------------- • 프로그램 5.4: 비순환적 중위 순회

  27. 5.3 이진 트리의 순회와 트리 반복자 • ----------------------------------------- • class InorderIterator { • public: • char *Next(); • InorderIterator(Tree tree) : t(tree) { • CurrentNode= t.root; • }; • private: • Tree t; • Stack <TreeNode*> s; • TreeNode*CurrentNode; • }; • ----------------------------------------- • 프로그램 5.5: 중위 반복자 클래스의 정의

  28. 5.3 이진 트리의 순회와 트리 반복자 • ----------------------------------------- • char *InorderIterator::Next() • { • while(CurrentNode) { • s.add(CurrentNode); • CurrentNode= CurrentNode->LeftChild; • } • if (!s.IsEmpty()) { • CurrentNode= *s.Delete(CurrentNode); • char &temp = CurrentNode->data; • CurrentNode= CurrentNode->RightChild; • //CurrentNode를 수정 • return &temp; • } • else return 0; // 트리가 순회되었고 더 이상 원소 없음 • } • ----------------------------------------- • 프로그램 5.6: 다음 중위 원소를 가져오는 코드

  29. 5.3 이진 트리의 순회와 트리 반복자 • ▶ 레벨 순서 순회 • •큐를 사용. • 그림 5.16을 레벨 순회한 결과 : +*E*D/CAB • ----------------------------------------- • void Tree::LevelOrder() • // 이진 트리의 레벨 순서 순회 • { • QUEUE<TreeNode*> q; • TreeNode*CurrentNode= root; • while(CurrentNode) { • cout<<CurrentNode->data<<endl; • if (CurrentNode->LeftChild) • q.add(CurrentNode->LeftChild); • if (CurrentNode->RightChild) • q.add(CurrentNode->RightChild); • CurrentNode= *q.Delete(CurrentNode); • } • } • ----------------------------------------- • 프로그램 5.7: 이진 트리의 레벨 순서 순회

  30. 5.3 이진 트리의 순회와 트리 반복자 • ▶ 스택없는 순회 • - 각 노드에 parent 필드 추가. • - 각 노드에 두 비트가 필요. • 이진 트리를 스레드(thread)이진 트리로 표현.

  31. 5.4 이진 트리의 추가 연산

  32. 5.4 이진 트리의 추가 연산 • ▶ 이진 트리의 복사 • ----------------------------------------- • // 복사 생성자(copy constructor) • Tree::Tree(constTree &s) // Driver • { • root = copy(s.root); • } • TreeNode*Tree::copy(TreeNode*orignode) // Workhorse • // 이 함수는 루트가 orignode인 트리를 복사하여 복사된 트 • // 리의 포인터를 반환한다. • { • if (orignode) { • TreeNode*temp = new TreeNode; • temp->data = orignode->data; • temp->LeftChild= copy(orignode->LeftChild); • temp->RightChild= copy(orignode->RightChild); • return temp; • } • else return 0; • } • ----------------------------------------- • 프로그램 5.9: 이진 트리의 복사

  33. 5.4 이진 트리의 추가 연산 • ▶ 이진 트리의 동일성 • - 동일한 구조 • - 동일한 정보 • ----------------------------------------- • // Driver - Tree 클래스의 friend로 가정. • int operator==(constTree& s, Tree& t) • { • return equal(s.root, t.root); • } • // Workhorse - TreeNode클래스의 friend로 가정. • int equal(TreeNode*a, TreeNode*b) • // 이 함수는 a와 b의 서브트리들이 동일하지 않으면 0을, 동일하면 1을 반환한다. • { • if ((!a) && (!b)) return 1; // a, b 둘다 0 • if (a && b && (a->data == b->data) // data가 같다 • && equal(a->LeftChild, b->LeftChild) // 왼쪽 서브트리 //가 같다 • && equal(a->RightChild, b->RightChild)) //오른쪽 서브 • //트리가 같다 • return 1; • return 0; • } • ----------------------------------------- • 프로그램 5.10: 이진 트리 동일성

  34. 5.4 이진 트리의 추가 연산 • ▶ 만족성 문제 • 명제 해석(propositional calculus) • - 불리언 변수 x1, x2, ...., xn 과 연산자 ∧,∨,¬로 이루어진식 • - { T, F } 로 사상 • ⑴ 변수 자체도 하나의 식 • ⑵ x,y가 식 일때, ¬x, x∧y, x∨y 도 식 • ⑶ 연산순서는 ¬,∧,∨.

  35. 5.4 이진 트리의 추가 연산 • (x1∧¬x2)∨(¬x1∧x3)∨¬x3 • 그림 5.18 : 이진 트리로 표현된 명제식 • - 중위순회 : x1∧¬x2∨¬x1∧x3∨¬x3 • x1 x2 x3 formula • T T T ? • T T F ? evaluation : • T F T ? postorder traversal • T F F ? • . • :

  36. 5.4 이진 트리의 추가 연산 • - 후위 순회 계산 • data : boolean variable or boolean operator • value : T, F

  37. 5.4 이진 트리의 추가 연산 • enumBoolean {FALSE, TRUE}; • enumTypesOfData {LogicalNot, LogicalAnd, LogicalOr, • LogicalTrue, LogicalFalse}; • class SatTree; // 전방 선언 • class SatNode { • friend class SatTree; • private: • SatNode*LeftChild; • TypesOfDatadata; • Boolean value; • SatNode*RightChild; • }; • class SatTree { • public • void PostOrderEval(): • void rootvalue() { cout<< root->value;} ; • private: • SatNode*root; • void PostOrderEval(SatNode*); • };

  38. 5.4 이진 트리의 추가 연산 • ----------------------------------------- • for n변수에 대한 2n개의 가능한 참값 조합 • { • 다음 조합을 생성; • 그들의 값을 변수에 대입; • 명제식을 나타내는 트리를 후위 순회로 계산; • if (formula.rootvalue()) { cout<< combination; return; } • } • cout<< "no satisfiablecombination"; • ----------------------------------------- • 프로그램 5.11: 만족성 알고리즘의 첫번째 버전

  39. 5.4 이진 트리의 추가 연산 • ----------------------------------------- • void SatTree::PostOrderEval() // Driver • { PostOrderEval(root); } • void SatTree::PostOrderEval(SatNode*s) // Workhorse • { • if (s) { • PostOrderEval(s->LeftChild); • PostOrderEval(s->RightChild); • switch(s->data) { • case LogicalNot: s->value = !s->RightChild->value; break; • case LogicalAnd: s->value = • s->RightChild->value && s->LeftChild->value; • break; • case LogicalOr: • s->value = s->RightChild->value || • s->LeftChild->value; • break; • case LogicalTrue: s->value = TRUE; break; • case LogicalFalse: s->value = FALSE; • } • } • } • ----------------------------------------- • 프로그램 5.12: 명제식의 계산

  40. 5.5 스레드 이진 트리

  41. 5.5 스레드 이진 트리 • ▶스레드 • •n 노드 이진 트리의 연결 표현 • - 총 링크 필드의 수 : 2n • - 널 링크 필드의 수 : n+1 • 널 링크 수 > 실제 포인터 수 • •스레드(Thread) • - 널 링크 필드에 삽입된 포인터(널 필드의 활용) • ① P->RightChild= 0  • P->RightChild: 중위순회시 P의 successor에 • 대한 포인터 • ② P->LeftChild= 0  • P->LeftChild: 중위순회시 P의 predecessor에 • 대한 포인터

  42. 5.5 스레드 이진 트리 • - 중위 순회 • H D I B E A F C G

  43. 5.5 스레드 이진 트리 • - 스레드 이진 트리의 표현 • LeftThread== F : LeftChild←pointer • == T : LeftChild←thread • RightThread== F : RightChild←pointer • == T : RightChild←thread • dangling 포인터 문제 → 헤드 노드 • 공백 이진 트리 : 헤드 노드

  44. - 스레드 이진 트리를 위한 클래스 정의 • ----------------------------------------- • class ThreadedNode { • friend class ThreadedTree; • friend class ThreadedInorderIterator; • private: • Boolean LeftThread; • ThreadedNode*LeftChild; • char data; • ThreadedNode*RightChild; • Boolean RightThread; • }; • class ThreadedTree { • friend class ThreadedInorderIterator; • public: • : // 트리 조작 연산들 • private: • ThreadedNode*root; • }; • class ThreadedInorderIterator { • public: • char *Next(); • ThreadedInorderIterator(ThreadedTreetree):t(tree) • CurrentNode= t.root; ; • private: • ThreadedTreet; • ThreadedNode*CurrentNode; • }; • -----------------------------------------

  45. 5.5 스레드 이진 트리 • - 스레드 이진 트리의 메모리 표현 • 주의 : 헤드 노드의 왼쪽 서브트리

  46. 5.5 스레드 이진 트리 • ▶ 스레드 이진 트리의 중위 순회 • •스택을 이용하지 않고 순회 • •중위 순회의 후속자 • RightThread == T : RightChild • == F : 오른쪽 자식의 왼쪽 자식 링크를 따라 • LeftThread == TRUE인 노드 • - 스레드 이진 트리에서 중위 후속자를 찾는 함수 • ----------------------------------------- • char *ThreadedInorderIterator::Next() { • // 스레드 이진 트리에서 CurrentNode의 중위 후속자를 찾는다 • ThreadedNode *temp = CurrentNode->RightChild; • if (!CurrentNode->RightThread) • while (!temp->LeftThread) temp = temp->LeftChild; • CurrentNode = temp; • if (CurrentNode==t.root) return 0; • else return &CurrentNode->data; • } • ----------------------------------------- • - 스레드 이진 트리의 중위 순회 • ----------------------------------------- • void ThreadedInorderIterator::Inorder() { • for (char *ch=Next(); ch; ch = Next()) cout<< *ch << endl; • } • -----------------------------------------

  47. 5.5 스레드 이진 트리 • ▶ 스레드 이진 트리에서의 노드 삽입 • - s의 오른쪽 자식으로 r을 삽입

  48. 5.5 스레드 이진 트리 • - s의 오른쪽 자식으로 r을 삽입 • ----------------------------------------- • void ThreadTree::InsertRight(ThreadedNode *s, • ThreadedNode *r) • // 스레드 이진 트리에서 r을 s의 오른쪽 자식으로 삽입 • { • r->RightChild = s->RightChild; • r->RightThread = s->RightThread; • r->LeftChild = s; • r->LeftThread = TRUE; // 왼쪽 자식은 스레드 • s->RightChild = r; // r을 s에 연결 • s->RightThread = FALSE; • if (!r->RightThread) { • ThreadedNode *temp = InorderSucc(r); • // r의 중위 후속자를 반환 • temp->LeftChild = r; • } • } • -----------------------------------------

  49. 5.6 히프(heap)

  50. 5.6 히프(heap) • ▶ 우선 순위 큐 • •완전 이진 트리의 응용 • •히프(heap):우선 순위 큐(priorty queue)를 구현하는 방법 • •서비스 순서: • Max priority queue : highest priority first • in job scheduler • Min priority queue : lowest priority first • template <class Type> • class MaxPQ { • public: • virtual void Insert(const Element<Type>&) = 0; • virtual Element<Type> *DeleteMax(Element<Type>&) = 0; • }; • Element<Type> : Key 데이타 멤버를 가진 struct

More Related