[BinaryTree] 二叉樹類的實現


二叉樹結點的抽象數據類型:

 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

測試結果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM