按之字形顺序打印二叉树
一、总结
1、一行一行打印用的队列做BFS(广度优先搜索)
2、这里因为要区分奇偶行,用了两个队列。
3、效率的保障用的是奇数行存的时候是从左向右存入队列,偶数行的时候是从右向左存。而不是偶数行节点也会从左向右存入队列,然后array_reverse(),大量数据的时候这样效率很低的。
二、题目描述
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
三、代码
代码一:java
1 /** 2 * 大家的实现很多都是将每层的数据存进ArrayList中,偶数层时进行reverse操作, 3 * 在海量数据时,这样效率太低了。 4 * (我有一次面试,算法考的就是之字形打印二叉树,用了reverse, 5 * 直接被鄙视了,面试官说海量数据时效率根本就不行。) 6 * 7 * 下面的实现:不必将每层的数据存进ArrayList中,偶数层时进行reverse操作,直接按打印顺序存入 8 * 思路:利用Java中的LinkedList的底层实现是双向链表的特点。 9 * 1)可用做队列,实现树的层次遍历 10 * 2)可双向遍历,奇数层时从前向后遍历,偶数层时从后向前遍历 11 */ 12 public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) { 13 ArrayList<ArrayList<Integer>> ret = new ArrayList<>(); 14 if (pRoot == null) { 15 return ret; 16 } 17 ArrayList<Integer> list = new ArrayList<>(); 18 LinkedList<TreeNode> queue = new LinkedList<>(); 19 queue.addLast(null);//层分隔符 20 queue.addLast(pRoot); 21 boolean leftToRight = true; 22 23 while (queue.size() != 1) { 24 TreeNode node = queue.removeFirst(); 25 if (node == null) {//到达层分隔符 26 Iterator<TreeNode> iter = null; 27 if (leftToRight) { 28 iter = queue.iterator();//从前往后遍历 29 } else { 30 iter = queue.descendingIterator();//从后往前遍历 31 } 32 leftToRight = !leftToRight; 33 while (iter.hasNext()) { 34 TreeNode temp = (TreeNode)iter.next(); 35 list.add(temp.val); 36 } 37 ret.add(new ArrayList<Integer>(list)); 38 list.clear(); 39 queue.addLast(null);//添加层分隔符 40 continue;//一定要continue 41 } 42 if (node.left != null) { 43 queue.addLast(node.left); 44 } 45 if (node.right != null) { 46 queue.addLast(node.right); 47 } 48 } 49 50 return ret; 51 }
代码二:php
1 <?php 2 3 /*class TreeNode{ 4 var $val; 5 var $left = NULL; 6 var $right = NULL; 7 function __construct($val){ 8 $this->val = $val; 9 } 10 }*/ 11 function MyPrint($pRoot) 12 { 13 if($pRoot == NULL) 14 return []; 15 $current = 0; //记录当前行是奇数行还是偶数行 16 $next = 1; 17 18 $stack[0] = array(); 19 $stack[1] = array(); 20 $resultQueue = array(); 21 22 array_push($stack[0], $pRoot); 23 24 $i = 0; //记录达到数的第多少层 25 $result = array(); 26 $result[0]= array(); 27 28 while(!empty($stack[0]) || !empty($stack[1])){ 29 $node = array_pop($stack[$current]); 30 array_push($result[$i], $node->val); 31 32 //var_dump($resultQueue);echo "</br>"; 33 if($current == 0){ //如果当前为奇数行,从左到右存入节点 34 if($node->left != NULL) 35 array_push($stack[$next], $node->left); 36 if($node->right != NULL) 37 array_push($stack[$next], $node->right); 38 }else{ //当前为偶数行,从右向左存入节点 39 if($node->right != NULL) 40 array_push($stack[$next], $node->right); 41 if($node->left != NULL) 42 array_push($stack[$next], $node->left); 43 } 44 45 if(empty($stack[$current])){ //打印完一行之后 46 $current = 1-$current; 47 $next = 1-$next; 48 if(!empty($stack[0]) || !empty($stack[1])){ 49 $i++; 50 $result[$i] = array(); 51 } 52 } 53 54 } 55 return $result; 56 57 }
四、测试题-简答题
1、php中类中的构造器的函数名是怎么写?
解答:function __construct($val){}
2、php中如何判断一个链表节点是否为空?
解答:if($pRoot == NULL)
3、php中如何返回一个空数组?
解答:return [];
4、之字形输出树的题目中,队列里面存节点还是值,答案数组里面存节点还是值?
解答:队列里面存节点,答案数组里面存值。
5、如何实现奇偶行切换?
解答:$current = 0; //记录当前行是奇数行还是偶数行 $current = 1-$current;
6、之字形输出树的题目中,如何判断树到达了下一层?
解答:当前队列打印完之后。if(empty($stack[$current]))
7、之字形输出树的题目中,答案数组继续加行的前提是什么?
解答:奇数行队列或者偶数行队列至少有一个还有值。也就是非空。if(!empty($stack[0]) || !empty($stack[1]))
8、php中如何判断一个数组非空?
解答:用!empty()。if(!empty($stack[0]) || !empty($stack[1]))
9、之字形输出树的题目中,要保证奇偶行操作方式不同,需要几个队列?
解答:两个。
10、之字形输出树的题目中,如何提高效率?
解答:奇数行队列从左向右存,偶数行队列从右向左存。
11、树的层次遍历,用的是什么数据结构?
解答:队列。
12、队列数据结构的操作核心是?
解答:判断队列是否有值,有值的话就做入队或出队操作。