【Java】 劍指offer(32) 從上往下打印二叉樹

本文參考自《劍指offer》一書,代碼採用Java語言。html

更多:《劍指Offer》Java實現合集  java

題目 

  (一)從上往下打印出二叉樹的每一個結點,同一層的結點按照從左到右的順序打印。node

  (二)從上到下按層打印二叉樹,同一層的結點按從左到右的順序打印,每一層打印到一行。面試

  (三)請實現一個函數按照之字形順序打印二叉樹,即第一行按照從左到右的順序打印,第二層按照從右到左的順序打印,第三行再按照從左到右的順序打印,其餘行以此類推。編程

思路

  (一)不分行從上往下打印二叉樹:該題即爲對二叉樹的層序遍歷,結點知足先進先出的原則,採用隊列。每從隊列中取出頭部結點並打印,若其有子結點,把子結點放入隊列尾部,直到全部結點打印完畢。數組

	/*
	 * 不分行從上往下打印二叉樹
	 */
	// 題目:從上往下打印出二叉樹的每一個結點,同一層的結點按照從左到右的順序打印。
	public void printTree1(TreeNode root) {
		if (root == null)
			return;
		LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
		queue.offer(root);
		TreeNode node = null;
		while (queue.size()!=0) {
			node = queue.poll();
			System.out.print(node.val + " ");
			if (node.left != null)
				queue.offer(node.left);
			if (node.right != null)
				queue.offer(node.right);
		}
		System.out.println();
	}

  (二)分行從上到下打印二叉樹:一樣使用隊列,但比第一題增長兩個變量:當前層結點數目pCount,下一層結點數目nextCount。根據當前層結點數目來打印當前層結點,同時計算下一層結點數目,以後令pCount等於nextCount,重複循環,直到打印完畢。ide

	/*
	 * 分行從上到下打印二叉樹
	 */
	// 題目:從上到下按層打印二叉樹,同一層的結點按從左到右的順序打印,每一層
	// 打印到一行。
	public void printTree2(TreeNode root) {
		if (root == null)
			return;
		LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
		queue.offer(root);
		TreeNode node = null;
		int pCount = 0;		 //當前層結點數目
		int nextCount = 1;   //下一層結點數目
		while (!queue.isEmpty()) {
			pCount = nextCount;
			nextCount = 0;
			//打印當前層數字,並計算下一層結點數目
			for (int i = 1; i <= pCount; i++) {
				node = queue.poll();
				System.out.print(node.val + " ");
				if (node.left != null) {
					queue.offer(node.left);
					nextCount++;
				}
				if (node.right != null) {
					queue.offer(node.right);
					nextCount++;
				}
			}
			System.out.println();
		}
	}

  (三)之字形打印二叉樹:函數

    (1)本身開始想的方法:在(二)的基礎上,多定義一個表示當前層數的變量level。每層結點不直接打印,放入一個數組中,根據此時的層數level的奇偶來決定正向仍是反向打印數組。post

	/*
	 * 之字形打印二叉樹
	 */
	// 題目:請實現一個函數按照之字形順序打印二叉樹,即第一行按照從左到右的順
	// 序打印,第二層按照從右到左的順序打印,第三行再按照從左到右的順序打印,
	// 其餘行以此類推。
	/**
	 * 本身開始想的方法,採用數組存儲每層的數字,根據當前層數肯定正反向打印數組
	 */
	public void printTree3_1(TreeNode root) {
		if (root == null)
			return;
		LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
		queue.offer(root);
		TreeNode node = null;
		int pCount = 0;		 //當前層結點數目
		int nextCount = 1;   //下一層結點數目
		int level=1;    //層數
		int[] pNums=null;    //用於存儲當前層的數字
		while (!queue.isEmpty()) {
			pCount = nextCount;
			nextCount = 0;
			pNums=new int[pCount];
			//存儲當前層數字,並計算下一層結點數目
			for (int i = 0; i < pCount; i++) {
				node = queue.poll();
				pNums[i]=node.val;
				if (node.left != null) {
					queue.offer(node.left);
					nextCount++;
				}
				if (node.right != null) {
					queue.offer(node.right);
					nextCount++;
				}
			}
			//根據當前層數肯定正向或者反向打印數組
			if((level&1)!=0 ) {
				for(int i=0;i<pCount;i++) {
					System.out.print(pNums[i]+" ");
				}
			}else {
				for(int i=pCount-1;i>=0;i--) {
					System.out.print(pNums[i]+" ");
				}
			}
			level++;
			System.out.println();
		}
	}

    (2)書中提供的方法:採用兩個棧,對於不一樣層的結點,一個棧用於正向存儲,一個棧用於逆向存儲,打印出來就正好是相反方向。測試

	/**
	 * 採用兩個棧進行操做的方法
	 */
	public void printTree3_2(TreeNode root) {
		if (root == null)
			return;
		Stack<TreeNode> stack1 = new Stack<TreeNode>();
		Stack<TreeNode> stack2 = new Stack<TreeNode>();
		TreeNode node = null;
		stack1.push(root);
		while(!stack1.empty() || !stack2.empty()) {
			while(!stack1.empty()) {
				node=stack1.pop();
				System.out.print(node.val + " ");
				if (node.left != null)
					stack2.push(node.left);
				if (node.right != null)
					stack2.push(node.right);
			}
			System.out.println();
			while(!stack2.empty()) {
				node=stack2.pop();
				System.out.print(node.val + " ");
				if (node.right != null)
					stack1.push(node.right);
				if (node.left != null)
					stack1.push(node.left);
			}
			System.out.println();
		}
	}

  

