二叉樹的多種遍歷

二叉樹的遍歷:

遞歸就不用說了,3行代碼就解決了

面試的時候遇到這個,想不起來了,現在總結一下。

參考博客:https://blog.csdn.net/u012102306/article/details/52841163

https://www.cnblogs.com/SHERO-Vae/p/5800363.html

先序遍歷:

根左右。當前節點p放入棧中,判斷P是否有左孩子,如果沒有,則從棧中取出這個節點,並且將p的右孩子當做當前節點。如果有左孩子,則p的左孩子爲當前節點。知道p爲空並且棧爲空,遍歷結束。

p遍歷樹的時候直接輸出再入棧

	/**
	 * 二叉樹的先序遍歷
	 * 遍歷的時候輸出
	 * 根左右
	 * 1245367
	 */
	public static void preOder(Tree tree){
		Tree p = tree;
		Stack<Tree> s = new Stack<Tree>();
		while(p != null || s.isEmpty()==false){
//			如果有左子樹,入棧
			while(p != null){
				System.out.print(p.val);
				s.push(p);
				p = p.left;
			}
//			p指向棧頂元素
			if(!s.isEmpty()){
				Tree pop = s.pop();
				p = pop;
				p = p.right;
			}
		}
	}

中序遍歷:

等到出棧的時候再輸出棧頂元素

	/**
	 * 二叉樹的中序遍歷
	 * 出棧時再輸出
	 * 左根右
	 * 4251637
	 */
	public static void midOder(Tree tree){
		Stack<Tree> s = new Stack<Tree>();
		Tree p = tree;
		while(p != null || s.isEmpty()==false){
			while(p != null){
				s.push(p);
				p = p.left;
			}//
			if(s.isEmpty()==false){
				Tree t = s.pop();
				System.out.print(t.val);
//				p指向棧頂元素
				p = t;
				p = p.right;
			}//if
		}//while
	}

後序遍歷:

保證根節點必須在左右節點都遍歷之後才能遍歷,兩個引用pre(上一次訪問的節點),cur(當前訪問的節點)

如果左右節點爲空,則爲葉子節點,輸出

如果pre不爲空,並且當前節點的左子樹或者右子樹等於pre,則表示左右節點已經訪問過,輸出

否則,

將當前節點的右孩子,左孩子分別入棧,右孩子先入棧,左孩子再入棧,這樣棧頂的元素就是左孩子

/**
	 * 二叉樹的後序遍歷
	 * 左右根
	 * 4526731
	 */
	public static void postOder(Tree tree){
		Tree pre = null;//上一次訪問的節點
		Tree cur = null;//當前節點
		Stack<Tree> s = new Stack<Tree>();
//		根節點先入棧
		s.push(tree);
		while(s.isEmpty()==false){
//			cur指向棧頂元素
			cur = s.peek();
			if((cur.left==null && cur.right==null)
					||
				(pre!=null&&(pre==cur.left || pre == cur.right))){
//				葉子節點或者當前節點的左右節點已經遍歷過
				System.out.print(cur.val);
				s.pop();
				pre = cur;
			}else{
//				先push右節點,再左節點,這樣左節點在上面,下次遍歷棧得到的棧頂元素就是左節點
				if(cur.right!= null){
					s.push(cur.right);
				}
				if(cur.left!= null){
					s.push(cur.left);
				}
				
			}
		}
	}

層序遍歷:

/**
	 * 二叉樹的層序遍歷
	 * 1234567
	 * @throws Exception 
	 */
	public static void Oder(Tree tree){
//		使用隊列
		LinkedBlockingQueue<Tree> q = new LinkedBlockingQueue<Tree>();
		Tree p = tree;
//		根節點先進隊列
		q.add(p);
		while(q.isEmpty()==false){
			Tree top = q.poll();
			p = top;
			System.out.print(p.val);
//			每次輸出隊列中一個元素,將這個節點的左右節點入隊
			if(p.left!=null){
				q.add(p.left);
			}
			if(p.right!= null){
				q.add(p.right);
			}
		}
	}

按層遍歷,並且按層換行:

/**
	 * 二叉樹的層序遍歷,按層輸出
	 * @throws Exception 
	 */
	public static void Oder2(Tree tree){
//		使用隊列
		LinkedBlockingQueue<Tree> q = new LinkedBlockingQueue<Tree>();
//		last執行每一行的最後一個元素
		Tree last = tree;
//		nlast指向隊列中最新進入的一個元素
		Tree nlast = tree;
		Tree p = tree;
//		根節點先進隊列
		q.add(p);
		while(!q.isEmpty()){
			p = q.poll();
			System.out.print(p.val);
//			nlast始終表示這一層的最後一個元素
			if(p.left!=null){
				q.add(p.left);
				nlast = p.left;
			}
			if(p.right!=null){
				q.add(p.right);
				nlast = p.right;
			}
			if(last == p){
//				當前出隊的元素是某一行的最後一個元素,這時候輸出換行,並且last指向下一行的最後一個元素
				System.out.println();
				last = nlast;
			}//
			
			
		}
		
	}

二叉樹結構:

class Tree{
	int val;
	Tree left;
	Tree right;
	public Tree(int val){
		this.val = val;
	}
}

測試代碼:

public static void main(String[] args) {
		Tree root = new Tree(1);
		Tree r1 = new Tree(2);
		Tree r2 = new Tree(3);
		Tree r3 = new Tree(4);
		Tree r4 = new Tree(5);
		Tree r5= new Tree(6);
		Tree r6 = new Tree(7);
		root.left = r1;
		root.right = r2;
		r1.left = r3;
		r1.right = r4;
		r2.left = r5;
		r2.right = r6;
		System.out.println("前序:");
		preOder(root);
		System.out.println("\n中序:");
		midOder(root);
		System.out.println("\n後序:");
		postOder(root);
		System.out.println("\n層序:");
		Oder(root);
		System.out.println("\n按層輸出:");
		Oder2(root);
	}

測試結果:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章