二叉树的前序遍历,中序遍历,后序遍历(Java实现)

二叉树的前序遍历,中序遍历,后序遍历(Java实现)

1.前序遍历

    前序遍历(DLR,lchild,data,rchild),是二叉树遍历的一种,也叫做先根遍历、先序遍历、前序周游,可记做根左右。前序遍历首先访问根结点然后遍历左子树,最后遍历右子树。

前序遍历首先访问根结点然后遍历左子树,最后遍历右子树。在遍历左、右子树时,仍然先访问 根结点,然后遍历左子树,最后遍历右子树。
二叉树为空则结束返回,否则:
(1)访问根结点。
(2)前序遍历左子树 。
(3)前序遍历右子树 。
前序遍历 前序遍历
需要注意的是:遍历左右子树时仍然采用前序遍历方法。
如右图所示 二叉树
前序遍历结果:ABDECF
已知后序遍历和中序遍历,就能确定前序遍历。

    其实在遍历二叉树的时候有三次遍历, 比如前序遍历:A->B->D->D(D左子节点并返回到D)->D(D右子节点并返回到D)->B->E->E(左)->E(右)->->B->A->C->F->F(左)->F(右)->C->C(右),所以可以用栈结构,把遍历到的节点压进栈,没子节点时再出栈。也可以用递归的方式,递归的输出当前节点,然后递归的输出左子节点,最后递归的输出右子节点。直接看代码更能理解:


     
     
  1. package test;
  2. //前序遍历的递归实现与非递归实现
  3. import java.util.Stack;
  4. public class Test
  5. {
  6. public static void main(String[] args)
  7. {
  8. TreeNode[] node = new TreeNode[ 10]; //以数组形式生成一棵完全二叉树
  9. for( int i = 0; i < 10; i++)
  10. {
  11. node[i] = new TreeNode(i);
  12. }
  13. for( int i = 0; i < 10; i++)
  14. {
  15. if(i* 2+ 1 < 10)
  16. node[i].left = node[i* 2+ 1];
  17. if(i* 2+ 2 < 10)
  18. node[i].right = node[i* 2+ 2];
  19. }
  20. preOrderRe(node[ 0]);
  21. }
  22. public static void preOrderRe(TreeNode biTree)
  23. { //递归实现
  24. System.out.println(biTree.value);
  25. TreeNode leftTree = biTree.left;
  26. if(leftTree != null)
  27. {
  28. preOrderRe(leftTree);
  29. }
  30. TreeNode rightTree = biTree.right;
  31. if(rightTree != null)
  32. {
  33. preOrderRe(rightTree);
  34. }
  35. }
  36. public static void preOrder(TreeNode biTree)
  37. { //非递归实现
  38. Stack<TreeNode> stack = new Stack<TreeNode>();
  39. while(biTree != null || !stack.isEmpty())
  40. {
  41. while(biTree != null)
  42. {
  43. System.out.println(biTree.value);
  44. stack.push(biTree);
  45. biTree = biTree.left;
  46. }
  47. if(!stack.isEmpty())
  48. {
  49. biTree = stack.pop();
  50. biTree = biTree.right;
  51. }
  52. }
  53. }
  54. }
  55. class TreeNode//节点结构
  56. {
  57. int value;
  58. TreeNode left;
  59. TreeNode right;
  60. TreeNode( int value)
  61. {
  62. this.value = value;
  63. }
  64. }


2.中序遍历