測試算例 

  1.功能測試(徹底二叉樹;左斜樹;右斜樹)

  2.特殊測試(null;一個結點)

完整Java代碼

含測試代碼:

import java.util.LinkedList;
import java.util.Stack;
/**
 * 
 * @Description 面試題32:從上往下打印二叉樹
 *
 * @author yongh
 */

public class PrintTreeFromTopToBottom {
	public class TreeNode {
		int val = 0;
		TreeNode left = null;
		TreeNode right = null;

		public TreeNode(int val) {
			this.val = val;
		}
	}
	
	
	/*
	 * 	不分行從上往下打印二叉樹
	 */
	// 題目:從上往下打印出二叉樹的每一個結點,同一層的結點按照從左到右的順序打印。
	public void printTree1(TreeNode root) {
		if (root == null)
			return;
		LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
		queue.offer(root);
		TreeNode node = null;
		while (queue.size()!=0) {
			node = queue.poll();
			System.out.print(node.val + " ");
			if (node.left != null)
				queue.offer(node.left);
			if (node.right != null)
				queue.offer(node.right);
		}
		System.out.println();
	}	

	/*
	 * 分行從上到下打印二叉樹
	 */
	// 題目:從上到下按層打印二叉樹,同一層的結點按從左到右的順序打印,每一層
	// 打印到一行。
	public void printTree2(TreeNode root) {
		if (root == null)
			return;
		LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
		queue.offer(root);
		TreeNode node = null;
		int pCount = 0;		 //當前層結點數目
		int nextCount = 1;   //下一層結點數目
		while (!queue.isEmpty()) {
			pCount = nextCount;
			nextCount = 0;
			//打印當前層數字,並計算下一層結點數目
			for (int i = 1; i <= pCount; i++) {
				node = queue.poll();
				System.out.print(node.val + " ");
				if (node.left != null) {
					queue.offer(node.left);
					nextCount++;
				}
				if (node.right != null) {
					queue.offer(node.right);
					nextCount++;
				}
			}
			System.out.println();
		}
	}
	
	/*
	 * 之字形打印二叉樹
	 */
	// 題目:請實現一個函數按照之字形順序打印二叉樹,即第一行按照從左到右的順
	// 序打印,第二層按照從右到左的順序打印,第三行再按照從左到右的順序打印,
	// 其餘行以此類推。
	/**
	 * 本身開始想的方法,採用數組存儲每層的數字,根據當前層數肯定正反向打印數組
	 */
	public void printTree3_1(TreeNode root) {
		if (root == null)
			return;
		LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
		queue.offer(root);
		TreeNode node = null;
		int pCount = 0;		 //當前層結點數目
		int nextCount = 1;   //下一層結點數目
		int level=1;    //層數
		int[] pNums=null;    //用於存儲當前層的數字
		while (!queue.isEmpty()) {
			pCount = nextCount;
			nextCount = 0;
			pNums=new int[pCount];
			//存儲當前層數字,並計算下一層結點數目
			for (int i = 0; i < pCount; i++) {
				node = queue.poll();
				pNums[i]=node.val;
				if (node.left != null) {
					queue.offer(node.left);
					nextCount++;
				}
				if (node.right != null) {
					queue.offer(node.right);
					nextCount++;
				}
			}
			//根據當前層數肯定正向或者反向打印數組
			if((level&1)!=0 ) {
				for(int i=0;i<pCount;i++) {
					System.out.print(pNums[i]+" ");
				}
			}else {
				for(int i=pCount-1;i>=0;i--) {
					System.out.print(pNums[i]+" ");
				}
			}
			level++;
			System.out.println();
		}
	}
	
