P1030 求先序排列

根据给定的二叉树中序和后序遍历,可以通过递归算法构造出二叉树并输出其先序遍历。首先,从后序遍历的最后一个节点找到根节点,然后在中序遍历中确定根节点的位置,以此划分左右子树,再分别对左右子树进行相同的操作。
摘要由CSDN通过智能技术生成

本题来源于洛谷,题目要求根据一颗二叉树的中序后序遍历,输出二叉树的先序遍历。

题目描述

给出一棵二叉树的中序与后序排列。求出它的先序排列。(约定树结点用不同的大写字母表示,且二叉树的节点个数 ≤ 8 \le 8 8)。

输入格式

共两行,均为大写字母组成的字符串,表示一棵二叉树的中序与后序排列。

输出格式

共一行一个字符串,表示一棵二叉树的先序。

解题思路

树是一种具有递归定义的数据结构,也可以看成一个无环图。
下面将介绍两种写法:

  • 在递归过程中直接输出先序遍历
  • 根据中序和后序遍历构造一棵二叉树,然后使用深度优先搜索遍历出二叉树的先序遍历(主要是有的题目不会直接让我们求先序遍历,而是先构造出二叉树,然后再进行别的操作)

思考过程

中序遍历二叉树的顺序:

  1. 遍历左子树
  2. 遍历根节点
  3. 遍历右子树

后序遍历二叉树的顺序:
4. 遍历左子树
5. 遍历右子树
6. 遍历根节点

所以我可以确定,后序遍历的最后一个节点一定是整个二叉树的根节点,所以根据这个根节点的在中序遍历中的位置,将中序遍历分为这个根节点的左子树和右子树。
递归的有,我们依次根据后序遍历重复上述过程,最终可以得到二叉树的前序遍历。
步骤:

  1. 找根节点
  2. 确定根节点在中序遍历中的位置
  3. 递归的求左子树
  4. 递归的求右子树

需要注意的一点,这个是二叉树的知识,我们每一轮是针对一个节点来说的,它的左子树和右子树在前序遍历和后序遍历中的节点数量是一致的

方法一:

#include <iostream>
#include <string>

using std::cin;
using std::ios;
using std::cout;
using std::endl;
using std::string;

void printPreorder(string, string);

int main(int argc, char **argv){
	ios::sync_with_stdio(false);
	string inorder;
	string postorder;
	
	cin >> inorder;
	cin >> postorder;
	
	printPreorder(inorder, postorder);
	return 0;
}

void printPreorder(string inorder, string postorder){
	if(postorder.length() <= 0){
		return;
	}
	char root = postorder[postorder.length() - 1];
	cout << root;
	int pos = inorder.find(root);
	printPreorder(inorder.substr(0, pos), postorder.substr(0, pos));
	printPreorder(inorder.substr(pos+1), postorder.substr(pos, inorder.length() - pos - 1));
}

方法二

和方法一思路基本是一样的:

  1. 根据后序遍历找根节点
  2. 在中序遍历中找根节点的位置
  3. 构造根节点
  4. 递归构造该节点的左子树
  5. 递归构造该节点的右子树
  6. 返回根节点
#include <iostream>
#include <string>

using std::cin;
using std::ios;
using std::cout;
using std::endl;
using std::string;

typedef struct Node{
	char value_;
	Node *right_;
	Node *left_;
	Node(char, Node*, Node*);
	
	~Node();
}Node;

Node::Node(char value, Node *right = nullptr, Node *left = nullptr){
	value_ = value;
	right_ = right;
	left_ = left;
}

Node::~Node(){
	if(right_ != nullptr){
		delete right_;
		right_ = nullptr;
	}
	if(left_ != nullptr){
		delete left_;
		left_ = nullptr;
	}
}

Node* build(const string&, const string&);
void preTraverse(Node*);

int main(int argc, char **argv){
	ios::sync_with_stdio(false);
	string inorder;
	string postorder;
	
	cin >> inorder;
	cin >> postorder;
	
	Node *root = build(inorder, postorder);
	preTraverse(root);
	return 0;
}

Node* build(const string& inorder, const string& postorder){
	if(postorder.length() <= 0){
		return nullptr;
	}
	char r = postorder[postorder.length() - 1];
	int pos = inorder.find(r);
	Node *root = new Node(r);
	//构造左子树
	root->left_ = build(inorder.substr(0, pos), postorder.substr(0, pos));
	//构造右子树
	root->right_ = build(inorder.substr(pos+1), postorder.substr(pos, inorder.length() - pos - 1));
	return root;
}

void preTraverse(Node* root){
	if(root == nullptr){
		return;
	}
	cout << root->value_;
	preTraverse(root->left_);
	preTraverse(root->right_);
}

做完这题可以尝试一下 UVA548

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值