中序遍历(LDR)是 二叉树遍历的一种,也叫做 中根遍历、中序周游。在二叉树中,先左后根再右。巧记:左根右。
中序遍历首先遍历左子树,然后访问根结点,最后遍历右子树
二叉树为空则结束返回,
否则:

  
(1)中序遍历左子树
(2)访问根结点
(3)中序遍历右子树
如右图所示 二叉树
中序遍历结果:DBEAFC


     
     
  1. import java.util.Stack;
  2. public class Test
  3. {
  4. public static void main(String[] args)
  5. {
  6. TreeNode[] node = new TreeNode[ 10]; //以数组形式生成一棵完全二叉树
  7. for( int i = 0; i < 10; i++)
  8. {
  9. node[i] = new TreeNode(i);
  10. }
  11. for( int i = 0; i < 10; i++)
  12. {
  13. if(i* 2+ 1 < 10)
  14. node[i].left = node[i* 2+ 1];
  15. if(i* 2+ 2 < 10)
  16. node[i].right = node[i* 2+ 2];
  17. }
  18. midOrderRe(node[ 0]);
  19. System.out.println();
  20. midOrder(node[ 0]);
  21. }
  22. public static void midOrderRe(TreeNode biTree)
  23. { //中序遍历递归实现
  24. if(biTree == null)
  25. return;
  26. else
  27. {
  28. midOrderRe(biTree.left);
  29. System.out.println(biTree.value);
  30. midOrderRe(biTree.right);
  31. }
  32. }
  33. public static void midOrder(TreeNode biTree)
  34. { //中序遍历费递归实现
  35. Stack<TreeNode> stack = new Stack<TreeNode>();
  36. while(biTree != null || !stack.isEmpty())
  37. {
  38. while(biTree != null)
  39. {
  40. stack.push(biTree);
  41. biTree = biTree.left;
  42. }
  43. if(!stack.isEmpty())
  44. {
  45. biTree = stack.pop();
  46. System.out.println(biTree.value);
  47. biTree = biTree.right;
  48. }
  49. }
  50. }
  51. }
  52. class TreeNode//节点结构
  53. {
  54. int value;
  55. TreeNode left;
  56. TreeNode right;
  57. TreeNode( int value)
  58. {
  59. this.value = value;
  60. }
  61. }

3.后序遍历(难点)

后序遍历(LRD)是 二叉树遍历的一种,也叫做 后根遍历、后序周游,可记做左右根。后序遍历有 递归算法和非递归算法两种。在二叉树中,先左后右再根。巧记:左右根。
后序遍历首先遍历左子树,然后遍历右子树,最后访问根结点,在遍历左、右子树时,仍然先遍历左子树,然后遍历右子树,最后遍历根结点。即:
二叉树为空则结束返回,
否则:
(1)后序遍历左子树
(2)后序遍历右子树
(3)访问根结点
如右图所示 二叉树
后序遍历结果:DEBFCA
已知前序遍历和中序遍历,就能确定后序遍历。
算法核心思想:
    首先要搞清楚先序、中序、后序的非递归算法共同之处:用栈来保存先前走过的路径,以便可以在访问完子树后,可以利用栈中的信息,回退到当前节点的双亲节点,进行下一步操作。
    后序遍历的非递归算法是三种顺序中最复杂的,原因在于,后序遍历是先访问左、右子树,再访问根节点,而在非递归算法中,利用栈回退到时,并不知道是从左子树回退到根节点,还是从右子树回退到根节点,如果从左子树回退到根节点,此时就应该去访问右子树,而如果从右子树回退到根节点,此时就应该访问根节点。所以相比前序和后序,必须得在压栈时添加信息,以便在退栈时可以知道是从左子树返回,还是从右子树返回进而决定下一步的操作。


     
     
  1. import java.util.Stack;
  2. public class Test
  3. {
  4. public static void main(String[] args)
  5. {
  6. TreeNode[] node = new TreeNode[ 10]; //以数组形式生成一棵完全二叉树
  7. for( int i = 0; i < 10; i++)
  8. {
  9. node[i] = new TreeNode(i);
  10. }
  11. for( int i = 0; i < 10; i++)
  12. {
  13. if(i* 2+ 1 < 10)
  14. node[i].left = node[i* 2+ 1];
  15. if(i* 2+ 2 < 10)
  16. node[i].right = node[i* 2+ 2];
  17. }
  18. postOrderRe(node[ 0]);
  19. System.out.println( "***");
  20. postOrder(node[ 0]);
  21. }
  22. public static void postOrderRe(TreeNode biTree)
  23. { //后序遍历递归实现
  24. if(biTree == null)
  25. return;
  26. else
  27. {
  28. postOrderRe(biTree.left);
  29. postOrderRe(biTree.right);
  30. System.out.println(biTree.value);
  31. }
  32. }
  33. public static void postOrder(TreeNode biTree)
  34. { //后序遍历非递归实现
  35. int left = 1; //在辅助栈里表示左节点
  36. int right = 2; //在辅助栈里表示右节点
  37. Stack<TreeNode> stack = new Stack<TreeNode>();
  38. Stack<Integer> stack2 = new Stack<Integer>(); //辅助栈,用来判断子节点返回父节点时处于左节点还是右节点。
  39. while(biTree != null || !stack.empty())
  40. {
  41. while(biTree != null)
  42. { //将节点压入栈1,并在栈2将节点标记为左节点
  43. stack.push(biTree);
  44. stack2.push(left);
  45. biTree = biTree.left;
  46. }
  47. while(!stack.empty() && stack2.peek() == right)
  48. { //如果是从右子节点返回父节点,则任务完成,将两个栈的栈顶弹出
  49. stack2.pop();
  50. System.out.println(stack.pop().value);
  51. }
  52. if(!stack.empty() && stack2.peek() == left)
  53. { //如果是从左子节点返回父节点,则将标记改为右子节点
  54. stack2.pop();
  55. stack2.push(right);
  56. biTree = stack.peek().right;
  57. }
  58. }
  59. }
  60. }
  61. class TreeNode//节点结构
  62. {
  63. int value;
  64. TreeNode left;
  65. TreeNode right;
  66. TreeNode( int value)
  67. {
  68. this.value = value;
  69. }
  70. }

