[BinaryTree] 二叉树类的实现

来源:互联网 发布:coach淘宝代购 编辑:程序博客网 时间:2024/06/02 05:54
二叉树结点的抽象数据类型:

 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;            //判断该结点是否是叶子结点,若是,则返回true14 };

二叉树结点函数功能实现:

 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() const21 {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         else16         {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         else14         {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 //           A32 //    B             C33 //       D              E34 //     F   G               H

测试结果:

原创粉丝点击