编程基础 - 二叉树 (Binary Tree)

编程基础 - 二叉树 (Binary Tree)

返回分类:全部文章 >> 基础知识

本文将介绍二叉树的基础知识,并用C++实现主要方法。

在查看本文之前,需要一些数据结构和程序语言的基础,要对“树 (tree) ”的概念有一些了解。

其中的方法还需要熟悉“栈(stack)”、“队列(queue)”和“递归”。



1 二叉树简述 (Introduction)

二叉树:

  • 是结点的一个有限集合

  • 是一个最多有两个子树的树结构(左子树和右子树),同时子树也是二叉树;

  • 是一个连通的无环图

  • 是递归定义的;

二叉树逻辑上有五种基本形态:

  • (1)空

    NULL
  • (2)只有一个根结点

    Root
  • (3)只有左子树

    Root
    L
    NULL
  • (4)只有右子树

    Root
    NULL
    R
  • (5)完全二叉树

    Root
    L
    R

一些常见二叉树:

  • (1)完全二叉树 (Complete Binary Tree) :从深度上看,最深层有叶节点,且叶节点从左到右依次排序,其它层结点达到最大值;

    A
    B
    C
    D
    E
    F
    NULL
  • (2)满二叉树 (Full Binary Tree) :

    • 国内定义:除最深层外,其它结点都存在左右结点,且叶结点都在最深层;它还是一种特殊的完全二叉树;

      A
      B
      C
      D
      E
      F
      G
    • 国际定义:二叉树的每个结点都有0或2个结点;

      A
      B
      C
      D
      E
      F
      G
      A
      B
      C
      D
      E
      F
      G

    注意:国内与国际定义不同,看外文文献或是看外文算法时要注意区分。

  • (3)二叉排序树 (Binary Search Tree) :也称二叉查找树和二叉搜索树。空树或左子二叉排序树的结点都小于根结点且右子二叉排序树的结点都大于根结点的二叉树;

  • (4)平衡二叉树 (Balanced Binary Tree) :又称AVL树。空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树;

  • (5)线索二叉树 (Threaded Binary Tree) :加上线索指针(存放指向结点在某种遍历次序下的前驱和后继结点的指针)的二叉树;

  • (6)哈夫曼树 (Huffman Tree) :带权路径长度达到最小的二叉树,也称最优二叉树。

二叉树与树的不同点:

  • (1)结点最大度数为2(树无限制)

  • (2)子树分左右(树不分)


2 二叉树性质 (Properties)

(提示:在CSDN的app中,公式有可能会出现乱码或格式错乱,如果出现请打开网页)

  • (1)在非空二叉树中,且层次从1开始,则二叉树第 i i i 层最多有 2 i − 1 ( i ≥ 1 ) 2^{i-1} (i \ge 1) 2i1(i1) 个结点;

  • (2)高度为 h h h 的二叉树最多有 2 h − 1 ( h ≥ 1 ) 2^h-1 (h \ge 1) 2h1(h1) 个结点

  • (3)对任意一棵非空二叉树,如果其叶结点有 n 0 n_0 n0 个,度为2的非叶结点有 n 2 n_2 n2 个,则有 n 0 = n 2 + 1 n_0 = n_2 + 1 n0=n2+1

  • (4)具有 n ( n ≥ 0 ) n (n \ge 0) n(n0) 个结点的完全二叉树的高度为 ⌈ log ⁡ 2 ( n + 1 ) ⌉ \lceil \log_2 (n+1) \rceil log2(n+1)

    • 注意:另一个公式 ⌊ log ⁡ 2 n ⌋ + 1 \lfloor \log_2 n \rfloor + 1 log2n+1 n = 0 n = 0 n=0 不适用。
  • (5)有 n n n 个结点的完全二叉树各结点如果用顺序方式存储,则结点之间有如下关系( i i i 为结点标号):

    • i = 0 i = 0 i=0 ,则 i i i 无双亲;
    • i > 0 i > 0 i>0 ,则 i i i 双亲为 ⌊ ( i − 1 ) ÷ 2 ⌋ \lfloor (i-1) \div 2 \rfloor (i1)÷2
    • 2 × i + 1 &lt; n 2 \times i + 1 &lt; n 2×i+1<n ,则 i i i 的左子女为 2 × i + 1 2 \times i + 1 2×i+1
    • 2 × i + 2 &lt; n 2 \times i + 2 &lt; n 2×i+2<n ,则 i i i 的左子女为 2 × i + 2 2 \times i + 2 2×i+2
    • i i i 为偶数,且 i ≠ 0 i \ne 0 i̸=0 ,则左兄弟为 i − 1 i-1 i1
    • i i i 为奇数,且 i ≠ n − 1 i \ne n-1 i̸=n1,则右兄弟为 i + 1 i+1 i+1
  • (6)给定 n n n 个节点,能构成 1 n + 1 C 2 n n \frac{1}{n+1} C_{2n}^{n} n+11C2nn (卡特兰数)种不同的二叉树;

  • (7)设有 i i i 个枝点, I I I 为所有枝点的道路长度总和,则叶的道路长度总和 J = I + 2 × i J = I + 2 \times i J=I+2×i


