个人主页:Lei宝啊
愿所有美好如期而遇
目录
递归
前序遍历
void PrevOrder(BT_Tree* node)
{
if (node == NULL)
return;
printf("%c ", node->data);
PrevOrder(node->left);
PrevOrder(node->right);
}
中序遍历
void InOrder(BT_Tree* node)
{
if (node == NULL)
return;
PrevOrder(node->left);
printf("%d ", node->data);
PrevOrder(node->right);
}
后序遍历
void LastOrder(BT_Tree* node)
{
if (node == NULL)
return;
PrevOrder(node->left);
PrevOrder(node->right);
printf("%d ", node->data);
}
前序中序还原二叉树
思路是通过前序序列确定根,中序序列划分左右子树
- 前序遍历:根 左子树 右子树
- 中序遍历:左子树 根 右子树
前序序列:3 1 9 2 8 5 4 6
中序序列:9 8 2 1 5 3 4 6
先确定3是根,然后在中序序列中找到3的位置,左子树区间就是{9,8,2,1,5},右子树区间就是{4,6},然后再确认左子树的根,也就是1,再划分区间,他的左子树区间是{9,8,2},右子树区间就是{5},如果我们以下标来说,就是[0,2]和[4,4](1的右边只有5,也就是说右子树的右边界就是5的下标,左边界就是1的下标加1,这里的下标指的都是中序序列中的下标,因为划分左右子树是在中序序列中进行的),我们按照这样的思路,不断划分,创建节点,返回条件是划分的区间的左右边界下标,当左边界下标大于右边界下标时返回空,否则,我们执行我们写的代码后,返回创建的节点,并进行连接。
class Solution
{
public:
TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder,
int& rooti, int begin, int end) {
if (begin > end)
return nullptr;
TreeNode* root = new TreeNode(preorder[rooti++]);
int temp = begin;
while (temp <= end)
{
if (preorder[rooti - 1] == inorder[temp])
break;
else
temp++;
}
root->left = _buildTree(preorder, inorder, rooti, begin, temp - 1);
root->right = _buildTree(preorder, inorder, rooti, temp + 1, end);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int i = 0;
return _buildTree(preorder, inorder, i, 0, preorder.size() - 1);
}
};
中序后序还原二叉树
这里参照前面的逻辑就很好理解,唯一需要注意的一点是:这里还原时要先从右子树开始还原,因为后序遍历的根是先从右子树出现的。
- 后序遍历:左子树 右子树 根
- 中序遍历:左子树 根 右子树
class Solution
{
public:
TreeNode* _buildTree(vector<int>& inorder, vector<int>& postorder, int& rooti, int begin, int end) {
if (begin > end)
return nullptr;
TreeNode* root = new TreeNode(postorder[rooti--]);
int temp = begin;
while (temp <= end)
{
if (postorder[rooti + 1] == inorder[temp])
break;
else
temp++;
}
root->right = _buildTree(inorder, postorder, rooti, temp + 1, end);
root->left = _buildTree(inorder, postorder, rooti, begin, temp - 1);
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
int i = inorder.size() - 1;
return _buildTree(inorder, postorder, i, 0, inorder.size() - 1);
}
};
非递归
前序遍历
我们的思路是分成两个过程:
- 通过栈存储左路节点,并将左路节点的值放入数组
- 出栈,访问出栈的节点的右树
如此循环执行,结束条件就是指向temp右树的变量为nullptr并且栈为空。
class Solution
{
public:
vector<int> preorderTraversal(TreeNode* root)
{
vector<int> v;
stack<TreeNode*> st;
TreeNode* cur = root;
while (cur || !st.empty())
{
while (cur)
{
st.push(cur);
v.push_back(cur->val);
cur = cur->left;
}
TreeNode* temp = st.top();
st.pop();
cur = temp->right;
}
return v;
}
};
中序遍历
这里只变动了一行代码,从入栈时访问节点变成出栈时访问节点。
class Solution
{
public:
vector<int> inorderTraversal(TreeNode* root)
{
vector<int> v;
stack<TreeNode*> st;
TreeNode* cur = root;
while (cur || !st.empty())
{
while (cur)
{
st.push(cur);
cur = cur->left;
}
TreeNode* temp = st.top();
st.pop();
//出栈后再进行访问
v.push_back(temp->val);
cur = temp->right;
}
return v;
}
};
后序遍历
这里的逻辑就是如果栈顶的节点的右树为空,或者当访问当前节点时他的右孩子是前一个访问的节点,我们出栈并将节点值push_back进v。
class Solution
{
public:
vector<int> postorderTraversal(TreeNode* root)
{
vector<int> v;
stack<TreeNode*> st;
TreeNode* cur = root;
TreeNode* prev = nullptr;
while (cur || !st.empty())
{
while (cur)
{
st.push(cur);
cur = cur->left;
}
TreeNode* temp = st.top();
if (temp->right == nullptr || temp->right == prev)
{
v.push_back(temp->val);
st.pop();
}
else
{
cur = temp->right;
}
prev = temp;
}
return v;
}
};
分层遍历
我们将每层的节点分别push_back进他们各自层级的vector<int> v中,然后将所有v push_back进vector<vector<int>> vv中。
这里我们借助队列,首先将3入队列,计算出3这个节点本层有levelsize个节点,我们就循环levelsize次使本层的levelsize个节点分别将他们的左右孩子带入队列,并在循环过程中,将本层的节点的值push_back进vector<int> v中,每循环一次,队列出一个节点。
结束条件为队列为空。
class Solution
{
public:
void reform(vector<vector<int>>& vv, queue<TreeNode*>& qt, TreeNode* root)
{
qt.push(root);
while (!qt.empty())
{
vector<int> v;
int levelsize = qt.size();
for (int i = 0; i < levelsize; i++)
{
TreeNode* node = qt.front();
if (node)
v.push_back(node->val);
if (node && node->left)
qt.push(node->left);
if (node && node->right)
qt.push(node->right);
qt.pop();
}
vv.push_back(v);
}
}
vector<vector<int>> levelOrder(TreeNode* root)
{
vector<vector<int>> vv;
queue<TreeNode*> qt;
if (root == nullptr)
return vv;
reform(vv, qt, root);
return vv;
}
};
从最底层层序遍历,只改动一行代码,我们将结果reverse即可,因为我们每个元素是vector<int>,所以可以这么做。
class Solution
{
public:
void reform(vector<vector<int>>& vv, queue<TreeNode*>& qt, TreeNode* root)
{
qt.push(root);
while (!qt.empty())
{
vector<int> v;
int levelsize = qt.size();
for (int i = 0; i < levelsize; i++)
{
TreeNode* node = qt.front();
if (node)
v.push_back(node->val);
if (node && node->left)
qt.push(node->left);
if (node && node->right)
qt.push(node->right);
qt.pop();
}
vv.push_back(v);
}
}
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> vv;
queue<TreeNode*> qt;
if (root == nullptr)
return vv;
reform(vv, qt, root);
reverse(vv.begin(), vv.end());
return vv;
}
};