当前位置:   article > 正文

深入底层!二叉树的迭代遍历与非迭代遍历_非迭代前序遍历

非迭代前序遍历

二叉树的遍历方式及其概念

前序遍历:按照 Head-Left-Right的方式遍历,先输出头,再输出左侧,最后输出右侧。

                按照上图,前序遍历应该为:1>2>4>5>3>6>7

                对于上图的数和子树的关系做好区分,那么理解前序、中序、后序就很轻松了。

                例如:245为大二叉树的左侧,367为大二叉树的右侧,而4为245这个小数的左侧...

中序遍历:按照 Left-Head-Right的方式遍历,先输出左侧,再输出头,最后输出右侧。

                按照上图,中序遍历应该为:4>2>5>1>6>3>7

后序遍历:按照 Left-Right-Head的方式遍历,先输出左侧,再输出右侧,最后输出头。

                按照上图,后序遍历应该为:4>5>2>6>7>3>1

②二叉树的迭代遍历

        迭代这种方式在Java以及其它语言中都是很常用的,迭代具有代码简洁易懂,最接近算法底层原理等优势。但是当样本数据过大时,迭代会产生令人吃惊的空间消耗,例如斐波那契迭代数列,当计算第100个数字时,计算机就需要耗费大量时间和空间去做运算,这是迭代巨大的缺点。因此应该视工程实际情况来灵活选用迭代这个工具。

        话不多说,放马过来。(Java实现)

前序遍历:

        第一个if判断防止极端情况,即head==null的发生。

        下面三行分别是输出头部、左侧继续迭代、右侧再迭代。沿用第一张图做分析:首先head.val为1时,打印出输出1,而又head.left即2开始了新一轮的迭代;2进入迭代后,head会等于2,会打印2,而后再将2的左侧即4进入第三轮迭代,打印4,并且4左、右均为null;因此会返回2处,开始右侧迭代,打印5,并且5左、右均为null;因此再回到最开始的1,进入1右侧即3进行迭代,打印3;进入3左侧迭代,打印6,6左右为null,返回3;进入3的右侧,打印7,7左右为null,完成迭代。

因此前序遍历为1>2>4>5>3>6>7

   

  1. //先序 头>左>右
  2. public static void preOrderRecursive(Node head){
  3. if(head == null){return;}
  4. System.out.print(head.val);
  5. preOrderRecursive(head.left);
  6. preOrderRecursive(head.right);
  7. }

中序遍历:

  1. //中序 左>头>右
  2. public static void inOrderRecursive(Node head){
  3. if(head==null){return;}
  4. inOrderRecursive(head.left);
  5. System.out.print(head.val);
  6. inOrderRecursive(head.right);
  7. }

后序遍历:

  1. //后序 左>右>头
  2. public static void posOrderRecursive(Node head){
  3. if(head==null){return;}
  4. posOrderRecursive(head.left);
  5. posOrderRecursive(head.right);
  6. System.out.print(head.val);
  7. }

③二叉树的非迭代遍历

        如前所述,迭代在数据巨大的时候会造成大量空间耗费和时间消耗。对于任何一个工程来说,都是致命的,因此我们做出改进,来用while实现“迭代”的逻辑。

前序遍历:

        我们利用栈,先进后出FILO的特征,为了实现前序的头-左-右(Head-Left-Right)。我们可以反其道行之,将头先弹出,反过来压入右侧再压入左侧(这个顺序很重要!)。因此栈弹出的时候会先弹出左侧再弹出右侧。这就与 Head-Left-Right的顺序一致。

   

  1. public static void preOrder(Node head){
  2. Stack<Node> stack = new Stack<>();
  3. stack.add(head);
  4. while(!stack.isEmpty()){
  5. head = stack.pop();//头先出来
  6. System.out.print(head.val);
  7. //利用栈先进后出的特征,让右边进再左边进
  8. //这样出来的时候可以保证左先出,右再出。完成 头>左>右先序遍历
  9. if(head.right!=null)
  10. stack.push(head.right);
  11. if(head.left!=null)
  12. stack.push(head.left);
  13. }//结束while循环时stack全部弹出,先序完成
  14. }