3 二叉树的结构 (Structure)

而在二叉树的结构中,依然可以分成两种:

  • 顺序存储

    顺序存储一般是存储在数组或列表中。

    (性质(5)中是从0存储,但实际下标常常从1开始,0留空或作他用)

    A
    B
    C
    D
    E
    F
    G
    即:
    tree  = [ NULL, a, b, c, d, e, NULL, NULL, NULL, NULL,  f,  g, ... ]
    index = [    0, 1, 2, 3, 4, 5,    6,    7,    8,    9, 10, 11, ... ]
    
    

    从1开始存储,假设 P i P_i Pi 为结点下标, L i L_i Li 为其左孩子下标, R i R_i Ri 为其右孩子下标。

    由结点下标求左右孩子下标:

    L i = P i × 2 R i = P i × 2 + 1 \begin{aligned} L_i &amp;= P_i \times 2 \\ R_i &amp;= P_i \times 2 + 1 \\ \end{aligned} LiRi=Pi×2=Pi×2+1

    由左右孩子下标求结点下标:

    P i = L i ÷ 2 P i = ⌊ R i ÷ 2 ⌋ \begin{aligned} P_i &amp;= L_i \div 2 \\ P_i &amp;= \lfloor R_i \div 2 \rfloor \end{aligned} PiPi=Li÷2=Ri÷2

  • 链式存储

    二叉树结点一般定义为:

    template<typename T>
    class BinaryTreeNode
    {
        T element;
        BinaryTreeNode<T>* leftChild;
        BinaryTreeNode<T>* rightChild;
        BinaryTreeNode(const T& x) : element(x), leftChild(0), rightChild(0) {}
    };

4 二叉树的遍历 (Traversal)

二叉树的基本遍历分为四种(V=Visit,L=Left,R=Right):

  • 层序遍历(Layer),见文章 [5.5 层序遍历 (Layer Traversal)]

  • 中序遍历(LVR),中序镜像遍历(RVL)

  • 前序遍历(VLR),前序镜像遍历(VRL)

  • 后序遍历(LRV),后序镜像遍历(RLV)

以下我们用链式结构来说明如何遍历(数组结构同理,只是改成了下标的运算)。

4.1 中序遍历 (Inorder)

步骤(二叉树不为空):

  • (1)遍历左子树(Left);

  • (2)访问当前结点(Visit);

  • (3)遍历右子树(Right)。

递归方法代码一般为:

    // 中序递归
    template<typename T>
    void InorderTraversal(BinaryTreeNode<T>* node, void(*pVisit)(BinaryTreeNode<T>&))
    {
        if (node != 0)
        {
            InorderTraversal(node->leftChild);
            (*pVisit)(*node);
            InorderTraversal(node->rightChild);
        }
    }

例如,abcdefg结点:

        a
      /   \
    b       c
  /   \
d       e
      /   \
    f       g

