赞
踩
关于二叉树的另外一个重要内容就二叉树的重构,二叉树的重构就是根据已知的二叉树前序,中序,后续遍历的数组重新构造出园二叉树。
对于普通的二叉树可以由 前序遍历+中序遍历 或者 后序遍历+中序遍历 重构(注意:二叉树各节点不能有相同值)。
对于只知道 前序遍历和后续遍历是否可以进行二叉树重构呢?对于普通二叉树以上两个条件是无法重构二叉树的,比如:
1 1
/ /
2 2
\ \
3 3
/ \
4 4
以上两个不同的二叉树他们的
前序遍历:1 2 3 4;
后序遍历:4 3 2 1;
相同,所以可以看出对于一般的二叉树仅仅知道前序和后序遍历是不够的,因为对于有些节点无无法判断出是左节点还是右节点。但是如果提前已知该二叉树是满二叉树(full binary tree)那可以根据前序和后序遍实现对二叉树重构,后面我会再对这个内容进行整理。
以下例对二叉树进行重构:
1
/ \
2 3
/ \ / \
4 5 6 7
/ \ \
8 9 10
前序遍历:1 2 4 5 8 9 3 6 7 10;
中序遍历:4 2 8 5 9 1 6 3 7 10;
后续遍历:4 8 9 5 2 6 10 7 3 1;
前序遍历的顺序是:根->左子树->右子树
中序遍历的顺序是:左子树->根->右子树;
因此前序遍历的第一个元素1就是整个二叉树的根节点;
在中序遍历中找到该元素,则该元素把中序遍历数组分成左右两部分,分别为左子树(4 2 8 5 9)和右子树(6 3 7 10);
前序遍历的第二个元素2为左子树的根节点,同理在中序遍历中找到该元素,左子树又被一分为二(4)和(8 5 9);
……
如此递归下去直到最后一个元素;
代码如下:
Node* RebuildTree_Pre_In(int preorder[], int inorder[], int inorder_left, int inorder_right, int &pre_index){
if(inorder_left > inorder_right)
return NULL;
int key = preorder[pre_index++];
Node *node = new Node(key);
if(inorder_left == inorder_right)
return node;
int i;
for(i = inorder_left; inorder[i] != key; ++i);
node->left = RebuildTree_Pre_In(preorder, inorder, inorder_left, i-1, pre_index);
node->right = RebuildTree_Pre_In(preorder, inorder, i+1, inorder_right, pre_index);
return node;
}
后序遍历的顺序是:左子树->右子树->根;
中序遍历的顺序是:左子树->根->右子树;
和前面相似,不同的是对于后序遍历我们从最后一个元素下手。
后续遍历数组的最后一个元素 1 就是整个数组的根节点;
在中序遍历数组中查找到该元素同样把整个数组分成两部分,左子树(4 2 8 5 9)和右子树(6 3 7 10);
后续遍历数组的倒数第二个元素 3 就是右子树的根节点,同样又把上述右子树分成左右两部分(6)和(7 10);
…….
如此地递归至最后一个元素。
注意,我们在后序遍历数组是从根节点到右子树的顺序取值的,所以在递归的时候也要先从右节点开始。
代码如下:
Node* RebuildTree_In_Post( int inorder[], int postorder[], int inorder_left, int inorder_right, int &post_index){
if(inorder_left > inorder_right)
return NULL;
int key = postorder[post_index--];
Node *node = new Node(key);
if(inorder_left == inorder_right)
return node;
int i;
for(i = inorder_left; inorder[i] != key; ++i);
node->right= RebuildTree_In_Post(inorder, postorder, i+1, inorder_right, post_index);
node->left = RebuildTree_In_Post(inorder, postorder, inorder_left, i-1, post_index);
return node;
}
//reconstruct a binary by preorder ang inorder traversal
int preorder[] = {1,2,4,5,8,9,3,6,7,10};
int inorder[] = {4,2,8,5,9,1,6,3,7,10};
int postorder[] = {4,8,9,5,2,6,10,7,3,1};
int pre_index = 0;
int post_index = 9;
cout << "\n--------------- rebuild tree:--------------------\n";
cout << "rebuild from preorder and inorder traversal:\n";
Tree reTree1(RebuildTree_Pre_In(preorder, inorder, 0, 9, pre_index));
reTree1.StackPreorder();
std::cout << endl;
reTree1.StackInorder();
std::cout << endl;
reTree1.StackPostorder();
std::cout << endl;
cout << "rebuild from preorder and inorder traversal:\n";
Tree reTree2(RebuildTree_In_Post(inorder, postorder, 0, 9, post_index));
reTree2.StackPreorder();
std::cout << endl;
reTree2.StackInorder();
std::cout << endl;
reTree2.StackPostorder();
std::cout << endl;

测试结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。