根据中序遍历和后序遍历重建二叉树

二叉树的重建

二叉树的重建方法:
一、根据前序加中序遍历重建二叉树
构造该二叉树的过程如下:
1. 根据前序序列的第一个元素建立根结点;
2. 在中序序列中找到该元素,确定根结点的左右子树的中序序列;
3. 在前序序列中确定左右子树的前序序列;
4. 由左子树的前序序列和中序序列建立左子树;
5. 由右子树的前序序列和中序序列建立右子树。
二、根据中序加后序遍历重建二叉树
构造该二叉树的过程如下:
1. 根据后序序列的最后一个元素建立根结点;
2. 在中序序列中找到该元素,确定根结点的左右子树的中序序列;
3. 在后序序列中确定左右子树的后序序列;
4. 由左子树的后序序列和中序序列建立左子树;
5. 由右子树的后序序列和中序序列建立右子树。
三、前序加后序
前序和后序在本质上都是将父节点与子结点进行分离,但并没有指明左子树和右子树的能力,因此得到这两个序列只能明确父子关系,而不能确定一个二叉树。
下面是一棵二叉树:
前序遍历:1 2 4 3 5 7 6 
中序遍历:2 4 1 5 7 3 6
后序遍历:4 2 7 5 6 3 1
前序+中序重建二叉树
#include<stdio.h>
#include<stdlib.h>

typedef struct node{
	int data;
	struct node *lchild,*rchild;
}bitree;

void rebuild(int *prelist,int *inlist,int n,bitree **t)
{
	if(!prelist || !inlist || n<=0 )		//空树 
		return;
	int i;
	
	//找到根结点在中序遍历中的位置 
	for(i = 0; i < n; i++)
	{
		if(inlist[i] == prelist[0])			
			break;					 
	} 
	
	if(i>=n)
		return;
	
	//初始化根结点 
	*t = (bitree*)malloc(sizeof(bitree));
	if(!t)
		return;
	(*t)->lchild = (*t)->rchild = NULL;
	(*t)->data = prelist[0];
	
	//重建左子树
	rebuild(prelist+1,inlist,i,&(*t)->lchild); 
	//重建右子树 
	rebuild(prelist+i+1,inlist+i+1,n-i-1,&(*t)->rchild);
}

void postOrderTraverse(bitree *t)
{	//	后序遍历 
	if(t)
	{
		postOrderTraverse(t->lchild);
		postOrderTraverse(t->rchild);
		printf("%d ",t->data);
	}
}

int main()
{
	int pre[] = {1,2,4,3,5,7,6};
	int in[] = {2,4,1,5,7,3,6};
	
	bitree *t = NULL;
	rebuild(pre,in,7,&t); 
	postOrderTraverse(t);
	
	return 0;
} 

 
中序+后序重建二叉树:
void rebuild(int *inlist,int *postlist,int n,bitree **t)
{
	if(!inlist || !postlist || n<=0 )		//空树 
		return;
	int i;
	
	//找到根结点在中序遍历中的位置 
	for(i = 0; i < n; i++)
	{
		if(inlist[i] == postlist[n-1])			
			break;					 
	} 
	
	if(i>=n)
		return;
	
	//初始化根结点 
	*t = (bitree*)malloc(sizeof(bitree));
	if(!t)
		return;
	(*t)->lchild = (*t)->rchild = NULL;
	(*t)->data = postlist[n-1];
	
			
	//重建左子树	
	rebuild(inlist,postlist,i,&(*t)->lchild); 				
	//重建右子树 
	rebuild(inlist+i+1,postlist+i,n-i-1,&(*t)->rchild);			//post+i 
}

====2023.1.28更新====

剑指offer07. 重建二叉树

#include<iostream>
#include<vector>
#include<stack>
using namespace std;

struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
		if (preorder.size() == 0 || inorder.size() == 0) {
			return NULL;
		}	
		TreeNode *root = new TreeNode(preorder[0]);
		int i = 0;
		for ( ; i < inorder.size(); i++) {
			if (preorder[0] == inorder[i]) {
				break;
			}
		}
		vector<int> leftPre(preorder.begin()+1,preorder.begin()+i+1);
		vector<int> rightPre(preorder.begin()+i+1,preorder.end());
		vector<int> leftIn(inorder.begin(),inorder.begin()+i);
		vector<int> rightIn(inorder.begin()+i+1,inorder.end());
		root->left = buildTree(leftPre,leftIn);
		root->right = buildTree(rightPre,rightIn);
		return root;
    }
};

void preOrderTraverse(TreeNode *root) {
	if (root == NULL) {
		return;
	}
	stack<TreeNode*> stk;
	stk.push(root);
	vector<int> ans;
	
	while (!stk.empty()) {
		root = stk.top();
		stk.pop();
		if (root) {
			if (root->right) {
				stk.push(root->right);
			}
			if (root->left) {
				stk.push(root->left);
			}
			stk.push(root);
			stk.push(NULL);
		} else {
			root = stk.top();
			ans.push_back(root->val);
			if (!stk.empty()) {
				stk.pop();
			}
		}
	}
	for (int &x : ans) {
		cout << x << " ";
	}
	cout << endl;
}

int main() {
	vector<int> nums = {3,9,20,-1,-1,15,7};
	int n = nums.size();
	
	// 1.构建二叉树 
	vector<TreeNode*> tree(n,NULL);
	tree[0] = new TreeNode(nums[0]);
	
	for (int i = 1; i < n; i++) {
		if (nums[i] == -1) {
			continue;
		}
		int parent = (i%2) ? i/2 : i/2-1; 
		tree[i] = new TreeNode(nums[i]);
		if (i % 2) {
			tree[parent]->left = tree[i];
		} else {
			tree[parent]->right = tree[i];
		}
	}
	// 2.二叉树的先序遍历 
	preOrderTraverse(tree[0]);
	
	cout << "====rebuild====" << endl;
	// 3.重建二叉树 
	vector<int> preorder = {3,9,20,15,7};
	vector<int> inorder = {9,3,15,20,7};
	
	Solution s;
	TreeNode *root = s.buildTree(preorder, inorder);
	preOrderTraverse(root);
	return 0;
}

  • 10
    点赞
  • 83
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值