22计算机408考研—数据结构—二叉树根据中序遍历,后序遍历构建二叉树,并输出前序遍历

177 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第24天,点击查看活动详情

手把手教学考研大纲范围内树定义,遍历,Huffman,并查集 22考研大纲数据结构要求的是C/C++,笔者以前使用的都是Java,对于C++还很欠缺, 如有什么建议或者不足欢迎大佬评论区或者私信指出 初心是用最简单的语言描述数据结构

Talk is cheap. Show me the code. 理论到处都有,代码加例题自己练习才能真的学会

二叉树根据中序遍历,后序遍历构建二叉树,并输出前序遍历

​ 中序遍历:相对根结点的位置,左面是当前根结点左子树的结点,右面是当前根结点的右子树的结点

​ 后序遍历:相对子树的根结点在相对左右子结点靠后的位置,相对根结点都靠后

思路:

​ 从后序遍历后面找到根结点,

​ 在中序遍历找到根结点,根结点左面就是根结点左子树的结点,右面就是根结点右子树的结点

​ 然后继续在后序遍历找下一个根结点(右子树的根结点),在上面的右子树的结点中找右子树的根结点,

​ 继续这种循环,直到右子树的结点为空,返回上一层

​ 如果上面右子树不存在,那么右子树的结点也是不存在的,直接返回上一层了

​ 左子树也是,在后序遍历找上一个根结点(刚才的右结点都找完了现在才会是左结点),在上面左子树结点找左子树的根结点

​ 继续循环

思路简化:

后序遍历是后面的都是根结点,后序遍历是根结点的从后向前排序

根据后序遍历的根结点,在中序遍历找到根结点位置,

中序遍历中:根结点左面是根结点的左子树的结点,根结点的右面是根结点的右子树的结点

继续找下一个根结点,在右子树结点里找新的根结点,
(如果右子树结点不存在,那么新的根结点就是原根的左结点,就是在左子树结点里找新的根结点)		
	
如果右子树结点或者左子树结点不存在返回上一级

不断循环这个过程

思路图解:

例子:	
    3
   / \
  9  20
    /  \
   15   7
	 
中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]

1、初始状态:

img

2、先从后序遍历中找到根结点,在中序遍历找到根结点,

img

3、中序遍历中根结点右面是右子树结点

img

4、中序遍历中根结点右面是右子树结点

img

5、中序遍历中根结点左面是左子树结点

img

6、当前根结点的左子树右子树都遍历完了,返回上一层,遍历上一层的左子树结点

img

7、构建完成

img

代码+注释

 //根据前序遍历和中序遍历构建二叉树,求出后序遍历
#include "iostream"
#include "math.h"
#include "queue"
#define MAXSize 100

using namespace std;

int mid[MAXSize];
int post[MAXSize];

typedef struct TreeNode{    //树的结构体
    int data;
    struct TreeNode *left;
    struct TreeNode *right;
} TreeNode, *Tree;
//创建二叉树                     //中序遍历的范围midStart-midEnd       后序遍历的范围postStrat - postEnd
Tree createTree(int midStart, int midEnd, int postStart, int postEnd) { //范围都是包括左边不包括右边(包括起始点不包括终止点)
    if (postStart >= postEnd || midStart >= midEnd) {   //起始点大于等于终止点,范围即为空,返回空
        return NULL;
    }
    Tree root = new TreeNode;
    root->data = post[postEnd - 1]; //后序遍历最后一个就是根结点(后序遍历,遍历顺序为:左结点,右结点,根结点)
    int i;
    for (i = midStart; i < midEnd; ++i) {   //在中序遍历中找到根结点下标 i
        if (mid[i] == post[postEnd - 1]) {      //i左边范围就是左子树结点,i右面范围就是右子树结点
            break;                                  //(中序遍历的顺序:左子树,根结点,右子树)  (根结点以左就是左子树结点,以右就是右子树结点)
        }
    }
        //后序遍历 要先找右子结点(后序遍历中,根结点前面是右子树,所以先找右子结点)
            //中序遍历中右子树的范围:根结点在中序遍历的位置以右,到这段中序范围的结束
            //后序遍历中右子树的范围:根结点在后序遍历中是最后一位,所以右子树后序遍历的结束范围是到当前后序范围终止点的前一位
                               //根结点的起始点是 终止点向前走  右子树数量个位置   (midEnd - i - 1)
                                    //midend - i 是中序遍历中根结点到末尾的数量(范围不包括末尾)   -1 是因为右子树不能包括根结点,要把根结点删除
                                    	//也可以理解为,右子树结点的数量为midEnd-(i+1)  后序列遍历的范围是postEnd - 1  向前走右子树结点的数量位
    root->right = createTree(i + 1, midEnd, postEnd - 1 - (midEnd - i - 1) , postEnd - 1);
            //中序遍历中左子树的范围:中序遍历开始位置 到 根结点位置 i (不包括根结点)
            //后序遍历中左子树的范围: 后序遍历起始位置 到 右子树以前    都是左子树的结点范围
    root->left = createTree(midStart, i,postStart , postEnd - 1 - (midEnd - i - 1) );
    return root;
}

//后序遍历
void preOrderPrintTree (Tree tree) {
    if (tree == NULL) return;
    cout << tree->data << " ";
    preOrderPrintTree(tree->left);
    preOrderPrintTree(tree->right);
}

//返回二叉树的深度(递归)
int Depth (Tree tree) {
    if (tree == NULL) {
        return 0;
    }
    return max(Depth(tree->left), Depth(tree->right)) + 1;    //找左或右结点的最大深度 + 1(加一是加上当前这一层)
    //不断循环这种操作
}

//格式化输出二叉树(直接看顺序存储的注释就可以,格式化输出就是找二叉树的规律)
void treePrint(Tree tree) { //与顺序打印二叉树基本相似(如果结点为空的时候,要创建一个0结点,给0结点的左右结点都附空)
    cout << "打印二叉树:\n";
    int depth = Depth(tree);
    queue<Tree> q;
    q.push(tree);
    for (int i = 0; i < depth; i++) {
        int space = 0;
        for (int j = 0; j < depth - 1 - i; j++) {
            space = space * 2 + 1;
        }
        for (int j = 0; j < space; j++) {
            cout << " ";