中序遍历步骤为:
    (1)a,遍历左子树,即:a->b
        (2)b,遍历左子树,即:b->d
            (3)d,没有左子树
            (4)d,访问当前结点,即:Visit(d)
            (5)d,没有右子树
            (6)d,返回,即:b<-d
        (7)b,访问当前结点,即:Visit(b)
        (8)b,遍历右子树,即:b->e
            (9)e,遍历左子树,即:e->f
                (10)f,没有左子树
                (11)f,访问当前结点,即:Visit(f)
                (12)f,没有右子树
                (13)f,返回,即:e<-f
            (14)e,访问当前结点,即:Visit(e)
            (15)e,遍历右子树,即:e->g
                (16)g,没有左子树
                (17)g,访问当前结点,即:Visit(g)
                (18)g,没有右子树
                (19)g,返回,即:e<-g
            (20)e,返回,即:b<-e
        (21)b,返回,即:a<-b
    (22)a,访问当前结点,即:Visit(a)
    (23)a,遍历右子树,即:a->c
        (24)c,没有左子树
        (25)c,访问当前结点,即:Visit(c)
        (26)c,没有右子树
        (27)c,返回,即:a<-c
    (28)a,返回,即:NULL <-a

中序遍历结果为:dbfegac

4.2 前序遍历 (Preorder)

步骤(二叉树不为空):

  • (1)访问当前结点(Visit);

  • (2)遍历左子树(Left);

  • (3)遍历右子树(Right)。

