当前位置:   article > 正文

恢复二叉树

恢复二叉树

恢复二叉树(已知中后序序列得到前序序列)

提示:本文研究的对象是已知中后序序列 还原二叉树 已知树的结构为递归型,可用递归方式创建树 可用递归方式遍历树 同样也可用递归方式还原树



前言

二叉树的遍历在数据结构中是一种非常常见的操作,已知两个遍历的序列(必须包含中序序列) 恢复二叉树是一个重点 也是一个难点 本文讨论已知中序和后序序列 恢复二叉树


提示:以下是本篇文章正文内容

一、恢复二叉树是什么?

通过给定的遍历序列 从遍历序列已知的遍历序列还原为原来的二叉树称为恢复二叉树,因树采用递归的方式创建 故也可采用递归的方式恢复二叉树

二、恢复步骤

1.给定已知的遍历序列

如下:
前:ABDGCEF
中:DGBAECF
后:GDBEFCA

2.读入数据

前:ABDGCEF
中:DGBAECF

3.实现思想和代码

以下完成已知先序和中序 还原整颗二叉树(C语言实现)
前序的根节点一定为根节点,在中序序列中找到根节点A的位置 左半边为左子树 左子树中序序列为 DGB 右半边为右子树 右子树中序序列为ECF 再依次类推 找到左右子树中序序列 回到先序序列 根据先序序列的特点 中序序列的节点在先序序列中出现的必为根节点 这样可以把一个大问题化为若干个子问题 逐一击破 最后再合并 刚好也符合递归的思想 以下给出实现的具体代码:

以下的所有操作均基于该二叉树,关于二叉树的其他基本操作,参考该文章

在还原二叉树之前需要熟悉二叉树的三种遍历 为下文的还原操作提供理论支持
讨论
前序遍历特点: 先根后左结点 再右结点 前序序列总是先输出第一个访问的结点
中序遍历特点:先访问左孩子 遇到左结点 遇到左结点为空再访问根结点 再访问右结点
后序遍历特点: 先访问左结点 左节点已访问或为空时访问右结点 又结点为空或被访问时访问根结点

参考:LeetCode官方视频(已知前序和后序恢复二叉树)
来自:LeetCode106从中序与后序遍历序列构造二叉树

以下是已知中后序 还原二叉树的算法

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<queue>
#include<stdlib.h>
using namespace std;
typedef struct BiTNode {
	char data;
	struct BiTNode *lchild;
	struct BiTNode *rchild;
}*BiTree;

//中后序恢复二叉树
BiTree buildTree(char inOrder[], char postOrder[], int inLeft,
                 int inRight, int postLeft, int postRight) {
	if (postLeft > postRight) {
		return NULL;
	}
	BiTree root = (BiTNode*)malloc(sizeof(BiTNode));
	root->data=postOrder[postRight]; //根节点赋值 
	int k = 0;	//记录中序根节点位置  接下来找中序根节点
	for (int i = inLeft; i <= inRight; i++) {
		if (inOrder[i] == postOrder[postRight]) {
			k = i;
			break;
		}
	}
	int numLeft = k-inLeft;	 
    root->lchild=buildTree(inOrder,postOrder,inLeft,k-1,postLeft,postLeft+numLeft-1);
    root->rchild=buildTree(inOrder,postOrder,k+1,inRight,postLeft+numLeft,postRight-1);
	return root;
}

//先序遍历
void preOrder(BiTree T){
	if(T){
		cout<<T->data<<" ";
		preOrder(T->lchild);
		preOrder(T->rchild); 
	}
} 

//后序递归遍历二叉树
void postOrder(BiTree T) {
	if(T) {
		postOrder(T->lchild);
		postOrder(T->rchild);
		cout<<T->data<<" ";
	}
}

int main() {
	char post[60]="GDBEFCA", in[60]="DGBAECF";
	/*
	//解除注释后可自行测试需要的数据 
	cin >> in;
	cin >> post;
	*/
	int inLeft = 0, postLeft = 0;
	int inRight = strlen(in)-1, postRight = strlen(post)-1;
	BiTree T = buildTree(in, post, inLeft, inRight, postLeft, postRight);
	cout<<"后序遍历"<<endl;
	postOrder(T);
	cout<<endl;
	cout<<"先序遍历"<<endl; 
	preOrder(T); 
	return 0;
}
/*
前:ABDGCEF
中:DGBAECF
后:GDBEFCA
试错笔记:
	int numLeft = k-inLeft;	 
    root->lchild=buildTree(inOrder,postOrder,inLeft,k-1,postLeft,postLeft+numLeft-1);
    root->rchild=buildTree(inOrder,postOrder,k+1,inRight,postLeft+numLeft,postRight-1);	 
*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

核心的思想以及难点在如下程序段中:
分析:先来简单分析一个 后序遍历的顺序是左右根 即一段后序序列中 最后一个节点一定是根节点 设置postRight用于记录最后一个节点 取后序最后一个节点作为根节点 再到中序序列中找到根节点 将中序序列切分为左右子树 再将左右子树继续分割 知道还原整颗二叉树 依此类推

算法中要注意的细节 当后序序列的postLeft(序列起始位置)>postRight(序列结束位置)时 即退出递归
另外 每次需要将后序遍历最后一个节点的data域赋值给root->data 用于记录数据
再设置好一个变量k用于记录中序序列中根节点的位置 作为以下递归切割子树的依据

BiTree buildTree(char inOrder[], char postOrder[], int inLeft,
                 int inRight, int postLeft, int postRight) {
	if (postLeft > postRight) {
		return NULL;
	}
	BiTree root = (BiTNode*)malloc(sizeof(BiTNode));
	root->data=postOrder[postRight]; //根节点赋值 
	cout<<root->data<<endl;
	int k = 0;	//记录中序根节点位置  接下来找中序根节点
	for (int i = inLeft; i <= inRight; i++) {
		if (inOrder[i] == postOrder[postRight]) {
			k = i;
			break;
		}
	}
	int numLeft = k-inLeft;	//定义该变量不可省略  省略以后会出错  思考为何该变量不可省略 
    root->lchild=buildTree(inOrder,postOrder,inLeft,k-1,postLeft,postLeft+numLeft-1);
    root->rchild=buildTree(inOrder,postOrder,k+1,inRight,postLeft+numLeft,postRight-1);
	return root;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/663473
推荐阅读
相关标签
  

闽ICP备14008679号