4.层次遍历

    与树的前中后序遍历的DFS思想不同,层次遍历用到的是BFS思想。一般DFS用递归去实现(也可以用栈实现),BFS需要用队列去实现。
层次遍历的步骤是:
    1.对于不为空的结点,先把该结点加入到队列中
    2.从队中拿出结点,如果该结点的左右结点不为空,就分别把左右结点加入到队列中

    3.重复以上操作直到队列为空


     
     
  1. public static void levelOrder(TreeNode biTree)
  2. { //层次遍历
  3. if(biTree == null)
  4. return;
  5. LinkedList<TreeNode> list = new LinkedList<TreeNode>();
  6. list.add(biTree);
  7. TreeNode currentNode;
  8. while(!list.isEmpty())
  9. {
  10. currentNode = list.poll();
  11. System.out.println(currentNode.value);
  12. if(currentNode.left != null)
  13. list.add(currentNode.left);
  14. if(currentNode.right != null)
  15. list.add(currentNode.right);
  16. }
  17. }
先序遍历特点:第一个值是根节点
中序遍历特点:根节点左边都是左子树,右边都是右子树
  •                     <li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#csdnc-thumbsup"></use>
                        </svg><span class="name">点赞</span>
                        <span class="count">41</span>
                        </a></li>
                        <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;popu_824&quot;}"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-Collection-G"></use>
                        </svg><span class="name">收藏</span></a></li>
                        <li class="tool-item tool-active is-share"><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;1582594662_002&quot;}"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-fenxiang"></use>
                        </svg>分享</a></li>
                        <!--打赏开始-->
                                                <!--打赏结束-->
                                                <li class="tool-item tool-more">
                            <a>
                            <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg>
                            </a>
                            <ul class="more-box">
                                <li class="item"><a class="article-report">文章举报</a></li>
                            </ul>
                        </li>
                                            </ul>
                </div>
                            </div>
            <div class="person-messagebox">
                <div class="left-message"><a href="https://blog.csdn.net/coder__666">
                    <img src="https://profile.csdnimg.cn/3/4/A/3_coder__666" class="avatar_pic" username="coder__666">
                                            <img src="https://g.csdnimg.cn/static/user-reg-year/1x/2.png" class="user-years">
                                    </a></div>
                <div class="middle-message">
                                        <div class="title"><span class="tit"><a href="https://blog.csdn.net/coder__666" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}" target="_blank">coder__666</a></span>
                                            </div>
                    <div class="text"><span>发布了52 篇原创文章</span> · <span>获赞 53</span> · <span>访问量 3万+</span></div>
                </div>
                                <div class="right-message">
                                            <a href="https://im.csdn.net/im/main.html?userName=coder__666" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-letter">私信
                        </a>
                                                            <a class="btn btn-sm  bt-button personal-watch" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}">关注</a>
                                    </div>
                            </div>
                    </div>
    </article>
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值