二叉树的非递归遍历
一.非递归先序遍历
递归的方式遍历是指就是利用了函数压栈的特点,我们根据这个特点可以自己设计栈来实现非递归遍历的方式。
先序遍历的过程:
代码:
//非递归的先序遍历
void preOrderNoR(TreeNode* root) {
//从根节点进入,根节点入栈,
//打印根节点,根节点出栈,并将根节点的非空左孩子入栈
//如果左孩子为空,就入其右孩子。
if (root == NULL) {
return;
}
//创建一个栈
stack <TreeNode*> s;
TreeNode* cur = root;
//循环
while (cur != NULL || !s.empty()) {
//先遍历所有左结点,打印后,再入栈
while (cur) {
printf("%c ", cur->val);
s.push(cur);
cur = cur->left;
}
//所有的左结点已经打印完毕,
//取栈顶指针,更新cur为最后一个左结点的右子树
TreeNode* top = s.top();
s.pop();//更新栈顶指针,
cur = top->right;
}
}
二.非递归中序遍历
中序与先序大同小异:只是再第二次访问到该结点的时候打印它。
我们只需要调整打印的位置即可。
先将根节点以及其左孩子入栈,直到左孩子为空时再打印,并出栈,调整到右孩子处。
思路:
代码:
//非递归的中序遍历
void inOrderNoR(TreeNode* root) {
if (root == NULL) {
return;
}
//建栈
stack<TreeNode*> s;
TreeNode* cur = root;//遍历指针
while (cur || !s.empty()) {
while (cur) {
s.push(cur);
cur = cur->left;
}
TreeNode* top = s.top();
printf("%c ", top->val);
s.pop();
cur = top->right;
}
}
三.非递归后序遍历
后序:当第三次访问到该节点的时候打印它
分析:
由于我们不知道什么时候是第三次访问到了该节点,我们就记录一下上一次被打印的结点的位置
什么时候该打印:1.栈顶元素的右子树是NULL的时候,表示该节点是叶子节点该打印了。
2.当栈顶元素的右子树是上一次被打印的结点的时候,表明访问到了根节点,并且是第三次访问了,该打印 了。
直接上代码:
//非递归的后序遍历
void postOrderNoR(TreeNode* root) {
if (root == NULL) {
return;
}
stack<TreeNode*> s;
TreeNode* cur = root;
TreeNode* last = NULL;
//由于后序不知道是第几次访问到该节点,
//因此用last来记录最近一个被打印的结点
while (cur != NULL || !s.empty()) {
while (cur) { //第一次
s.push(cur);
cur = cur->left;
}
//左子树走完了,
//获取栈顶指针,右子树压栈,
TreeNode* top = s.top();
if (top->right == NULL) {
printf("%c ", top->val);
s.pop();
last = top;
}
//如果栈顶的右子树是上一次打印过的,就也让它打印
else if (top->right == last) {
printf("%c ", top->val);
s.pop();
last = top;
}
else {
cur = top->right;
}
}
}
总结:
1.非递归遍历,就是自己将二叉树的结点压入栈内,并进行循环的过程。
2.先序:第一次访问到该节点的时候打印该节点
3.中序:第二次访问到该节点的时候打印该节点
4.后序:第三次访问到该节点的时候打印该节点
但是由于不知道什么时候是第三次访问到该节点,则记录一下最近一次打印的结点的位置即可。