一.二叉树的数据结构:
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)
{}
};
二.递归遍历
1.前序
void preOrder(TreeNode* root)
{
if (root)
{
cout << root->val << " ";
preOrder(root->left);
preOrder(root->right);
}
cout<<endl;
}
2.中序
void inOrder(TreeNode* root)
{
if (root)
{
inOrder(root->left);
cout << root->val << " ";
inOrder(root->right);
}
cout<<endl;
}
3.后序
void postOrder(TreeNode* root)
{
if (root)
{
postOrder(root->left);
postOrder(root->right);
cout << root->val << " ";
}
cout<<endl;
}
三.非递归
1.前序
(1)建立一个栈,存储节点;
定义当前节点指向根节点;
(2)当当前节点不为空或者栈不为空时:
遍历最左路径,并输出这条路径的节点的值;
拿到栈顶的节点,让当前节点指向栈顶节点的右孩子,栈顶元素出栈;
(3)重复上一步;
void preOrderTranversal(TreeNode* root)
{
TreeNode* cur = root;
stack<TreeNode*> st;
while (cur || !st.empty())
{
//遍历最左路径,让这条路径的节点入栈
//在入栈的同时输出节点的值
while (cur)
{
st.push(cur);
cout << cur->val << " ";
cur = cur->left;
}
TreeNode* top = st.top();
st.pop();//栈顶元素出栈
cur = top->right;//当前节点指向栈顶元素的右孩子
}
cout << endl;
}
2.中序
(1)建立一个栈,存储节点;
定义当前节点指向根节点;
(2)当当前节点不为空或者栈不为空时:
遍历最左路径,并让节点入栈;
拿到栈顶元素,此时栈顶元素就是根节点,输出栈顶元素的值;
让当前节点指向栈顶元素的右孩子,栈顶元素出栈;
(3)重复上一步;
void inOrderTranversal(TreeNode* root)
{
TreeNode* cur = root;
stack<TreeNode*> st;
while (cur || !st.empty())
{
//遍历最左路径,让这条路径的节点入栈
while (cur)
{
st.push(cur);
cur = cur->left;
}
TreeNode* top = st.top();
cout << top->val << " ";//输出栈顶元素的值
st.pop();//让栈顶元素出栈
cur = top->right;//让当前节点指向top的右孩子
}
cout << endl;
}
3.后序
(1)建立一个栈,存储节点;
定义当前节点指向根节点;
定义父节点,初始化为空;
(2)当当前节点不为空或者栈不为空时:
遍历最左路径,并让节点入栈;
拿到栈顶元素,此时栈顶元素就是根节点,判断当前节点是否可以访问:
如果当前节点的右子树为空或者右孩子已经访问过了,就输出栈顶元素的值,更新父节点,栈顶元素出栈;
否则访问右子树;
(3)重复上一步;
void postOrderTranversal(TreeNode* root)
{
TreeNode* cur = root;
TreeNode* prev = nullptr;//父节点初始为空
stack<TreeNode*> st;
while (cur || !st.empty())
{
//遍历最左路径,节点入栈
while (cur)
{
st.push(cur);
cur = cur->left;
}
TreeNode* top = st.top();
//栈顶元素的右孩子等于父节点,或者栈顶元素的右孩子为空,说明当前根节点可以访问
if (top->right == nullptr || top->right == prev)
{
cout << top->val<<" ";
st.pop();
prev = top;
}
else
{
//根节点不能访问,访问根节点的右子树
cur = top->right;
}
}
cout << endl;
}
非递归前序和后序的不同方式
前序的思想:
- 让根节点入栈;
- 拿到栈顶元素,将栈顶元素打印,同时让栈顶元素的右孩子和左孩子依次入栈;
- 重复上一步,直到栈为空;
后序的思想:
- 创建两个栈, 一个辅助栈,一个仓库栈,让根节点先入到辅助栈中;
- 让辅助栈的栈顶元素top出栈,同时将top入栈到仓库栈中,如果top有左右孩子,让左右孩子依次入栈到辅助栈;
- 重复上一步,直到辅助栈为空;
- 将仓库栈的元素出栈并打印;
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
class Solution {
public:
/**
*
* @param root TreeNode类 the root of binary tree
* @return int整型vector<vector<>>
*/
vector<vector<int> > threeOrders(TreeNode* root) {
// write code here
vector<vector<int>> res;
vector<int> preRes;
vector<int> inRes;
vector<int> postRes;
preOrder(root, preRes);
inOrder(root, inRes);
postOrder(root, postRes);
res.push_back(preRes);
res.push_back(inRes);
res.push_back(postRes);
return res;
}
private:
//前序,不同于我之前接触的方法
void preOrder(TreeNode* root, vector<int>& preRes)
{
stack<TreeNode*> st;
if(root)
{
st.push(root);
}
while(!st.empty())
{
TreeNode* top = st.top();
st.pop();
preRes.push_back(top->val);
if(top->right)
{
st.push(top->right);
}
if(top->left)
{
st.push(top->left);
}
}
}
//中序,和之前接触的二叉树的遍历方法相同
void inOrder(TreeNode* root, vector<int>& inRes)
{
stack<TreeNode*> st;
TreeNode* curNode = root;
while(curNode || !st.empty())
{
while(curNode)
{
st.push(curNode);
curNode = curNode->left;
}
TreeNode* top = st.top();
st.pop();
inRes.push_back(top->val);
if(top->right)
{
curNode = top->right;
}
}
}
//后序,不同于之前我接触的方法
void postOrder(TreeNode* root, vector<int>& postRes)
{
stack<TreeNode*> tmp;
stack<TreeNode*> wareHouse;
if(root)
{
tmp.push(root);
}
while(!tmp.empty())
{
TreeNode* top = tmp.top();
tmp.pop();
wareHouse.push(top);
if(top->left)
{
tmp.push(top->left);
}
if(top->right)
{
tmp.push(top->right);
}
}
while(!wareHouse.empty())
{
postRes.push_back(wareHouse.top()->val);
wareHouse.pop();
}
}
};