对于二叉树,如果我们需要对它进行遍历的话(不管是前序,中序还是后序,下面如果不特指的话,那么就是对三种遍历的统称)。如果用递归的方法,那么就非常简单了,我们只需要写下类似的代码即可

work(TreeNode *root)
{
if(NULL == root)
return ;
work(root->left);
work(root->right);
}

这样我们的三种遍历,只需要在这个函数里面进行一些细微的更改就可以达到了(把当前点的输出位置放在不同的地方)。不过这里主要讲的将是如何用非递归的方法进行二叉树的遍历。

首先,我们来看树的前序遍历,我们需要先输出当前节点,然后处理左子树,然后再处理右子树。这里我们可以用桟来保存每个节点,但是我们需要处理每个节点的左右子树,如果我们只把每个节点压桟一次的话,那么每次我们不知道如果处理右子树(处理左子树的时候会把当前节点弹出桟)。这里就有问题了,但是我们可以考虑把每个节点压桟两次,也就是说第一次我们弹出的时候处理左子树,第二次弹出的时候,我们处理右子树。那么上面的这个问题就解决了,只不过桟的空间需要会大一点。不过已经可以工作了,至于怎么判断是第一次还是第二次弹出的话,我们可以把弹出的节点和桟里面最上面的节点做比较,相等的话就是第一次弹出,不相等就是第二次弹出。具体代码可以参考这里

然后我们考虑树的中序,可以把上面的代码进行一些细微的更改就好了,大致的框架我们不需要更改,具体的代码可以参考这里

接下来是后序,我们发现上面的算法不行了,因为我们必须在处理完了左右子树之后,才能够输出当前节点,但是按照上面的算法,我们在处理完左右子树之后,已经找不到当前节点了,这就是问题的所在,或许我们想可以把每个节点压桟3次,这样的话也是可以的,在第一次的时候处理左子树,第二次的时候处理右子树,第三次处理当前节点。不过我们可以看出上面的要不是压桟2次,要不是压桟3次,那么我们可以把压桟的数据更改一下,我们把桟保存的元素变成一个pair,这样的话后面的int保存的是这个节点在桟里面的次数,比如说前序遍历中,我们压桟的时候把pair后面的参数改成1(有0和1两种可能),然后弹出一次就把后面的int值减1。对于后序遍历的话,我们把后面的int值设为2(有0,1和2三种可能),每次出桟的时候,如果int值为2就处理左子树,然后把int值减1再次压桟;如果int值为1的话,就处理右子树,然后把int值设为0,再次压桟;如果int值为0的话,那么就输出当前节点。这样的话我们可以比较好的处理二叉树的后序遍历了。具体的代码可以参考这里

Comments