中序遍历:

        中序遍历相比较而言会比较复杂,同样利用栈的先进后出原理。但是判定条件为head!=null ||  !stack.isEmpty。下面我来参考文章开头的二叉树,捋一下思路。

     宏观思路为:把左侧全部压入栈,指针一直跟随左侧元素,若指针为空,栈弹出,并指向右侧,进而循环压入右侧元素的左侧(相对)。如此一来把二叉树斜着分割,所以压出栈的时候顺序相反,则是 左-头-右,这正好与中序遍历契合。

        由于中序遍历是Left-Head-Right。我们先创建栈,若头不为空则压入头,并把head作为指针移至原位(即1)的左侧(即2),这个操作放在while下面即把左侧所有不为null的元素都压入栈,即1入栈、2入栈、4入栈,而4左侧为null,停止while-if,转而进入while-else把栈顶元素放出(此时栈顶为4),打印4(此时栈内为1(底)-2(顶)),把head指针指向被打印元素的右侧(4右侧为null);再次while大循环,head为空,进入else,打印此时栈顶元素,打印2,(此时栈内仅有1),head指针指向了2的右侧5....

        一致循环直到head==null 且栈内弹出所有元素停止。

   

   

  1. //二叉树中序遍历 左>头>右
  2. public static void inOrder(Node head){
  3. Stack<Node> stack = new Stack<>();
  4. while(head!=null || !stack.isEmpty()){
  5. if(head!=null){
  6. stack.push(head);
  7. head = head.left;
  8. }
  9. else{
  10. head = stack.pop();
  11. System.out.print(head.val);
  12. head = head.right;
  13. }
  14. }
  15. }

后序遍历:

        后序遍历 Left-Right-Head。用了两个栈,首栈首先压入头部,再圧左侧,再压右侧。

而后将首栈弹出,顺序为头-右-左(注意左右被首栈倒出时颠倒),被尾栈接收为头(在最底层)-右-左。最后将尾栈遍历倒出,最终顺序为左-右-头,即后序遍历。

   

  1. //二叉树后序遍历 左>右>头 利用一个辅助栈,只需要反向造即可
  2. public static void posOrder(Node head){
  3. Stack<Node> stack = new Stack<>();
  4. Stack<Node> helpStack = new Stack<>();
  5. stack.add(head);
  6. while(!stack.isEmpty()){
  7. head = stack.pop();
  8. helpStack.push(head);
  9. if(head.left!=null)
  10. stack.push(head.left);
  11. if(head.right!=null)
  12. stack.push(head.right);
  13. }
  14. while(!helpStack.isEmpty()){//把辅助栈倒出来
  15. System.out.print(helpStack.pop().val);
  16. }
  17. }

最后,对调用方法进行测试

   

  1. public static class Node{
  2. int val;
  3. Node left;
  4. Node right;
  5. Node(int x){
  6. this.val = x;
  7. left = null;
  8. right = null;
  9. }
  10. }
  11. public static void main(String[] args){
  12. Node head = new Node(1);
  13. head.left = new Node(2);
  14. head.right = new Node(3);
  15. head.left.left = new Node(4);
  16. head.left.right = new Node(5);
  17. head.right.left = new Node(6);
  18. head.right.right = new Node(7);
  19. System.out.print("前序遍历");
  20. preOrder(head);
  21. System.out.println();
  22. System.out.print("中序遍历");
  23. inOrder(head);
  24. System.out.println();
  25. System.out.print("后序遍历");
  26. posOrder(head);
  27. System.out.println();
  28. }

结果

     
   

  1. ================recursive========================
  2. pre-order:1245367
  3. in-Order:4251637
  4. pos-Order:4526731
  5. Process finished with exit code 0


 

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号