目录
一、概述
在计算机科学中,二叉树是每个结点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。
一棵深度为k,且有2^k-1个结点的二叉树,称为满二叉树。这种树的特点是每一层上的结点数都是最大结点数。而在一棵二叉树中,除最后一层外,若其余层都是满的,并且或者最后一层是满的,或者是在右边缺少连续若干结点,则此二叉树为完全二叉树。具有n个结点的完全二叉树的深度为floor(log2n)+1。深度为k的完全二叉树,至少有2k-1个叶子结点,至多有2k-1个结点。
(1)前序遍历
a、访问根节点;b、前序遍历左子树;c、前序遍历右子树。
(2)中序遍历
a、中序遍历左子树;b、访问根节点;c、中序遍历右子树。
(3)后序遍历
a、后序遍历左子树;b、后续遍历右子树;c、访问根节点。
二、题目
// 3
// / \
// 9 20
// / \
// 15 7
//inorder = [9,3,15,20,7]
//postorder = [9,15,7,20,3]
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
三、实战
1、思路
中序遍历和后序遍历还原二叉树思想如下:
a、根据后序遍历结果,最后一个元素为二叉树的根结点;
b、观察中序遍历结果,根结点左侧的为左子树;根结点右侧的为右子树
c、上面的过程是递归的。先从postorder结果中找到当前树的根结点(postorder的最后一个元素),然后使用该值在中序遍历结果中找到数的左右子树和根节点(3为根节点 ,9为左子树,15,50,7为右子树),由于已经根据中序遍历结果知道左子树和有子树的节点个数进一步也可以在后序遍历结果中找到左右子树(9位左子树,15,7,20为右子树,3为根节点)。最后划分为左右子树,再进入左子树重复上面的过程,最后进入右子树重复上面的过程,最终还原一棵树
2、实现
TreeNode* buildTree_help(vector<int>& inorder, vector<int>& postorder, int instart, int inend, int poststart, int postend)
{
if (poststart >= postend)
{
return NULL;
}
int nl = inend - instart;
int k = 0;
for (int i = instart; i <instart + nl; ++i)
{
if (inorder[i] == postorder[postend-1])
break;
k++;
}
TreeNode*left = buildTree_help(inorder, postorder, instart, instart + k, poststart, poststart + k);
TreeNode *right= buildTree_help(inorder, postorder, instart+k+1,inend, poststart + k, postend-1);
TreeNode *p = new TreeNode(postorder[postend - 1]);
p->left = left;
p->right = right;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder)
{
return buildTree_help(inorder, postorder, 0, inorder.size() , 0, postorder.size());
}
四、调用
int main()
{
std::vector<int>inorder = { 9,3,15,20,7 };
std::vector<int> postorder = { 9,15,7,20,3 };
TreeNode* p = buildTree(inorder, postorder);
return 0;
}
五、总结
二叉树的一些算法很有意思,很值得研究,重点是先找到当前树的根结点,然后划分为左右子树,再进入左子树重复上面的过程,最后进入右子树重复上面的过程,最终还原一棵树。