递归方法代码一般为:

    // 前序递归
    template<typename T>
    void PreorderTraversal(BinaryTreeNode<T>* node, void(*pVisit)(BinaryTreeNode<T>&))
    {
        if (node != 0)
        {
            (*pVisit)(*node);
            PreorderTraversal(node->leftChild);
            PreorderTraversal(node->rightChild;
        }
    }

例如,abcdefg结点:

        a
      /   \
    b       c
  /   \
d       e
      /   \
    f       g

前序遍历步骤为:
    (1)a,访问当前结点,即:Visit(a)
    (2)a,遍历左子树,即:a->b
        (3)b,访问当前结点,即:Visit(b)
        (4)b,遍历左子树,即:b->d
            (5)d,访问当前结点,即:Visit(d)
            (6)d,没有左子树
            (7)d,没有右子树
            (8)d,返回,即:b<-d
        (9)b,遍历右子树,即:b->e
            (10)e,访问当前结点,即:Visit(e)
            (11)e,遍历左子树,即:e->f
                (12)f,访问当前结点,即:Visit(f)
                (13)f,没有左子树
                (14)f,没有右子树
                (15)f,返回,即:e<-f
            (16)e,遍历右子树,即:e->g
                (17)g,访问当前结点,即:Visit(g)
                (18)g,没有左子树
                (19)g,没有右子树
                (20)g,返回,即:e<-g
            (21)e,返回,即:b<-e
        (22)b,返回,即:a<-b
    (23)a,遍历右子树,即:a->c
        (24)c,访问当前结点,即:Visit(c)
        (25)c,没有左子树
        (26)c,没有右子树
        (27)c,返回,即:a<-c
    (28)a,返回,即:NULL <-a

前序遍历结果为:abdefgc

4.3 后序遍历 (Postorder)

步骤(二叉树不为空):

  • (1)遍历左子树(Left);

  • (2)遍历右子树(Right)。

  • (3)访问当前结点(Visit);

递归方法代码一般为:

    // 后序递归
    template<typename T>
    void PostorderTraversal(BinaryTreeNode<T>* node, void(*pVisit)(BinaryTreeNode<T>&))
    {
        if (node != 0)
        {
            PostorderTraversal(node->leftChild);
            PostorderTraversal(node->rightChild;
            (*pVisit)(*node);
        }
    }

例如,abcdefg结点:

        a
      /   \
    b       c
  /   \
d       e
      /   \
    f       g

后序遍历步骤为:
    (1)a,遍历左子树,即:a->b
        (2)b,遍历左子树,即:b->d
            (3)d,没有左子树
            (4)d,没有右子树
            (5)d,访问当前结点,即:Visit(d)
            (6)d,返回,即:b<-d
        (7)b,遍历右子树,即:b->e
            (8)e,遍历左子树,即:e->f
                (9)f,没有左子树
                (10)f,没有右子树
                (11)f,访问当前结点,即:Visit(f)
                (12)f,返回,即:e<-f
            (13)e,遍历右子树,即:e->g
                (14)g,没有左子树
                (15)g,没有右子树
                (16)g,访问当前结点,即:Visit(g)
                (17)g,返回,即:e<-g
            (18)e,访问当前结点,即:Visit(e)
            (19)e,返回,即:b<-e
        (20)b,访问当前结点,即:Visit(b)
        (21)b,返回,即:a<-b
    (22)a,遍历右子树,即:a->c
        (23)c,没有左子树
        (24)c,没有右子树
        (25)c,访问当前结点,即:Visit(c)
        (26)c,返回,即:a<-c
    (27)a,访问当前结点,即:Visit(a)
    (28)a,返回,即:NULL <-a

后序遍历结果为:dfgebca

4.4 已知前(或后)中序求二叉树 (Order Infer Tree)

前序(或后序)与中序求二叉树推导方法:

  • 当前 (子)二叉树中,前序第一位(后序最后一位)为根结点;

  • 当前 (子)二叉树中,中序负责使用根结点分割树;

  • 循环前两步过程,直到全部分完。

已知:

  • 前序遍历结果为:ABDEFCG

  • 中序遍历结果为:DBFEACG

  • 后序遍历结果为:DFEBGCA

推导过程:

  • 在前序ABDEFGC中,A为根结点,则在中序DBFEACG中找到A,并分成左右子树:

    A
    DBFE
    CG
  • 在前序BDEF中,B为根结点,则在中序DBFE中找到B,并分成左右子树:

    A
    B
    CG
    D
    FE
  • 在前序EF中,E为根结点,则在中序FE中找到E,并分成左右子树:

    A
    B
    CG
    D
    E
    F
    NULL
  • 在前序CG中,C为根结点,则在中序CG中找到C,并分成左右子树:

    A
    B
    C
    D
    E
    F
    NULL
    NULL
    G

同理可以用后序和中序推导二叉树。

比较重要的结论:

  • 前序(后序)序列和中序序列可唯一地确定一棵二叉树;

  • 前序序列和后序序列不能确定二叉树;

  • 前序(后序)序列固定不变,只改变中序排列,可得到 1 n + 1 C 2 n n \frac{1}{n+1} C_{2n}^n n+11C2nn 棵不同的二叉树;


5 一些常用方法的代码 (Code of Some Usual Methods)

5.1 结点数量 (Node Count)

  • 递归

    template<typename T>
    int Count(BinaryTreeNode<T>* root)
    {
        if (root == 0)
        {
            return 0;
        }
    
        return Count(root->leftChild) + Count(root->rightChild) + 1;
    }
    
  • 非递归

    // Author: https://blog.csdn.net/DarkRabbit
    // Binary Tree
    // 计算数量(与层序遍历差不多)
    template<typename T>
    int Count(BinaryTreeNode<T>* root)
    {
        if (root == 0)
        {
            return 0;
        }
    
        int count = 0;
    
        std::queue<BinaryTreeNode<T>*> nodeQueue;
        nodeQueue.push(root);
        
        BinaryTreeNode<T>* node;
        while (!nodeQueue.empty())
        {
            count++;
    
            node = nodeQueue.front();
            nodeQueue.pop();
    
            if (node->leftChild != 0)
            {
                nodeQueue.push(node->leftChild);
            }
    
            if (node->rightChild != 0)
            {
                nodeQueue.push(node->rightChild);
            }
        }
    
        return count;
    }
    

5.2 深度或高度 (Depth or Height)

  • 递归

    template<typename T>
    int DepthOrHeight(BinaryTreeNode<T>* root)
    {
        if (root == 0)
        {
            return 0;
        }
    
        int left = DepthOrHeight(root->leftChild);
        int right = DepthOrHeight(root->rightChild);
        return (left > right ? left : right) + 1;
    }
    
  • 非递归

    // Author: https://blog.csdn.net/DarkRabbit
    // Binary Tree
    // 计算深度或高度
    template<typename T>
    int DepthOrHeight(BinaryTreeNode<T>* root)
    {
        if (root == 0)
        {
            return 0;
        }
    
        int depth = 0;
        std::queue<BinaryTreeNode<T>*>* lineNodes = new std::queue<BinaryTreeNode<T>*>(); // 当前层结点队列
        std::queue<BinaryTreeNode<T>*>* nextNodes = new std::queue<BinaryTreeNode<T>*>(); // 下一层结点队列
        std::queue<BinaryTreeNode<T>*>* tmp = 0; // 用于队列交换
        lineNodes->push(root); // 加入头结点
        
        BinaryTreeNode<T>* node;
        while (!lineNodes->empty())
        {
            depth++;
    
            // 将下一层结点,加入到 nextNodes 队列中
            while (!lineNodes->empty())
            {
                node = lineNodes->front();
                lineNodes->pop();
    
                if (node->leftChild != 0)
                {
                    nextNodes->push(node->leftChild);
                }
                if (node->rightChild != 0)
                {
                    nextNodes->push(node->rightChild);
                }
            }
    
            // 将下一层结点队列作为当前层结点队列
            tmp = lineNodes;
            lineNodes = nextNodes;
            nextNodes = tmp;
            tmp = 0;
        }
    
        delete lineNodes; // 销毁队列
        delete nextNodes; // 销毁队列
        return depth;
    }
    

5.3 创建完全二叉树 (Create Complete Binary Tree)

// Author: https://blog.csdn.net/DarkRabbit
// Binary Tree
// 创建一个整型完全二叉树
// params:
//      rootVal:                根节点值
//      nodeCount:              结点数量
//      elementInterval:        相邻结点数值间隔
// return:
//      BinaryTreeNode<int>*:   完全二叉树
BinaryTreeNode<int>* CreateIntergerCompleteBinaryTree(const int rootVal,
                                                      const int nodeCount,
                                                      const int elementInterval)
{
    if (nodeCount < 1)
    {
        throw std::invalid_argument("`nodeCount` is less than one.");
    }

    BinaryTreeNode<int>* btTree = new BinaryTreeNode<int>*(rootVal) // 初始化根结点

    if (nodeCount == 1) // 如果只有根结点,直接返回
    {
        return btTree;
    }

    std::queue<BinaryTreeNode<int>*> nodeQueue; // 结点队列
    BinaryTreeNode<int>* node = btTree; // 定义初始结点
    nodeQueue.push(node); // 初始结点进队

    int val = rootVal; // 当前结点值
    for (int i = 1; i < nodeCount;) // 结点从左到右循环
    {
        node = nodeQueue.front(); // 队头
        nodeQueue.pop(); // 出队

        val += elementInterval; // 计算左孩子值
        node->leftChild = new BinaryTreeNode<int>*(val); // 初始化左孩子
        nodeQueue.push(node->leftChild); // 左孩子进队
        i++;

        if (i < nodeCount)
        {
            val += elementInterval; // 计算右孩子值
            node->rightChild = new BinaryTreeNode<int>*(val); // 初始化右孩子
            nodeQueue.push(node->rightChild); // 右孩子进队
            i++;
        }
    }

    nodeQueue.clear();
    return btTree;
}

5.4 创建满二叉树 (Create Full Binary Tree)

// Author: https://blog.csdn.net/DarkRabbit
// Binary Tree
// 创建一个整型满二叉树
// params:
//      rootVal:                根节点值
//      depth:                  深度
//      elementInterval:        相邻结点数值间隔
// return:
//      BinaryTreeNode<int>*:   满二叉树
BinaryTreeNode<int>* CreateIntergerFullBinaryTree(const int rootVal,
                                                  const int depth,
                                                  const int elementInterval)
{
    if (depth < 1)
    {
        throw std::invalid_argument("`depth` is less than one.");
    }

    int nodeCount = std::exp2(depth) - 1; // 计算结点数量 = 2^h - 1
    return CreateIntergerCompleteBinaryTree(rootVal, nodeCount, elementInterval); // 返回完全二叉树
}

5.5 层序遍历 (Layer Traversal)

// Author: https://blog.csdn.net/DarkRabbit
// Binary Tree
// 层序遍历
template<typename T>
void LayerTraversal(BinaryTreeNode<T>* node, void(*pVisit)(BinaryTreeNode<T>&))
{
    if (node == 0)
    {
        return;
    }

    std::queue<BinaryTreeNode<T>*> nodeQueue; // 定义队列
    nodeQueue.push(node); // 加根结点

    BinaryTreeNode<T>* loopNode; // 定义结点
    while (!nodeQueue.empty()) // 每层从左向右取出结点
    {
        loopNode = nodeQueue.front(); // 取队头
        nodeQueue.pop(); // 出队

        (*pVisit)(*loopNode); // 访问结点 (V)

        if (loopNode->leftChild != 0)
        {
            nodeQueue.push(loopNode->leftChild); // 加入下一层左孩子
        }
        if (loopNode->rightChild != 0)
        {
            nodeQueue.push(loopNode->rightChild); // 加入下一层右孩子
        }
    }
}

5.6 非递归中序遍历 (Non-recursive Inorder Traversal)

// Author: https://blog.csdn.net/DarkRabbit
// Binary Tree
// 中序
template<typename T>
void InorderTraversal(BinaryTreeNode<T>* node, void(*pVisit)(BinaryTreeNode<T>&))
{
    if (node == 0)
    {
        return;
    }

    std::stack<BinaryTreeNode<T>*> nodeStack; // 定义结点栈
    BinaryTreeNode<T>* loopNode = node;

    do
    {
        while (loopNode != 0) // 左子树 (L)
        {
            nodeStack.push(loopNode);
            loopNode = loopNode->leftChild;
        }

        if (!nodeStack.empty())
        {
            loopNode = nodeStack.top(); // 取结点
            nodeStack.pop(); // 出栈
            (*pVisit)(*loopNode); // 访问结点 (V)
            loopNode = loopNode->rightChild; // 右子树 (R)
        }
    } while (loopNode != 0 || !nodeStack.empty());
}

5.7 非递归前序遍历 (Non-recursive Preorder Traversal)

// Author: https://blog.csdn.net/DarkRabbit
// Binary Tree
// 前序
template<typename T>
void PreorderTraversal(BinaryTreeNode<T>* node, void(*pVisit)(BinaryTreeNode<T>&))
{
    if (node == 0)
    {
        return;
    }

    std::stack<BinaryTreeNode<T>*> nodeStack;
    BinaryTreeNode<T>* loopNode = node;
    nodeStack.push(loopNode); // 入栈根结点
    
    while (!nodeStack.empty())
    {
        loopNode = nodeStack.top(); // 取结点
        nodeStack.pop(); // 出栈

        (*pVisit)(*loopNode); // 访问节点 (V)

        if (loopNode->rightChild != 0)
        {
            nodeStack.push(loopNode->rightChild); // 右子树 (R)
        }

        if (loopNode->leftChild != 0)
        {
            nodeStack.push(loopNode->leftChild); // 左子树 (L)
        }
    }
}

5.8 非递归后序遍历 (Non-recursive Postorder Traversal)

// Author: https://blog.csdn.net/DarkRabbit
// Binary Tree
// 后序
template<typename T>
void PostorderTraversal(BinaryTreeNode<T>* node, void(*pVisit)(BinaryTreeNode<T>&))
{
    if (node == 0)
    {
        return;
    }

    std::stack<BinaryTreeNode<T>*> nodeStack;
    std::stack<BinaryTreeNode<T>*> rightStack; // 已经向右走过的结点
    bool right = false; // 访问方向,是否走右子树
    BinaryTreeNode<T>* loopNode = node;

    do
    {
        if (!right)
        {
            while (loopNode != 0) // 左子树 (L)
            {
                nodeStack.push(loopNode);
                loopNode = loopNode->leftChild;
            }
        }

        if (!nodeStack.empty())
        {
            loopNode = nodeStack.top();

            if (loopNode->rightChild == 0) // 如果结点没有右子树
            {
                nodeStack.pop();
                (*pVisit)(*loopNode); // 访问结点 (V)
                right = true; // 双亲结点向右子树走
            }
            else if (!rightStack.empty() && loopNode == rightStack.top()) // 如果已经走过右子树
            {
                nodeStack.pop();
                rightStack.pop();
                (*pVisit)(*loopNode); // 访问结点 (V)
            }
            else // 右子树 (R)
            {
                rightStack.push(loopNode); // 已经走过右子树
                loopNode = loopNode->rightChild; 
                right = false; // 结点向左子树走
            }
        }

    } while (!nodeStack.empty());
}

6 主函数与测试 (Main Method and Testing)

二叉树代码较多,以上已给出主要代码,其它代码省略;

二叉排序树(二叉搜索树,二叉查找树)在以后说明;

以下只是主函数。

6.1 主函数 (Main Method)

// Author: https://blog.csdn.net/DarkRabbit
// Binary Tree
// Binary Search Tree

#include <typeinfo>
#include <string>
#include <vector>
#include <unordered_map>

#include "binary_tree.h"
#include "binary_search_tree.h"
#include "binary_tree_factory.h"

#include <iomanip>
#include <iostream>

using namespace std;
using namespace BinaryTrees;

unordered_map<int, string> enum2str = 
{
    {0, "层序"},
    {1, "前序"},
    {2, "后序"},
    {3, "中序"},
    {4, "中序镜像"},
    {5, "前序镜像"},
    {6, "后序镜像"}
};

// 打印二叉树的遍历
void PrintBinaryTree(BinaryTree<int>& tree)
{
    for (int type = BTTraversalType::Normal; type <= BTTraversalType::PostorderMirror; type++)
    {
        cout << setiosflags(ios::left) << setw(12) << setfill(' ') << enum2str[type] << ":";
        for (BinaryTree<int>::Iterator it = tree.begin((BTTraversalType)type); it != tree.end(); it++)
        {
            cout << (char)((*it).GetElement()) << " ";
        }
        cout << endl;
    }
    cout << "元素数量:" << tree.GetCount() << endl;
    cout << "树的深度:" << tree.GetDepth() << endl;
    cout << endl;
}

int main()
{
    int rootVal = 'a';
    int nodeCount = 5;
    int interval = 1;
    int depth = 3;

    // 从 a-e 的完全二叉树
    BinaryTree<int>* cbtTree =  BinaryTreeFactory::CreateIntergerCompleteBinaryTree(rootVal, nodeCount, interval);
    cout << "完全二叉树[a, e]的遍历:" << endl;
    PrintBinaryTree(*cbtTree);

    // 从 f-l 的满二叉树
    BinaryTree<int> fbtTree;
    BinaryTreeFactory::InitializeIntergerFullBinaryTree(rootVal + nodeCount, depth, interval, fbtTree);
    cout << "满二叉树[f, l]的遍历:" << endl;
    PrintBinaryTree(fbtTree);

    // 创建头结点为 z ,左子树 cbtTree 和右子树 fbtTree,得到的二叉树
    BinaryTree<int> addTree = BinaryTree<int>('z', cbtTree, &fbtTree);
    cout << "合并二叉树的遍历:" << endl;
    PrintBinaryTree(addTree);

    // 二叉排序树,按数组顺序创建树
    vector<int> vals = { 'a', 'h', 'B','Y', 'z', 'g', 'T', 'b', 'X' };
    BinarySearchTree* bsTree = new BinarySearchTree(vals);
    bsTree->AddNode('U');
    cout << "二叉排序树的遍历,加入树顺序:a h B Y z g T b X U" << endl;
    cout << "(注:大写字母ASCII小于小写字母)" << endl;
    PrintBinaryTree(*bsTree);
    
    delete cbtTree;
    delete bsTree;

    //system("pause"); // VC++
    return 0;
}

6.2 打印结果 (Print Output)

完全二叉树[a, e]的遍历:
层序        :a b c d e
前序        :a b d e c
后序        :d e b c a
中序        :d b e a c
中序镜像    :c a e b d
前序镜像    :a c b e d
后序镜像    :c e d b a
元素数量:5
树的深度:3

满二叉树[f, l]的遍历:
层序        :f g h i j k l
前序        :f g i j h k l
后序        :i j g k l h f
中序        :i g j f k h l
中序镜像    :l h k f j g i
前序镜像    :f h l k g j i
后序镜像    :l k h j i g f
元素数量:7
树的深度:3

合并二叉树的遍历:
层序        :z a f b c g h d e i j k l
前序        :z a b d e c f g i j h k l
后序        :d e b c a i j g k l h f z
中序        :d b e a c z i g j f k h l
中序镜像    :l h k f j g i z c a e b d
前序镜像    :z f h l k g j i a c b e d
后序镜像    :l k h j i g f c e d b a z
元素数量:13
树的深度:4

二叉排序树的遍历,加入树顺序:a h B Y z g T b X U
(注:大写字母ASCII小于小写字母)
层序        :a B h Y g z T b X U
前序        :a B Y T X U h g b z
后序        :U X T Y B b g z h a
中序        :B T U X Y a b g h z
中序镜像    :z h g b a Y X U T B
前序镜像    :a h z g b B Y T X U
后序镜像    :z b g h U X T Y B a
元素数量:10
树的深度:6

请按任意键继续. . .


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值