欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【算法导论】 二叉树的重构

程序员文章站 2022-05-06 21:26:31
...

    二叉树的重构是指通过二叉树的遍历结果得到二叉树的构造。

    重构方案:    前序遍历(  PreOrder) + 中序遍历(InOrder)
                         后序遍历(PostOrder) + 中序遍历(InOrder)
                         前序遍历(  PreOrder) + 后续遍历(PostOrder)(只对真二叉树成立)


前序遍历+后序遍历:

    对于一颗二叉树,  其前序遍历可表示为: Root LeftTree + RightTree
                                  中序遍历可表示为: LeftTree + RootRightTree

    前序遍历的第一个结果为根节点,通过查找可确定中序遍历中根节点的位置,则可确定左子树和右子树中序遍历下的结果。确定左子树和右子树节点数量,则可确定左子树和右子树前序遍历下的结果。得到左右子树中序和前序遍历结果,则可递归的构造出二叉树。

【算法导论】 二叉树的重构

(下面程序以此作为实例对二叉树进行重构)

#include<stdio.h>

/** BinaryTree DS */
typedef struct BinaryTree
{
	int key;
	BinaryTree *lson;
	BinaryTree *rson;
}BinaryTree;

/** find a key in array A */
int Array_Find( int *A, int begin, int end, int key)
{
	for( int i=begin; i<end; i++) {
		if( key == A[i]) return i;
	}
	
	return -1;
}

/** 重构二叉树, 参数: PreOrder[pbegin ... pend]
  *                     InOrder[ibegin ... iend]
  */
BinaryTree *GetBinaryTree( int *PreOrder, int pbegin, int pend, 
                           int  *InOrder, int ibegin, int iend)
{
	if( pbegin>=pend || ibegin>=iend) return NULL;   // 出口, 无节点情况
	
	BinaryTree *Root = new BinaryTree;         // 分配在堆上, 函数结束时不会消失
	*Root = { PreOrder[pbegin], NULL, NULL};   // 构造根节点
	
	int r = Array_Find( InOrder, ibegin, iend, PreOrder[pbegin]);  // root's position in InOrder
	
	// 确定左子树、右子树 前序、中序遍历结果, 递归求解 */
	Root->lson = GetBinaryTree( PreOrder, pbegin+1, (r-ibegin)+pbegin+1, InOrder, ibegin, r);
	Root->rson = GetBinaryTree( PreOrder, (r-ibegin)+pbegin+1, pend, InOrder, r+1, iend);
	
	return Root;
}

/** 中序遍历 */
void Tree_Print( BinaryTree *Root)    
{
    if( Root==NULL) return;    
  
    printf( "key:   %d\n", Root->key);      //visit tree
    if( Root->lson !=NULL) printf( "lson:  %d\n", Root->lson->key);
    if( Root->rson !=NULL) printf( "rson:  %d\n", Root->rson->key);
	printf( "\n\n");
	
    Tree_Print( Root->lson);    
    Tree_Print( Root->rson);    
}

int main()
{
	int PreOrder[] = { 43, 12, 8, 32, 16, 35, 78, 56, 88, 83, 121, 97};
	int  InOrder[] = { 8, 12, 16, 32, 35, 43, 56, 78, 83, 88, 97, 121};
	
	BinaryTree *Root = GetBinaryTree( PreOrder, 0, 12, InOrder, 0, 12);
	Tree_Print( Root);
	
	return 0;
}

前序遍历+后序遍历:

    真二叉树( Proper Binary Tree) : 所有节点出度为0或2的二叉树,即左子树右子树皆空或皆非空的二叉树。

    真二叉树定义来自邓俊辉教授的慕课,国外称为 满二叉树(Full Binary Tree),注意和国内教材中的满二叉树区别。

    因为当某节点只有一颗子树时,前序遍历结果为 Root + SonTree,后序遍历结果为 SonTree + Root。通过前序遍历和后序遍历无法确定SonTree为左子树和右子树,因此不能还原这种二叉树的结构。

    对于真二叉树来说,前序遍历可表示为: Root + LeftTreeRoot + LeftTree  RightTreeRoot + RightTree 

                                  后续遍历可表示为:  LeftTree + LeftTreeRoot  RightTree + RightTreeRoot + Root

    可通过前序遍历确定左子树根节点,通过后序遍历确定右子树根节点,从而确定左右子树前序、后续遍历结果,递归求得二叉树结构。

根据前序、后序判断是否为真二叉树:

    若节点左子树为空,前序遍历前两个节点为 根节点 + 左子树根节点;后序遍历后两个节点为 根节点 + 左子树根节点;两者结果相同,右子树同上。若节点左右子树全为空 或 全不为空,都不会出现节点逆序相同情况。则可通过递归依次判断节点是否为真二叉树。

    下面code忽略了判断是否为真二叉树,当节点只有一颗子树时,都当做左子树进行处理。

/** 重构二叉树, 参数:  PreOrder[pbegin ... pend] 
  *                    PostOrder[tbegin ... tend] 
  */  
BinaryTree *GetBinaryTree( int  *PreOrder, int pbegin, int pend,  
                           int *PostOrder, int tbegin, int tend)  
{  
    if( pbegin>=pend || tbegin>=tend) return NULL;   // 出口, 无节点情况  
      
    BinaryTree *Root = new BinaryTree;         // 分配在堆上, 函数结束时不会消失  
    *Root = { PreOrder[pbegin], NULL, NULL};   // 构造根节点  
      
    if( pbegin+1==pend) return Root;   // 不存在左右子树情况  
    int lr = Array_Find( PostOrder, tbegin, tend, PreOrder[pbegin+1]); // leftsonRoot position in PostOrder
      
    // 确定左子树、右子树 前序、中序遍历结果, 递归求解 */  
    Root->lson = GetBinaryTree( PreOrder, pbegin+1, (lr+1-tbegin)+pbegin+1, PostOrder, tbegin, lr+1);  
    Root->rson = GetBinaryTree( PreOrder, (lr+1-tbegin)+pbegin+1, pend, PostOrder, lr+1, tend-1);  
      
    return Root;  
}
  
/** 中序遍历 */  
void Tree_Print( BinaryTree *Root)      
{  
    if( Root==NULL) return;      
    
    printf( "key:   %d\n", Root->key);      //visit tree  
    if( Root->lson !=NULL) printf( "lson:  %d\n", Root->lson->key);  
    if( Root->rson !=NULL) printf( "rson:  %d\n", Root->rson->key);  
    printf( "\n\n");  
      
    Tree_Print( Root->lson);      
    Tree_Print( Root->rson);      
}