节点结构体如下:
typedef struct BinaryTreeNode
{
int value;
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
}BinaryTree_Node;
背景知识:
前序遍历:访问顺序 根 左 右
中序遍历:访问顺序 左 根 右
所以,前序的第一个元素是整棵树的根节点,根节点后面先是左子树,然后右子树。中序序列中,根节点所在的位置的左边是根节点的左子树,右边是右子树。因此每次可根据前序和中序的根所在的位置,找出左子树和右子树的前序序列和中序序列。
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<math.h>
typedef struct BinaryTreeNode
{
int value;
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
}BinaryTree_Node;
void pre_order_print(BinaryTree_Node* root)
{
if(root == NULL)
{
return;
}
printf("%d,",root->value);
pre_order_print(root->left);
pre_order_print(root->right);
}
void in_order_print(BinaryTree_Node* root)
{
if(root == NULL)
{
return;
}
in_order_print(root->left);
printf("%d,",root->value);
in_order_print(root->right);
}
void release_tree(BinaryTree_Node** root)
{
if(NULL == *root)
{
return;
}
release_tree(&(*root)->left);
release_tree(&(*root)->right);
free(*root);
*root = NULL;
}
void print_to_screen(int*a, int n)
{
int i =0;
for(i = 0; i < n; ++i)
{
printf("%d ",a[i]);
}
printf("\n");
}
int rebuild_binary_tree( int size, int* pre_order, int*in_order, BinaryTree_Node** out)
{
BinaryTree_Node* node = NULL;
int i = 0;
int left_tree_len = 0;
int right_tree_len = 0;
int ret = 0;
if(NULL == pre_order || NULL == in_order || size <= 0)
{
return 0;
}
//前序的第一个数字是根节点
node = (BinaryTree_Node*)malloc(sizeof(BinaryTree_Node));
if(NULL == node)
{
return -1;
}
node->left = NULL;
node->right = NULL;
node->value = pre_order[0];
*out = node;
//在中序中找根节点,中序根节点左边是左子树,右边是右子树
//从而确定左子树长度和右子树长度
for(i = 0; i < size; ++i)
{
if(pre_order[0] == in_order[i])
{
break;
}
}
if(i == size)
{
printf("In_order not match with Pre_order. ERROR!!!\n\n");
free(node);
node = NULL;
*out = NULL;
return -1;
}
left_tree_len = i;
right_tree_len = size -i -1;
if(left_tree_len > 0)
{
ret = rebuild_binary_tree(left_tree_len,pre_order+1, in_order, &node->left);
if(-1 == ret)
{
free(node);
node = NULL;
*out = NULL;
return ret;
}
}
if(right_tree_len > 0)
{
ret = rebuild_binary_tree(right_tree_len, pre_order+1+left_tree_len, in_order+left_tree_len+1, &node->right);
if(-1 == ret)
{
free(node);
node = NULL;
*out = NULL;
return ret;
}
}
return ret;
}
int main()
{
int pre_order[8] = {1,2,4,7,3,5,6,8};
int in_order[8] = {4,7,2,1,5,3,8,6};
BinaryTree_Node* out = NULL;
int p_a[2] = {1,2};
int i_a[2] = {0,0};
int p_b[5] = {1,2,5,5,5};
int i_b[2] = {0,0};
int p_c =1,i_c = 1;
rebuild_binary_tree(8, pre_order, in_order, &out);
in_order_print(out);
printf("\n");
pre_order_print(out);
printf("\n");
release_tree(&out);
rebuild_binary_tree(2, p_a, i_a, &out);
in_order_print(out);
printf("\n");
pre_order_print(out);
printf("\n");
release_tree(&out);
rebuild_binary_tree(5, p_b, i_b, &out);
in_order_print(out);
printf("\n");
pre_order_print(out);
printf("\n");
release_tree(&out);
rebuild_binary_tree(1, &p_c, &i_c, &out);
in_order_print(out);
printf("\n");
pre_order_print(out);
printf("\n");
release_tree(&out);
rebuild_binary_tree(0, NULL, NULL, &out);
in_order_print(out);
printf("\n");
pre_order_print(out);
printf("\n");
release_tree(&out);
return 0;
}
这道题目的想法本身很简单,但是实际写代码得时候需要注意的点很多,也就是代码的健壮性,比如以下测试用例,是否也能确保程序不崩溃?
1.输入前序和中序不匹配;
2.输入空序列;
3.只有一个节点的二叉树;
4.整棵树只有右子节点的二叉树、或只有左子节点的二叉树
指针操作要特别小心,传值还是传址。