1. 程式人生 > >二叉樹前序、中序、後序遞迴與非遞迴遍歷+層序遍歷(java)

二叉樹前序、中序、後序遞迴與非遞迴遍歷+層序遍歷(java)

 

 

前序遞迴遍歷演算法:訪問根結點-->遞迴遍歷根結點的左子樹-->遞迴遍歷根結點的右子樹

 中序遞迴遍歷演算法:遞迴遍歷根結點的左子樹-->訪問根結點-->遞迴遍歷根結點的右子樹

 後序遞迴遍歷演算法:遞迴遍歷根結點的左子樹-->遞迴遍歷根結點的右子樹-->訪問根結點

層序遍歷演算法:將每個節點放入佇列中。依據佇列先進先出的特點,順序遍歷樹。直到佇列為空

二叉樹為:

Java程式碼:

二叉樹節點定義Treel.java:

package Test_1;

public class TreeNode {
	int data;
	TreeNode left;
	TreeNode right;
	
	public TreeNode(){};
	
	TreeNode(int data,TreeNode left, TreeNode right){
		super();//千萬別忘了,不然會出錯,如果沒有這句在node9例項化時報錯
		this.data = data;
		this.left = left;
		this.right = right;
	}
	
	public int getData(){
		return data;
	}
	
	public void setData(int data){
		this.data = data;
	}
	
	public TreeNode getLeft(){
		return left;
	}
	
	public void setLeft(TreeNode left){
		this.left = left;
	}
	
	public TreeNode getRight(){
		return right;
	}
	
	public void setRight(TreeNode right){
		this.right = right;
	}
}

二叉樹遍歷實現程式碼BinaryTree.java:

package Test_1;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class BinaryTree {
	//前序遞迴實現
	public void preOrderRe(TreeNode root){
		//System.out.println(biTree.value);
		if(root != null){
			System.out.print(root.getData()+", ");
			preOrderRe(root.getLeft());
			preOrderRe(root.getRight());
		}
	}
	
	//前序非遞迴的方式
	public void preOrderNonRecursive(TreeNode root){
		Stack<TreeNode> stack = new Stack<>();
		while(true){
			while(root !=null){
				System.out.print(root.getData()+", ");
				stack.push(root);
				root = root.getLeft();
			}
			if(stack.isEmpty()) break;//遍歷完最後一個節點時呼叫這一句跳出迴圈
			root = stack.pop();
			root = root.getRight();
		}
	}
	
	//中序遍歷+遞迴
	public void inOrder(TreeNode root){
		if(root != null){
			inOrder(root.getLeft());
			System.out.print(root.getData()+", ");
			inOrder(root.getRight());
		}
	}
	
	//中序遍歷+非遞迴
	public void inOrderNonRecursive(TreeNode root){
		Stack<TreeNode> stack = new Stack<>();
		while(true){
			while(root != null){
				stack.push(root);
				root = root.getLeft();
			}
			if(stack.isEmpty()) break;
			root = stack.pop();
			System.out.print(root.getData()+", ");
			root = root.getRight();
		}
	}
	
	//後序遍歷+遞迴
	public void postOrder(TreeNode root){
		if(root != null){
			postOrder(root.getLeft());
			postOrder(root.getRight());
			System.out.print(root.getData()+", ");
		}
	}
	
	//後續遍歷+非遞迴(這是最難的一個)
    //主要思想:首先遍歷root根節點的所有左節點,並依次入棧。對出棧的元素,如果沒有右兒子或者
    //雖然有右兒子但右兒子已完成遍歷,即可完成出棧;否則,再次入棧,並把右兒子入棧,遍歷右
    //兒子的所有左兒子。
    //後序遍歷的難點在於:需要判斷上次訪問的節點是位於左子樹,還是右子樹。若是位於左子樹,
    //則需跳過根節點,先進入右子樹,再回頭訪問根節點;若是位於右子樹,則直接訪問根節點。
	public void postOrderNonRecursive(TreeNode root){
		Stack<TreeNode> stack = new Stack<>();
		while(true){
			if(root !=null){
				stack.push(root);
				root = root.getLeft();
			}else{
				if(stack.isEmpty()) return;
				
				if(stack.lastElement().getRight() == null){//Vector中lastElement(),Returns the last component of the vector.
					root = stack.pop();
					System.out.print(root.getData()+", ");
					while(root == stack.lastElement().getRight()){
						System.out.print(stack.lastElement().getData()+", ");
						root = stack.pop();
						if(stack.isEmpty()){
							break;
						}
					}
				}
				
				if(!stack.isEmpty())
					root = stack.lastElement().getRight();
				else
					root = null;
			}
		}
	}
	
	//層序遍歷
	/*offer,add區別:
	 *  一些佇列有大小限制,因此如果想在一個滿的佇列中加入一個新項,多出的項就會被拒絕。 這時新的offer 方法
	 * 就可以起作用了。它不是對呼叫 add() 方法丟擲一個 unchecked 異常,而只是得到由 offer() 返回的 false。 
	 *  poll,remove區別: 
	 *  remove() 和 poll() 方法都是從佇列中刪除第一個元素。remove() 的行為與 Collection 介面的版本相似, 
	 *  但是新的 poll() 方法在用空集合呼叫時不是丟擲異常,只是返回 null。因此新的方法更適合容易出現異常條件的情況。
	 */
	public void levelOrder(TreeNode root){
		TreeNode temp;
		Queue<TreeNode> queue = new LinkedList<TreeNode>();
		queue.offer(root);
		while(!queue.isEmpty()){
			temp = queue.poll();
			System.out.print(temp.getData()+", ");
			if(temp.getLeft() != null)
				queue.offer(temp.getLeft());
			if(temp.getRight() != null)
				queue.offer(temp.getRight());
		}
	}
	
	public static void main(String[] args) {
		//注意如果建立使用函式二叉樹,則必須逆序建立,先建立子節點,再逆序往上建立,因為非葉子結點會使用到下面的節點,
		//而初始化是按順序初始化的,不逆序建立會報錯;如果不適用函式建立二叉樹,像下面這樣做,不必用逆序建立
		TreeNode node9 = new TreeNode(8,null, null);
		TreeNode node8 = new TreeNode(4,null, null);
		TreeNode node7 = new TreeNode(2, null, null);
		TreeNode node6 = new TreeNode(7,null, node9);
		TreeNode node5 = new TreeNode(5,node8, null);
		TreeNode node4 = new TreeNode(1, null, node7);
		TreeNode node3 = new TreeNode(9, node6, null);
		TreeNode node2 = new TreeNode(3, node4, node5);
		TreeNode node1 = new TreeNode(6, node2,node3);
		
		BinaryTree tree = new BinaryTree();
		System.out.println("先序遍歷二叉樹(遞迴):");
		tree.preOrderRe(node1);
		System.out.println();
		
		System.out.println("先序遍歷二叉樹(非遞迴):");
		tree.preOrderNonRecursive(node1);
		System.out.println();
		
		System.out.println("中序遍歷二叉樹(遞迴):");
		tree.inOrder(node1);
		System.out.println();
		
		System.out.println("中序遍歷二叉樹(非遞迴):");
		tree.inOrderNonRecursive(node1);
		System.out.println();
		
		System.out.println("後序遍歷二叉樹(遞迴):");
		tree.postOrder(node1);
		System.out.println();
		
		System.out.println("後序遍歷二叉樹(非遞迴):");
		tree.postOrderNonRecursive(node1);
		System.out.println();
		
		System.out.println("層序遍歷二叉樹(遞迴):");
		tree.levelOrder(node1);
		System.out.println();
	}
}

執行結果: