剑指offer:重建二叉树(C语言)

题目:输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中不包含重复的数字。

二叉树节点的定义如下:

#include<stdio.h>
#include<stdlib.h>
//二叉树结构的定义
typedef struct BinaryTreeNode{
	int m_nValue;
	struct BinaryTreeNode *m_pLeft;
	struct BinaryTreeNode *m_pRight;
}BinaryTreeNode;

//构建二叉树的核心函数,前序的子串起止位置和中序的子串起止位置
BinaryTreeNode * ConstructCore(int *startPreorder, int *endPreorder, int *startInorder, int *endInorder);

//构建二叉树的函数,前序遍历和中序遍历的起始位置与长度
BinaryTreeNode *Construct(int *preorder, int *inorder, int length)
{
	if(preorder == NULL || inorder == NULL || length <= 0) {
		printf("invalid input!\n");
		return 0;
	}

	return ConstructCore(preorder, preorder + length -1, inorder, inorder + length - 1);
}

BinaryTreeNode *ConstructCore(int *startPreorder,int *endPreorder,int *startInorder,int *endInorder)
{
    //前序遍历的第一个元素,即为根节点
	int rootValue = startPreorder[0];
    //构建根节点
	BinaryTreeNode * root = (BinaryTreeNode*)malloc(sizeof(BinaryTreeNode));
	root->m_nValue = rootValue;
	root->m_pLeft = root->m_pRight = NULL;

    //顺序遍历到最后一个元素
	if (startPreorder == endPreorder)
	{
        //该节点满足是根节点的条件如括号中所示
		if (startInorder == endInorder && *startPreorder == *startInorder) {
            return root;
        } else {
            printf("invalid input!\n");
        }	
	}

    //根据前序遍历中的根节点的值,在中序遍历中找到根节点
	int* rootInorder = startInorder;
	while(rootInorder <= endInorder && *rootInorder != rootValue) {
        ++rootInorder;
    }	

	if(rootInorder == endInorder && *rootInorder != rootValue) {
        printf("invalid input!\n");
    }

    //在中序数组中找到它的左子树的长度
	int leftLength = rootInorder - startInorder;
    //根据中序遍历中左子树的长度在前序遍历中找到左子树的位置
	int* leftPreorderEnd = startPreorder + leftLength;

	if(leftLength > 0){
        //构建左子树,输入为前序遍历子串的起始地址,中序遍历的起始地址
		root->m_pLeft = ConstructCore(startPreorder + 1, leftPreorderEnd, startInorder, rootInorder - 1);
	}

	if(leftLength < (endPreorder - startPreorder))
    {
        //构建右子树,输入为前序遍历子串的起始地址,中序遍历的起始地址
		root->m_pRight = ConstructCore(leftPreorderEnd + 1,endPreorder, rootInorder + 1, endInorder);
    }

	return root;
}

void lastOrderTraverse(BinaryTreeNode *root)
{
	if(root)
	{
		lastOrderTraverse(root->m_pLeft);
		lastOrderTraverse(root->m_pRight);
		printf("%d ",root->m_nValue);
	}
}

int main()
{
	int preorder[8] = {1, 2, 4, 7, 3, 5, 6, 8};
	int inorder[8] = {4, 7, 2, 1, 5, 3, 8, 6};
	int length = sizeof(preorder) / sizeof(int);
	BinaryTreeNode *tree = Construct(preorder, inorder, length);
	printf("后续遍历的顺序为:\n");
	lastOrderTraverse(tree);

	return 0;
}

下面我们来分析以上代码的结构,主要是对ConstructCore进行分析。

最初建立的两个数组,如图所示,这个指针指向的数据,由于前序遍历可知,我们的根节点是1,那么由中序遍历的结果就知道,472是其左子树上面的值,5386是其右子树的值。

根据前序遍历确定的根节点,在中序遍历当中确定该树的左子树,并且确定左子树的数据个数leftLength,以及在前序遍历中确定左子树的位置。(因为前序遍历会将根节点左子树遍历完,才会去遍历它的右子树,所以根节点后面紧跟的就是左子树的元素了。)

构建左子树,它们的起止地址分别如上图所示,然后就是一直递归调用下去了。

构建右子树,它们的起止地址分别如上图所示,然后就是一直递归调用下去了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值