zoukankan      html  css  js  c++  java
  • 二叉树的基本功能实现方法(C++)

    假设:有一个n个元素的完全二叉树,为了使其成为满二叉树,补全没有孩子的节点是的除了叶节点所有节点都有两个孩子,即最低层皆为-1.

    例1:

                  1

             2          3  

          4     5     -1    6 

         -1  -1     -1  -1                -1   -1   

    补全的节点赋值为-1,表示当前无节点,需转向别的子树。

    step 1:首先,对于一棵二叉树,需定义一个节点的类模板:

    包括:节点键值、左子树指针、右子树指针

    template <typename T>
    class binaryTreeNode {
    public:
        T element;
        binaryTreeNode<T>* leftChild;
        binaryTreeNode<T>* rightChild;
        
        binaryTreeNode(){leftChild = NULL;rightChild = NULL;}
    };

    step 2:如何创建一棵二叉树呢?根据链表的特性,成员变量为:节点指针类型的mRoot根节点。除此之外,还包括常见的成员函数:如 获取树的当前规模、获取树的深度、打印或输出树及销毁二叉树等操作。

     1 template <typename T>
     2 class binaryTree {
     3 private:
     4     binaryTreeNode<T>* mRoot;//树根
     5     
     6     
     7     int getSize(binaryTreeNode<T>*);
     8     int getHeight(binaryTreeNode<T>*);
     9     
    10     void preOrder(binaryTreeNode<T>*);
    11     void inOrder(binaryTreeNode<T>*);
    12     void postOrder(binaryTreeNode<T>*);
    13     void distroy(binaryTreeNode<T>*&);
    14     binaryTreeNode<T>* AddNode(const T& key,int direction,binaryTreeNode<T>*& root);
    15     
    16 public:
    17     binaryTree();
    18     virtual ~binaryTree();
    19     binaryTreeNode<T>* Create();//递归的创建二叉树的节点
    20     void AddNode(const T& key,int direction);
    21     
    22     int getSize();//递归得到树的节点数目
    23     int getHeight();//递归得到树的高度
    24     
    25     //递归遍历
    26     void preOrder();//前序遍历
    27     void inOrder();//中序遍历
    28     void postOrder();//后序遍历
    29     
    30     //删除二叉树
    31     void distroy();
    32     
    33 };
    View Code

    >>首先,怎么在二叉树中插入节点呢?
    可以想到的是,插入新节点的时候需要标明 插得是左孩子还是右孩子which,在哪一个父节点下插入where,及插入的键值是多少what,简单的来说,就是WWW问题

     1 template <typename T>
     2 binaryTreeNode<T>* binaryTree<T>::AddNode(const T& key,int direction,binaryTreeNode<T>*& root)
     3 {
     4     if(direction == 0)//左孩子
     5     {
     6         if(root->leftChild == NULL){//找到对应的叶节点插入
     7             root->leftChild = new binaryTreeNode<T>(key);
     8         }
     9         else{
    10             root->leftChild = AddNode(key, direction, root->leftChild);
    11         }
    12     }
    13     
    14     else//右孩子
    15     {
    16         if (root->rightChild == NULL) {//找到相应的叶节点插入
    17             root->rightChild = new binaryTreeNode<T>(key);
    18         }
    19         else{
    20             root->rightChild = AddNode(key, direction, root->rightChild);
    21         }
    22     }
    23     
    24     return root;
    25 }
    26 
    27 template <typename T>
    28 void binaryTree<T>::AddNode(const T& key,int direction)
    29 {
    30     AddNode(key, direction, mRoot);
    31 }

    了解了这个思路后,可以不用一个个插入节点,用输入流的方式直接创建一棵树,如下程序:

     1 template <typename T>
     2 binaryTreeNode<T>* binaryTree<T>::Create(){
     3     
     4     binaryTreeNode<T>* current = NULL;
     5     
     6     T val;
     7     
     8     cin >> val;//输入键值
     9     
    10     if(val == -1)//标识当前子树为空,转向下一节点
    11     {
    12         return NULL;
    13     }
    14     
    15     else{//递归的创建左右子树
    16         current = new binaryTreeNode<T>;
    17         current->element = val;
    18         current->leftChild = Create();
    19         current->rightChild = Create();
    20         return current;
    21     }
    22 }

    可以发现,-1是一个过渡标识,标明当前从递归左子树 转向 递归右子树。而上述创建程序是一个前序遍历,所谓前序遍历是指:

      1.先访问父节点

      2.递归左子树

      3.递归右子树

    时间复杂度是O(N),因为遍历了每一个节点。

    >>创建了二叉树后,怎么销毁?其实只要一一删除每个节点即可,考虑到链表结构,我们不能使用下标去删除节点,只能一个个的访问,而二叉树典型的遍历方法有:前序遍历、中序遍历 及 后序遍历。在这里,我们使用后序遍历进行递归删除, 即自下而上的删除。

     1 /*二叉树的销毁操作:后序遍历删除
     2 
     3 1)不能使用该声明:void distroy(binaryTreeNode<T>* pNode);该声明会创建一个局部的临时对象来保存传递的指针
     4 虽然实参指针和局部指针都执行同一块堆空间,delete局部指针也会删除二叉树结构所占用的堆内存
     5 但是实参指针将出现无所指的状态,出现不可预料的错误
     6 因此传递的是指针的引用,这样才能将实参指针置空。
     7 
     8 2)使用递归方法释放节点
     9  
    10 */
    11 
    12 template <typename T>
    13 void binaryTree<T>::distroy(binaryTreeNode<T>*& pNode)
    14 {
    15     if(pNode)
    16     {
    17         distroy(pNode->leftChild);
    18         distroy(pNode->rightChild);
    19         delete pNode;
    20         pNode = NULL;
    21     }
    22 }
    23 template <typename T>
    24 void binaryTree<T>::distroy()
    25 {
    26     distroy(mRoot);
    27 }

    如要删除如上例1中的二叉树,删除过程依次为:4 5 2 6 3 1

    >>对于获取树的深度,有一种方法是,获取左右子树的深度,比较子树深度大小,大的那个增1即为树的深度了。当然,也是递归实现。

     1 template <typename T>
     2 int binaryTree<T>::getHeight()
     3 {
     4     return getHeight(mRoot);
     5 }
     6 /*
     7 获取当前节点的深度
     8  递归的方法首先要设置截止条件,在进行递归操作。
     9  0.约束条件:节点为空
    10  1.递归左子树,每次递归加1
    11  2.递归右子树,每次递归加1
    12  3.比较左右子树深度,更深的子树+1即为当前节点深度。
    13 */
    14 
    15 template <typename T>
    16 int binaryTree<T>::getHeight(binaryTreeNode<T>* node)
    17 {
    18     if(node == NULL)
    19         return 0;
    20     else{
    21         int depL = getHeight(node->leftChild);
    22         int depR = getHeight(node->rightChild);
    23         return (depL > depR) ? depL+1 : depR+1;
    24     }
    25         
    26 }

    >>同理,获取树的规模只要遍历整棵树即可,这里用递归实现。这里仅给出前序遍历,后序遍历和中序遍历类似则不再给出。

     1 template <typename T>
     2 void binaryTree<T>::preOrder()
     3 {
     4     cout <<"前序遍历: ";
     5     preOrder(mRoot);
     6     cout << endl;
     7 }
     8 
     9 /*
    10  前序遍历:
    11  1.由于是递归实现,所以要设置截止条件:当前节点为空
    12  2.先访问父节点,再访问左节点,最后访问右孩子
    13  
    14  */
    15 template <typename T>
    16 void binaryTree<T>::preOrder(binaryTreeNode<T>* node)
    17 {
    18     if(node == NULL)
    19         return;
    20     else{
    21         cout << node->element <<' ';
    22         preOrder(node->leftChild);
    23         preOrder(node->rightChild);
    24     }
    25 }

    对于例1的遍历结果,如下:

    输入:1 2 4 -1 -1 5 -1 -1 3 -1 6 -1 -1
    前序遍历: 1 2 4 5 3 6  
    中序遍历: 4 2 5 1 3 6  
    后序遍历: 4 5 2 6 3 1 
    树的高度为: 3
    树的节点数目: 6

    >>总之呢,创建二叉树的全过程都用到了递归,那么递归到底是什么呢?

    从定义上来讲:递归作为一种算法,是让函数/子程序/过程在程序运行过程中调用自身的方法,能够把一个较为复杂的问题经过层层转换,得到一个与原问题相似但是规模大大减小的问题来求解。递归方法大大减少了代码的复杂度。

    实现方法:首先递归必须设置一个终止条件,当满足终止条件时,则递归返回。除此之外,则递归调用自身。

  • 相关阅读:
    题目:心灵的抚慰
    间谍网络
    tarjan算法模版
    rect
    学校食堂
    题目:自然的雪糕
    Winform里众多上下文菜单的控制要怎么做?
    ubuntu更新列表
    瞧,Silverlight是如何被部署到客户机的
    盖茨十条成功箴言 值得一生铭记
  • 原文地址:https://www.cnblogs.com/SarahZhang0104/p/5827532.html
Copyright © 2011-2022 走看看