	/**
	 * 採用兩個棧進行操做的方法
	 */
	public void printTree3_2(TreeNode root) {
		if (root == null)
			return;
		Stack<TreeNode> stack1 = new Stack<TreeNode>();
		Stack<TreeNode> stack2 = new Stack<TreeNode>();
		TreeNode node = null;
		stack1.push(root);
		while(!stack1.empty() || !stack2.empty()) {
			while(!stack1.empty()) {
				node=stack1.pop();
				System.out.print(node.val + " ");
				if (node.left != null)
					stack2.push(node.left);
				if (node.right != null)
					stack2.push(node.right);
			}
			System.out.println();
			while(!stack2.empty()) {
				node=stack2.pop();
				System.out.print(node.val + " ");
				if (node.right != null)
					stack1.push(node.right);
				if (node.left != null)
					stack1.push(node.left);
			}
			System.out.println();
		}
	}

	//============測試代碼==============
	private void test(int testNum,TreeNode root) {
		System.out.println("=========test"+testNum+"===========");
		System.out.println("method1:");
		printTree1(root);
		System.out.println("method2:");
		printTree2(root);
		System.out.println("method3_1:");
		printTree3_1(root);
		System.out.println("method3_2:");
		printTree3_2(root);
	}
	
	//null
	private void test1() {
		TreeNode node=null;
		test(1, node);
	}
	
	//單個結點
	private void test2() {
		TreeNode node=new TreeNode(1);
		test(2, node);
	}
	
	//左斜
	private void test3() {
		TreeNode node1=new TreeNode(1);
		TreeNode node2=new TreeNode(2);
		TreeNode node3=new TreeNode(3);
		node1.left=node2;
		node2.left=node3;
		test(3, node1);
	}
	
	//右斜
	private void test4() {
		TreeNode node1=new TreeNode(1);
		TreeNode node2=new TreeNode(2);
		TreeNode node3=new TreeNode(3);
		node1.right=node2;
		node2.right=node3;
		test(4, node1);
	}
	
	//徹底二叉樹
	private void test5() {
		TreeNode[] nodes = new TreeNode[15];
		for(int i=0;i<15;i++) {
			nodes[i]= new TreeNode(i+1);
		}
		for(int i=0;i<7;i++) {
			nodes[i].left=nodes[2*i+1];
			nodes[i].right=nodes[2*i+2];
		}
		test(5, nodes[0]);
	}
	
	public static void main(String[] args) {
		PrintTreeFromTopToBottom demo= new PrintTreeFromTopToBottom();
		demo.test1();
		demo.test2();
		demo.test3();
		demo.test4();
		demo.test5();
	}
}

  

=========test1===========
method1:
method2:
method3_1:
method3_2:
=========test2===========
method1:
1 
method2:
1 
method3_1:
1 
method3_2:
1 

=========test3===========
method1:
1 2 3 
method2:
1 
2 
3 
method3_1:
1 
2 
3 
method3_2:
1 
2 
3 

=========test4===========
method1:
1 2 3 
method2:
1 
2 
3 
method3_1:
1 
2 
3 
method3_2:
1 
2 
3 

=========test5===========
method1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 
method2:
1 
2 3 
4 5 6 7 
8 9 10 11 12 13 14 15 
method3_1:
1 
3 2 
4 5 6 7 
15 14 13 12 11 10 9 8 
method3_2:
1 
3 2 
4 5 6 7 
15 14 13 12 11 10 9 8 
PrintTreeFromTopToBottom

 

收穫

  1.層序遍歷時,通常都要用到隊列,能夠用LinkedList類(方法:poll() 和 offer(Obj) )。

  2.在分行打印時,定義的兩個int有明顯實際意義(當前層結點數目,下一層結點數目)。本身編程時,一開始只知道要設置兩個變量,但沒有去想這兩個變量的實際意義。當明白變量意義時,本身的思路會更清晰,並且代碼可讀性也更好。

  

更多:《劍指Offer》Java實現合集 

相關文章
相關標籤/搜索