1020 Tree Traversals

Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder and inorder traversal sequences, you are supposed to output the level order traversal sequence of the corresponding binary tree.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (≤30), the total number of nodes in the binary tree. The second line gives the postorder sequence and the third line gives the inorder sequence. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print in one line the level order traversal sequence of the corresponding binary tree. All the numbers in a line must be separated by exactly one space, and there must be no extra space at the end of the line.

Sample Input:

7
2 3 1 5 7 6 4
1 2 3 4 5 6 7

Sample Output:

4 1 6 3 5 7 2

假设二叉树中的所有键都是不同的正整数。给定后序和中序遍历序列,您应该输出相应二叉树的级序遍历序列。(inorder 是中间的意思,inorder sequence中序) 

输入规范:

每个输入文件包含一个测试用例。对于每种情况,第一行给出一个正整数N(≤30),即二叉树中的节点总数。第二行给出了后序序列,第三行给出了中序序列。一行中的所有数字都用空格隔开。

输出规格:

对于每个测试用例,在一行中打印相应二叉树的级别顺序遍历序列。一行中的所有数字必须正好用一个空格分隔,并且在行的末尾不能有多余的空格。

(级别顺序是层序的意思,也就相当于广度优先的顺序,不是前序!)

不太了解树的建议先看看这个

https://blog.csdn.net/ASBSIHD/article/details/130374198?spm=1001.2014.3001.5502

解题过程

#include
#include
#include
#include
#include
#include

using namespace std;

int n;
int postorder[50];
int inorder[50];

struct Node
{
	int data;
	Node* lchild;
	Node* rchild;//自己调用当前的结构体,目的就是为了继承更多的数据
};

Node* create(int postL, int postR, int inL,int inR)
{
	if (postL > postR)
	{
		return NULL;
	}

	Node* root = new Node;
	root->data = postorder[postR];

	int i;
	for (i = inL; i <= inR; i++)
	{
		if (inorder[i] == postorder[postR])
			break;
	}

	int leftnum = i - inL;

	root->lchild = create(postL, postL + leftnum - 1, inL, i - 1);
	root->rchild = create(postL + leftnum, postR - 1, i + 1, inR);

	
	return root;
}

int num = 0;
void levelorder(Node* root)
{
	queueq;
	q.push(root);

	while (!q.empty())
	{
		Node* now = q.front();
		q.pop();
		cout << now->data;
		num++;
		if (num < n)
			cout << " ";
		if (now->lchild != NULL)
			q.push(now->lchild);
		if (now->rchild != NULL)
			q.push(now->rchild);

	}
}


int main()
{
	
	cin >> n;
	for (int i = 0; i < n; i++)
		cin >> postorder[i];
	for (int i = 0; i < n; i++)
		cin >> inorder[i];

	Node* root=create(0, n - 1, 0, n - 1);

	levelorder(root);

	return 0;
}

详解

#include 
#include 
#include 
#include 

using namespace std;

struct Node {
    int data;//储存数据
    Node* lchild;//child起到连接左/右子树的作用,分别将两边的树都连接起来,是左右树的节点
    Node* rchild;
}node;
//这里可以用这个名字代替Node*,就跟java的效果一样
//作为一个node类型

const int maxn = 50;

int postorder[maxn], inorder[maxn];
int n; //!!!

//本质上就是自己理解如何通过后序中序来确定树的结构
//后序确定根,中序确定左右孩子,可以先自己手画出树的结构
//清晰逻辑后再通过代码实现
 //总的核心就是参照视频中的理解,如何构造树,然后使用DFS和指针连接起来即可
// 根据树的构造编写代码

//中序分化左右子树,后序确定根节点

//当我们将它看作为根的时候存放数据,看作为左右孩子的时候起到连接各个节点的作用
//目的就是为了输出,即输出根节点内容后往下面的孩子找,然后继续输出。


