二叉樹結點的抽象數據類型:
1 template<class T> 2 class BinaryTreeNode 3 { 4 friend class BinaryTree<T>; 5 private: 6 T element; //結點的數據域 7 BinaryTreeNode<T>* LeftChild; //結點的左孩子結點 8 BinaryTreeNode<T>* RightChild; //結點的右孩子結點 9 public: 10 BinaryTreeNode(); 11 BinaryTreeNode(const T& ele); 12 BinaryTreeNode(const T& ele, BinaryTreeNode<T>* l, BinaryTreeNode<T>* r); 13 bool isLeaf() const; //判斷該結點是否是葉子結點,若是,則返回true 14 };
二叉樹結點函數功能實現:
1 template<class T> 2 BinaryTreeNode<T>::BinaryTreeNode() 3 { 4 LeftChild = RightChild = NULL; 5 } 6 template<class T> 7 BinaryTreeNode<T>::BinaryTreeNode(const T& ele) 8 { 9 element = ele; 10 LeftChild = RightChild = NULL; 11 } 12 template<class T> 13 BinaryTreeNode<T>::BinaryTreeNode(const T& ele, BinaryTreeNode<T>* l, BinaryTreeNode<T>* r) 14 { 15 element = ele; 16 LeftChild = l; 17 RightChild = r; 18 } 19 template<class T> 20 bool BinaryTreeNode<T>::isLeaf() const 21 { 22 if (LeftChild == NULL && RightChild == NULL) 23 return true; 24 else return false; 25 }
二叉樹的抽象數據類型:
1 template<class T> 2 class BinaryTree 3 { 4 private: 5 BinaryTreeNode<T>* root; 6 public: 7 BinaryTree(); 8 ~BinaryTree() {} 9 bool IsEmpty() const; //判斷二叉樹是否為空樹 10 BinaryTreeNode<T>* getRoot() const; //返回二叉樹的根結點 11 void breadthFirstOrder(BinaryTreeNode<T>* root);//廣度優先遍歷以root為根結點的子樹 12 void preOrder(BinaryTreeNode<T>* root); //先序遍歷以root為根結點的子樹 13 void inOrder(BinaryTreeNode<T>* root); //中序遍歷以root為根結點的子樹 14 void postOrder(BinaryTreeNode<T>* root); //后序遍歷以root為根結點的子樹 15 void deleteBinaryTree(BinaryTreeNode<T>* root); //刪除以root為根結點的子樹 16 void visit(BinaryTreeNode<T>* pointer); //訪問當前結點 17 BinaryTreeNode<T>* build_from_pre_and_in(char* preorder, char* inorder, int n); 18 //根據前序和中序遍歷表達式構造二叉樹 19 BinaryTreeNode<T>* build_from_post_and_in(char* postorder, char* inorder, int m); 20 //根據后序和中序遍歷表達式構造二叉樹 21 int getRootId1(char *preorder, char *inorder, int n); //返回根結點在中序遍歷表達式中序號 22 int getRootId2(char *postorder, char *inorder, int m); //返回根結點在中序遍歷表達式中序號 23 };
廣度優先遍歷(隊列):
【思路】根結點入隊,隊列不空循環,訪問隊頭並出隊,左子樹不空則入隊,右子樹不空則入隊。
1 template<class T> 2 void BinaryTree<T>::breadthFirstOrder(BinaryTreeNode<T>* root) 3 { 4 queue<BinaryTreeNode<T> *> nodeQueue; 5 BinaryTreeNode<T> * pointer = root; 6 if (pointer) 7 nodeQueue.push(pointer); 8 while (!nodeQueue.empty()) 9 { 10 pointer = nodeQueue.front(); 11 visit(pointer); 12 nodeQueue.pop(); 13 if (pointer->LeftChild) 14 nodeQueue.push(pointer->LeftChild); 15 if (pointer->RightChild) 16 nodeQueue.push(pointer->RightChild); 17 } 18 }
先序遍歷:
【思路】
1.訪問當前結點
2.當前結點的右兒子結點非空,則入棧
3.左兒子結點非空,使之作為當前結點,否則彈出棧頂元素,使之作為當前結點
4.反復執行1、2、3,至棧空為止
1 template<class T> 2 void BinaryTree<T>::preOrder(BinaryTreeNode<T>* root) 3 { 4 stack<BinaryTreeNode<T> *> nodeStack; 5 BinaryTreeNode<T> * pointer = root; 6 while (!nodeStack.empty() || pointer) 7 { 8 if (pointer) 9 { 10 visit(pointer); 11 if (pointer->RightChild != NULL) 12 nodeStack.push(pointer->RightChild); 13 pointer = pointer->LeftChild; 14 } 15 else 16 { 17 pointer = nodeStack.top(); 18 nodeStack.pop(); 19 } 20 } 21 }
中序遍歷:
【思路】
1.每遇到一個結點就把它壓棧,然后去遍歷其左子樹
2.遍歷完左子樹后,從棧頂彈出這個結點並訪問之
3.然后遍歷該結點的右子樹
1 template<class T> 2 void BinaryTree<T>::inOrder(BinaryTreeNode<T>* root) 3 { 4 stack<BinaryTreeNode<T> *> nodeStack; 5 BinaryTreeNode<T> * pointer = root; 6 while (!nodeStack.empty() || pointer) 7 { 8 if (pointer) 9 { 10 nodeStack.push(pointer); 11 pointer = pointer->LeftChild; 12 } 13 else 14 { 15 pointer = nodeStack.top(); 16 visit(pointer); 17 pointer = pointer->RightChild; 18 nodeStack.pop(); 19 } 20 } 21 }
后序遍歷:
【基本思想】
1.每遇到一個結點,先把它推入棧中,去遍歷它的左子樹
2.遍歷完它的左子樹后,應繼續遍歷該結點的右子樹
3.遍歷完右子樹之后,才從棧頂彈出該結點並訪問它
【解決方案】
0.將根結點作為當前結點
1.進棧過程:
a.如果當前結點不空且具有左子樹,將當前結點壓入棧中,否則進入2
b.將當前結點的左子樹的根結點設置為當前結點
c.重復 a
2.出棧過程:
a.如果當前結點不空且沒有右子樹,或者其右子樹的根結點已經訪問,訪問之,否則進入3
b.若棧空,結束,否則取出當前棧頂結點作為當前結點
c.重復 a
3.將當前結點壓入棧中
4.將當前結點的右子樹的根結點設為當前結點,重復 1
1 template<class T> 2 void BinaryTree<T>::postOrder(BinaryTreeNode<T>* root) 3 { 4 stack<BinaryTreeNode<T> * > nodeStack; 5 BinaryTreeNode<T> *pre = root, *pointer = root; 6 while (pointer) 7 { 8 //入棧過程 9 for (; pointer->LeftChild != NULL; pointer = pointer->LeftChild) 10 { 11 nodeStack.push(pointer); 12 } 13 //出棧過程 14 while (pointer != NULL && (pointer->RightChild == NULL || pointer->RightChild == pre)) 15 //當前結點右孩子為空或右孩子剛被訪問過,則訪問該結點 16 { 17 visit(pointer); 18 pre = pointer; 19 if (nodeStack.empty()) 20 return; 21 pointer = nodeStack.top(); 22 nodeStack.pop(); 23 } 24 //將當前結點壓入棧中 25 nodeStack.push(pointer); 26 //將當前結點的右子樹的根結點設為當前結點 27 pointer = pointer->RightChild; 28 } 29 }
刪除以root為根結點的子樹:
1 template<class T> 2 void BinaryTree<T>::deleteBinaryTree(BinaryTreeNode<T>* root) 3 { 4 if (root->LeftChild != NULL) 5 deleteBinaryTree(root->LeftChild); 6 if (root->RightChild != NULL) 7 deleteBinaryTree(root->RightChild); 8 delete root; 9 root = NULL; 10 }
根據前序和中序遍歷表達式構造二叉樹:
【思路】根據前序序列,找到根結點在中序序列中的位置,遞歸根結點的左子樹序列和右子樹序列。
1 template<class T> 2 BinaryTreeNode<T>* BinaryTree<T>::build_from_pre_and_in(char* preorder, char* inorder, int n) 3 { 4 if (n == 0) 5 return NULL; 6 char root_element = preorder[0]; 7 int i = 0; 8 for( ;i < n;i ++) 9 { 10 if(root_element == inorder[i]) 11 break; 12 } 13 BinaryTreeNode<T>* root = new BinaryTreeNode<T>; 14 root->element = root_element; 15 root->LeftChild = build_from_pre_and_in(preorder + 1, inorder, i); 16 root->RightChild = build_from_pre_and_in(preorder + i + 1, inorder + i + 1, n - i - 1); 17 return root; 18 }
根據后序和中序遍歷表達式構造二叉樹:
【思路】根據后序序列,找到根結點在中序序列中的位置,遞歸根結點的左子樹序列和右子樹序列。
1 template<class T> 2 BinaryTreeNode<T>* BinaryTree<T>::build_from_post_and_in(char* postorder, char* inorder, int m) 3 { 4 if (m == 0) 5 return NULL; 6 char root_element = postorder[m - 1]; 7 int i = 0; 8 for( ;i < m;i ++) 9 { 10 if(root_element == inorder[i]) 11 break; 12 } 13 BinaryTreeNode<T>* root = new BinaryTreeNode<T>; 14 root->element = root_element; 15 root->LeftChild = build_from_post_and_in(postorder, inorder, i); 16 root->RightChild = build_from_post_and_in(postorder+i, inorder + i+1, m-i-1); 17 return root; 18 }
測試函數:
1 int main() 2 { 3 BinaryTreeNode<char> *zero = 0; 4 BinaryTreeNode<char> f('F'), g('G'), h('H'); 5 BinaryTreeNode<char> d('D', &f, &g), e('E', zero, &h); 6 BinaryTreeNode<char> b('B', zero, &d), c('C', zero, &e); 7 BinaryTreeNode<char> a('A', &b, &c); 8 BinaryTree<char> Tree; 9 cout << "廣度優先遍歷為:" << endl; 10 Tree.breadthFirstOrder(&a); 11 cout << endl << "先序遍歷為:" << endl; 12 Tree.preOrder(&a); 13 cout << endl << "中序遍歷為:" << endl; 14 Tree.inOrder(&a); 15 cout << endl << "后序遍歷為:" << endl; 16 Tree.postOrder(&a); 17 char *preorder = "ABDFGCEH"; 18 char *inorder = "BFDGACEH"; 19 char *postorder = "FGDBHECA"; 20 int n = strlen(preorder); 21 int m = strlen(postorder); 22 BinaryTreeNode<char>* root1 = Tree.build_from_pre_and_in(preorder, inorder, n); 23 cout << endl << "先序中序構造后廣度優先遍歷為:" << endl; 24 Tree.breadthFirstOrder(root1); 25 BinaryTreeNode<char>* root2 = Tree.build_from_post_and_in(postorder, inorder, m); 26 cout << endl << "后序中序構造后廣度優先遍歷為:" << endl; 27 Tree.breadthFirstOrder(root2); 28 return 0; 29 } 30 // 測試的二叉樹 31 // A 32 // B C 33 // D E 34 // F G H
測試結果: