保存父亲结点到自建栈内,也就是一路沿着左边压栈,回头了就弹出父结点,再走别的路。(树之所以要用栈,是因为下去了就没法上去)
//前序遍历
vector<int> preorderTraversal(TreeNode* root) {
vector<int> TraArr;
stack<TreeNode*> NodeStk;
TreeNode* p=root; //p指针指向当前根结点
TreeNode* q=NULL; //q指针指向栈顶元素,即父结点
while(p || !NodeStk.empty()){
if(p){
TraArr.push_back(p->val); //前序遍历,先把根结点的值放到遍历序列里
NodeStk.push(p); //父结点压栈
q=p; //q指针指向栈顶元素
p=p->left; //p指针指向左孩子
}
else{ //若p指针为空,去看看右孩子
p=q->right;
NodeStk.pop();
if(!NodeStk.empty()){
q=NodeStk.top(); //q指针重新指向栈顶元素,即上一级父结点
}else{
q=NULL;
}
}
}
return TraArr;
}
//中序遍历
vector<int> inorderTraversal(TreeNode* root) {
vector<int> TraArr;
stack<TreeNode*> NodeStk;
TreeNode* p=root;
while(p || !NodeStk.empty()){
if(p){
NodeStk.push(p);
p=p->left;
}
else{
//由于是中序遍历,父结点值应当在左孩子之后再插入
TraArr.push_back(NodeStk.top()->val);
p=NodeStk.top()->right;
NodeStk.pop();
}
}
return TraArr;
}
//后序遍历
vector<int> postorderTraversal(TreeNode* root) {
vector<int> TraArr;
stack<TreeNode*> NodeStk;
TreeNode* p=root;
TreeNode* temp=NULL; //临时存储访问过的右孩子
while(p || !NodeStk.empty()){
if(p){
NodeStk.push(p);
p=p->left;
}else{
TreeNode* node=NodeStk.top();
if(node->right && node->right!=temp){ //右孩子不为空、且右孩子没被访问过的情况
p=node->right; //去访问右孩子
}else{ //父结点没有右孩子、或者右孩子被访问过了的情况
TraArr.push_back(node->val);
NodeStk.pop();
temp=node; //父结点的值插入遍历序列,并标为“访问过”状态
}
}
}
return TraArr;
}