//          后序最左边开始 最右边      中序  左边   右边           ,此处都表示左右边界
Node* create(int postL, int postR, int inL, int inR) //创造一棵树
{
    if (postL > postR) //当前根节点已经没有对应的孩子时,即左/右节点已经没有时
    {
        return NULL; 
    }
   
    //寻找并插入节点

    Node* root = new Node;  //!!!没初始化
    //每次都新建一个Node储存数据
    //最后return到一个root中,就将他们连接起来了

    root->data = postorder[postR];   //通过后序规律,找到根节点    

    int i;//表示当前根节点的位置
    for (i = inL; i <= inR; i++) {//寻找根节点在中序的位置,从而寻找左孩子/右孩子
        if (inorder[i] == postorder[postR]) {//!!!!
            break;
        }
    }


    int leftNum = i - inL;//当前根节点的左边节点的个数

    
   
    
 //选定节点范围
    //优先寻找左子树,然后找右
    //注意这些减和加都是相当于往左/右移动,来确定左/右子树的节点范围
//一直都在寻找的是下标


                         //后序新树根节点选定范围       中序左/右子节点范围
    root->lchild = create(postL, postL + leftNum - 1, inL, i - 1);  //左子树
    //postL + leftNum - 1,因为左右根,上面求出左边节点的个数,那我们只要确定规则和个数
    // 就能锁定后序中的所求根节点的范围在哪,-1是因为下标从0开始
    // 
    // 左边的所有节点都可能为根节点,需要下一次进一步判断.
    
    //注意,位置都是在对应的树下的下标
    
    //i-1表示根节点左边,在中序中左边都是作为当前根的孩子
   


    //右子树,一旦没了左孩子,就去找当前节点的右孩子(符合左根右原则)
    root->rchild = create(postL + leftNum, postR - 1, i + 1, inR);
    //中序开始向右边遍历
    //与左子树类似.
    //postR-1就是沿着当前当前根节点找右孩子,此时根的左孩子没有,只有右孩子,
    //右孩子仍然存在,所以下一个节点仍然是作为新树的根,后序顺序左右根,所以当前根的左边一位就是新树的根节点
    //i+1是往右边找,因为此时根节点没有了左孩子,左根右,所以此时在中序中的节点范围只能是在根节点的右边,所以加一

 /*   postL + leftNum - 1与postR - 1有什么不同?*/
    //目标是不同的,前面是一直在找左子树,而后面是转向为右子树,找的都是右节点的范围,是不一样的
    //postR是范围右侧的边界,在后序中是根,去掉当前根就减一即可
    
    //如postL + leftNum就是当前左边界加上左子树节点的个数,就相当于排除了左节点,只选择右节点
    //因为后序是左右根,所以直接加就能移动到右节点

    //inL和inR意思就是继承上一个树的结果,不做任何变化,也就是不动,包括postR等也都是,使用的时候都是继承的
    //都是上一次的结果,直接拿来用就行了.


    


    return root;    //返回节点,将所有的节点连接起来
}

//层次遍历
int num = 0;    //!!!已经输出的节点个数
void levelorder(Node* root) //BFS
//root只能上传开头的节点,也就是头节点,然后输出,但是头结点的孩子就是lchild与rchild
//now节点就是接收了root的内容,然后孩子再往下遍历
{
    queue q;
    q.push(root);

    while (!q.empty()) {
        Node* now = q.front();
        q.pop();    //弹出
        printf("%d", now->data);
        num++;
        if (num < n) cout << " ";
        if (now->lchild != NULL) {//从左到右插入队列,然后循环输出
            q.push(now->lchild);//now指针变更指向孩子,也就是更新节点信息,往下遍历
        }
        if (now->rchild != NULL) {
            q.push(now->rchild);
        }
    }
}

int main()
{

    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> postorder[i];
    }
    for (int i = 0; i < n; i++) {
        cin >> inorder[i];
    }


    Node* root1 = create(0, n - 1, 0, n - 1);   //!!!

    levelorder(root1);
    return 0;
}

//反思,写程序如果没有特殊情况,那么只用把一个步骤想清楚写好就可以了
//剩下的重复操作交给递归,循环,不用理解的太透彻,交给计算机计算就行了

  

 

你可能感兴趣的:(c++)