zoukankan      html  css  js  c++  java
  • [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

    测试结果:

  • 相关阅读:
    亮剑.NET的系列文章之ADO.NET五大类(二)
    Effective C++ 读书笔记之Part6.Inheritance and ObjectOriented Design
    论计算机专业毕业生的人文素养
    LLVM每日谈之十四 如何给Clang添加一个属性
    那些年,面试中遇到的那些奇葩们
    亮剑.NET的系列文章之.NET实现三层架构(三)
    [转]C++预编译头文件
    [转]文件间的编译依赖性
    [转]详解编译预处理
    [转]Visual Studio 2005 IDE 技巧和窍门
  • 原文地址:https://www.cnblogs.com/lca1826/p/6358418.html
Copyright © 2011-2022 走看看