二叉樹的遍歷:
遞歸就不用說了,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);
}