二叉树遍历问题
1.递归算法
Note :
在于遍历与打印的先后。
2.非递归算法
2.1 先序遍历
设计思想1:
- 申请栈,将根结点压入栈;
- 弹出栈顶,记为cur,将cur的右孩子、左孩子压入栈,打印cur结点值;
- 重复步骤2,直至栈空,退出。
设计思想2:
- 申请栈,根结点记为root;
- 如果root不为空,打印root,将root的右孩子(包括空)压入栈,root的左孩子记为root;
- 否则,弹出栈顶结点,记为root;
- 重复步骤2~3,直至栈空且root为空,退出。
**区别 **:
设计1所有结点都是进入栈一次再出栈一次,所有结点一视同仁。
设计2不需要将左孩子入栈,直接先遍历并打印左孩子。
2.2 中序遍历
设计思想:
- 申请栈,根结点记为root;
- 如果root不为空,将root压入栈,root的左子树记为;
- 否则,弹出栈顶结点,记为root,打印root,root的右子树记为root;
- 重复步骤2~3,直至没有左子树,弹出栈顶,打印结点
2.3 后序遍历
设计思想:每次访问根结点时,必须先访问左右子树,因此应该设置一个指针指向上次访问的结点。
-
申请栈S,设置变量pre,pre指向上次访问的结点;
-
当前结点记为root;
-
如果root不为空,则先进栈,将root重新指向二叉树的左子树;
-
否则,root指向栈顶指针。
-
如果root的右子树存在,且未被访问过
将root的右子树压栈,再将root指向右子树的左子树;
-
否则,弹出栈顶结点,打印,并用pre记录此次访问的结点,root置空;
-
-
3.Morris遍历算法
3.1中序遍历
设计思想:
- 如果当前结点root的左孩子为空,那么输出该结点,并把该结点的右孩子作为当前结点;
- 如果当前结点root的左孩子非空,那么就找出该结点在中序遍历中的前驱结点pre;
- 当第一次访问该前驱结点pre时,其右孩子必定为空,那么就将其右孩子设置为当前结点,并将当前结点root设置为其左孩子;
- 当该前驱结点pre的右孩子为当前结点,那么就输出当前结点,并把前驱结点的右孩子设置为空(恢复树的结构),将当前结点更新为当前结点的右孩子
- 重复以上两步,直到当前结点为空。
3.2先序遍历
设计思想:
- 如果当前结点root的左孩子为空,那么输出该结点,并把该结点的右孩子作为当前结点;
- 如果当前结点root的左孩子非空,那么就找出该结点在中序遍历中的前驱结点pre
- 当第一次访问该前驱结点pre时,其右孩子必定为空,那么就将其右孩子设置为当前结点,输出当前结点,并将当前结点root设置为其左孩子;
- 当该前驱结点pre的右孩子为当前结点,那么把前驱结点的右孩子设置为空(恢复树的结构),将当前结点更新为当前结点的右孩子;
- 重复以上两步,直到当前结点为空。
3.3后序遍历
设计思想:在左子树最右结点指向当前结点时,打印结点。