1、遍历
- 前序 : 先访问根节点,再访问左子树,最后访问右子树
- 中序 : 先访问左子树,先访问根节点,最后访问右子树
- 后序 : 先访问左子树,再访问右子树,最后访问根节点
1.1 前序遍历
//void(*visit)(BinNode<E>*node)为一个函数指针
template <typename E>
void BinTree<E>::preOrder(BinNode<E> *tmp, void (*visit)(BinNode<E> *node))
{
//根、左、右
if (tmp == NULL)
return;
visit(tmp);
preOrder(tmp->left(), visit);
preOrder(tmp->right(), visit);
}
1.2 中序遍历
template <typename E>
void BinTree<E>::inOrder(BinNode<E> *tmp, void (*visit)(BinNode<E> *node))
{
//左、根、右
if (tmp == NULL)
return;
inOrder(tmp->left(), visit);
visit(tmp);
inOrder(tmp->right(), visit);
}
1.3 后序遍历
template <typename E>
void BinTree<E>::postOrder(BinNode<E> *tmp, void (*visit)(BinNode<E> *node))
{
//左、右、根
if (tmp == NULL)
return;
postOrder(tmp->left(), visit);
postOrder(tmp->right(), visit);
visit(tmp);
}
1.4 层次遍历(BFS)
template <typename E>
void BinTree<E>::LevelOrderTranverse(BinNode<E> *tmp, void (*visit)(BinNode<E> *node))
{
if (tmp == NULL)
return;
queue<BinNode<E> *> q;
q.push(tmp);
while (q.size())
{
BinNode<E> *t = q.front();
q.pop();
visit(t);
if (t->left() != NULL)
q.push(t->left());
if (t->right() != NULL)
q.push(t->right());
}
return;
}
2、建树
2.1 根据前序和中序建树
前序遍历的结果是
[ 根节点, [左子树的前序遍历结果], [右子树的前序遍历结果] ]
即根节点总是前序遍历中的第一个节点。
中序遍历的结果是
[ [左子树的中序遍历结果], 根节点, [右子树的中序遍历结果] ]
只要在中序遍历
中定位到根节点,那么我们就可以分别知道左子树和右子树中的节点数目,也就是可以确定前序遍历
和中序遍历
的每一部分。这样,原问题就缩小为:构造根节点
,在左子树遍历结果
中构造左子树,在右子树遍历结果
中构造右子树
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
//从preorder[pre_begin,pre_end]&inorder[in_begin,in_end]中构造二叉树
TreeNode* buildTreeHelper(vector<int>& preorder, int pre_begin,int pre_end,vector<int>& inorder,int in_begin,int in_end){
//preoder为空,返回NULL
if(pre_begin>pre_end)return NULL;
//构造根节点
TreeNode* root=new TreeNode(preorder[pre_begin]);
//在inoder中找到根节点的位置
int rootIdx=in_begin;
for(int i=in_begin;i<=in_end;i++){
if(inorder[i]==preorder[pre_begin])
rootIdx=i;
}
int leftNum=rootIdx-in_begin;//左子树的节点数
//构造左子树:递归搜索preorder[pre_begin+1,pre_begin+leftNum]&inorder[in_begin,rootIdx-1]
root->left=buildTreeHelper(preorder,pre_begin+1,pre_begin+leftNum,inorder,in_begin,rootIdx-1);
//构造右子树:递归搜索preorder[pre_begin+1+leftNum,pre_end]&inorder[rootIdx+1,in_end]
root->right=buildTreeHelper(preorder,pre_begin+1+leftNum,pre_end,inorder,rootIdx+1,in_end);
return root;
}
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
return buildTreeHelper(preorder,0,preorder.size()-1,inorder,0,inorder.size()-1);
}
};
利用map记录inorder中的<item,index>,减少在inorder中搜索root的时间:
class Solution {
unordered_map<int,int> m;//<item,index>
TreeNode* buildTreeHelper(vector<int>& preorder, int pre_begin,int pre_end,vector<int>& inorder,int in_begin,int in_end){
......
//在inoder中找到根节点的位置
int rootIdx=m[preorder[pre_begin]];
.......
}
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
// 建立(元素,下标)键值对的哈希表
for(int i=0;i<inorder.size();i++){
m[inorder[i]]=i;
}
......
}
};
2.1 根据中序和后序建树
中序遍历的结果是
[ [左子树的中序遍历结果], 根节点, [右子树的中序遍历结果] ]
后序遍历的结果是
[ [左子树的前序遍历结果], [右子树的前序遍历结果], 根节点 ]
即根节点总是后序遍历中的最后一个节点。
只要在中序遍历
中定位到根节点,那么我们就可以分别知道左子树和右子树中的节点数目,也就是可以确定后序遍历
和中序遍历
的每一部分。这样,原问题就缩小为:构造根节点
,在左子树遍历结果
中构造左子树,在右子树遍历结果
中构造右子树
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
TreeNode* buildTreeHelper(vector<int>& inorder, int in_begin,int in_end,vector<int>& postorder,int post_begin,int post_end) {
if(post_begin>post_end)return NULL;
//构造根节点
TreeNode* root=new TreeNode(postorder[post_end]);
//在inoder中找到根节点的位置
int rootIdx=in_begin;
for(int i=in_begin;i<=in_end;i++){
if(inorder[i]==postorder[post_end])
rootIdx=i;
}
int leftNum=rootIdx-in_begin;//左子树的节点数
//构造左子树:递归搜索inorder[in_begin,rootIdx-1]&postorder[0,leftNum-1]
root->left=buildTreeHelper(inorder,in_begin,rootIdx-1,postorder,post_begin,post_begin+leftNum-1);
//构造右子树:递归搜索inorder[rootIdx+1,in_end]&postorder[leftNum,post_end-1]
root->right=buildTreeHelper(inorder,rootIdx+1,in_end,postorder,post_begin+leftNum,post_end-1);
return root;
}
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
return buildTreeHelper(inorder,0,inorder.size()-1,postorder,0,postorder.size()-1);
}
};
利用map记录inorder中的<item,index>,减少在inorder中搜索root的时间:
class Solution {
unordered_map<int,int> m;//<item,index>
TreeNode* buildTreeHelper(vector<int>& inorder, int in_begin,int in_end,vector<int>& postorder,int post_begin,int post_end) {
......
//在inoder中找到根节点的位置
int rootIdx=m[postorder[post_end]];
......
}
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
// 建立(元素,下标)键值对的哈希表
for(int i=0;i<inorder.size();i++){
m[inorder[i]]=i;
}
return buildTreeHelper(inorder,0,inorder.size()-1,postorder,0,postorder.size()-1);
}
};
2.3根据前序和后序建树(不唯一)
给定两个整数数组,preorder 和 postorder ,其中 preorder 是一个具有 无重复 值的二叉树的前序遍历,postorder 是同一棵树的后序遍历,重构并返回二叉树。
如果存在多个答案,您可以返回其中 任何 一个。
前序遍历为:
- 【根结点】【前序遍历左分支】【前序遍历右分支】
- 【根结点】【左子树根节点,root->left>left, root->left>right】【右子树根节点,root->right>left, root->right>right】
而后序遍历为:
- 【root->left>left, root->left>right,左子树根节点】【root->right>left, root->right>right,右子树根节点】【根结点】
可以发现,划分出左右子树的关键是找到左子树根节点
在preorder和postorder中的位置,然后就可以算出左子树的节点数,之后递归地去构造左右子树。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
unordered_map<int,int> m;//<item,index>
TreeNode* helper(vector<int>& preorder, int pre_begin,int pre_end,vector<int>& postorder,int post_begin,int post_end) {
if(pre_begin>pre_end || post_begin>post_end)return NULL;
if(pre_begin==pre_end) return new TreeNode(preorder[pre_begin]);
TreeNode* root=new TreeNode(preorder[pre_begin]);
int leftSubRootIdx=m[preorder[pre_begin+1]];
// int leftSubRootIdx=post_begin;
// while(preorder[pre_begin+1]!=postorder[leftSubRootIdx]){
// leftSubRootIdx++;
// }
int leftNum=leftSubRootIdx-post_begin;
//构造左子树:递归搜索
root->left=helper(preorder,pre_begin+1,pre_begin+1+leftNum,postorder,post_begin,leftSubRootIdx);
//构造右子树:递归搜索
root->right=helper(preorder,pre_begin+1+leftNum+1,pre_end,postorder,leftSubRootIdx+1,post_end-1);
return root;
}
public:
TreeNode* constructFromPrePost(vector<int>& preorder, vector<int>& postorder) {
for(int i=0;i<postorder.size();i++){
m[postorder[i]]=i;
}
return helper(preorder,0,preorder.size()-1,postorder,0,postorder.size()-1);
}
};