一、前序遍历
分析:
1、前序遍历是中左右,因此利用栈,记录栈顶根结点的同时,先压右子树,后压左子树,从而先遍历左子树。
2、每次弹出的栈顶结点符合前序遍历的顺序,因此可直接记录。
3、注意:由于压入栈的是树的结点,所以栈内数据类型为Node*。
struct Node{
int val;
Node *left, *right;
};
vector<int> get_preorder(Node *root){
vector<int> preorder;
stack<Node*> st;
st.push(root);
while(!st.empty()){
Node* top = st.top();
st.pop();
preorder.push_back(top -> val);
st.push(top -> right);
st.push(top -> left);
}
return preorder;
}
二、中序遍历
分析:
1、中序遍历是左中右,对于一棵树,利用栈,应当先压入右子树的根结点,再压入根结点的值,再压入左子树的根结点。
2、如此操作,当栈顶元素是数字的时候进行记录,因此写一个结构体Stack_Element判断当前压入栈的是结点or结点的值。
struct Node{
int val;
Node *left, *right;
};
struct Stack_Element{
Node *node;
int val;
bool isNode;
Stack_Element(Node *_node, int _val, bool _isNode):node(_node), val(_val), isNode(_isNode){}
};
vector<int> get_inorder(Node *root){
vector<int> inorder;
stack<Stack_Element> st;
st.push(Stack_Element(root, -1, true));//由于该栈中元素为结点,因此他的值为多少并不重要,所以此处设为-1即可
while(!st.empty()){
Stack_Element top = st.top();
st.pop();
if(top.isNode){
if(top.node == NULL) continue;
st.push(Stack_Element(top.node -> right, -1, true));
st.push(Stack_Element(NULL, top.node -> val, false));
st.push(Stack_Element(top.node -> left, -1, true));
}
else{
inorder.push_back(top.val);
}
}
return inorder;
}
三、后序遍历
分析:
1、与中序遍历一样要考虑压入栈的元素是结点or结点的值。
2、唯一的区别是遍历顺序,因此将中序遍历的代码(20~22行)稍作改动即可。
struct Node{
int val;
Node *left, *right;
};
struct Stack_Element{
Node *node;
int val;
bool isNode;
Stack_Element(Node *_node, int _val, bool _isNode):node(_node), val(_val), isNode(_isNode){}
};
vector<int> get_postorder(Node *root){
vector<int> postorder;
stack<Stack_Element> st;
st.push(Stack_Element(root, -1, true));//由于该栈中元素为结点,因此他的值为多少并不重要,所以此处设为-1即可
while(!st.empty()){
Stack_Element top = st.top();
st.pop();
if(top.isNode){
if(top.node == NULL) continue;
st.push(Stack_Element(NULL, top.node -> val, false));
st.push(Stack_Element(top.node -> right, -1, true));
st.push(Stack_Element(top.node -> left, -1, true));
}
else{
postorder.push_back(top.val);
}
}
return postorder;
}