[C++日常小题] 计算二叉查找树的高度

Description

给定一个二叉查找树,要求计算其高度,每个二叉查找树将给出先序与中序的遍历。

例如:一个二叉查找树其先序遍历为:16, 10, 4, 15, 23 ; 中序遍历为 4, 10, 15, 16, 23,则其高度为2(假定空树高度为-1,只有根节点的数高度为0)

Input

第一行输入测试用例个数。

对于每个测试用例,

第一行是节点个数n,第二行是key值的先序遍历,第三行是key值的中序遍历

Output

对于每个测试用例,用一行输出树的高度

Sample Input

2
3
4 5 6
4 5 6
5
6 4 8 9 10
4 6 8 9 10

Sample Output

2
3

解题思路

首先,根据二叉树的遍历特性

  • 先序遍历: 首先访问根结点然后遍历左子树,最后遍历右子树。在遍历左、右子树时,仍然先访问根结点,然后遍历左子树,最后遍历右子树,如果二叉树为空则返回。
  • 中序遍历: 首先遍历左子树,然后访问根结点,最后遍历右子树。在遍历左、右子树时,仍然先遍历左子树,再访问根结点,最后遍历右子树。

可以推出,先序遍历的第一个元素就为二叉树的根结点。
又在中序遍历中,若找到根节点,则根节点左侧的为其左子树结点,右侧的为其右子树结点。

为了更方便阐述,设几个变量

  • root: 当前根结点在先序遍历中的下标
  • pos: 当前根结点在中序遍历中的下标
  • left: 根树或子树的所有结点在中序遍历中的下标范围的左边界
  • right: 根树或子树的所有结点在中序遍历中的下标范围的右边界(结点不包括右边界)

若根结点有左子树,则先序遍历中下标为 root + 1 的结点为其左子树的根结点,[left, pos) 为其左子树的所有结点。
当前根结点在先序遍历中下标为 root + pos - left + 1 的结点为右子树的根结点,[pos + 1, right) 为其右子树的所有结点。

知道了左子树和右子树的元素,并且找到了两个子树的根结点,通过同样的方法,在左右子树中分别再找其左右子树,这样递归下去,可以确定唯一的二叉树。
这道题只要求出树的高度,那么我们可以认为,若一个树有左子树或者右子树,则树的高度 + 1。

上面的描述可能不是很准确,举个例子更清楚一点,一棵有9个结点的二叉树

《[C++日常小题] 计算二叉查找树的高度》

  • 先序遍历: 5 2 1 4 3 8 7 6 9
  • 中序遍历: 1 2 3 4 5 6 7 8 9

根树

  • root = 0;
  • pos = 4;
  • left = 0;
  • right = 9;

根结点为 5;
左子树的根结点为 2先序遍历中下标为 root + 1 = 1;所有结点为 1 2 3 4中序遍历中下标范围为 [0, 4)
右子树的根结点为 8先序遍历中下标为 root + pos - left + 1 = 5;所有结点为 6 7 8 9中序遍历中下标范围为 [5, 9)

根树的左子树

  • root = 1;
  • pos = 1;
  • left = 0;
  • right = 4;

根结点为 2;
左子树的左子树的根结点为 1先序遍历中下标为 root + 1 = 2;所有结点为 1中序遍历中下标范围为 [0, 1)
左子树的右子树的根结点为 4先序遍历中下标为 root + pos - left + 1 = 3;所有结点为 3 4中序遍历中下标范围为 [2, 4)

根树的右左子树

  • root = 5;
  • pos = 7;
  • left = 5;
  • right = 9;

根结点为 8;
左子树的左子树的根结点为 7先序遍历中下标为 root + 1 = 6;所有结点为 6 7中序遍历中下标范围为 [5, 7)
左子树的右子树的根结点为 9先序遍历中下标为 root + pos - left + 1 = 8;所有结点为 9中序遍历中下标范围为 [8, 9)

左子树的左子树和右子树,右子树的左子树和右子树同理递归下去,就不再继续列出来了。

Code

#include <cstdio>

int preorder[1000001];  // 先序遍历
int inorder[1000001];  // 中序遍历
int height = 0;  // 树的高度

void findHeight(int root, int left, int right, int h);
int main() {
    int t, n;
    scanf("%d", &t);
    while (t--) {
        height = -1;
        scanf("%d", &n);

        for (int i = 0; i < n; ++i)
            scanf("%d", preorder + i);

        for (int i = 0; i < n; ++i)
            scanf("%d", inorder + i);

        findHeight(0, 0, n, 0);
        printf("%d\n", height);
    }
    return 0;
}
void findHeight(int root, int left, int right, int h) {
    if (left >= right) return;  // 判断是否为空树
    int pivot = preorder[root];
    int pos = left;

    if (h > height) height = h;  // 更新树的高度
    while (pos < right && inorder[pos] != pivot) pos++;  // 找根结点在中序遍历中的下标

    // 递归遍历左子树
    if (left < pos) findHeight(root + 1, left, pos, h + 1);

    // 递归遍历右子树
    if (pos + 1 < right) findHeight(root + pos - left + 1, pos + 1, right, h + 1);
}

以上所有,如有错误,麻烦指出,我会及时更改的。

    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/elliott_yoho/article/details/53965046
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