1. 程式人生 > >使用java實現二叉樹的遍歷

使用java實現二叉樹的遍歷

                             二叉樹連結串列儲存遍歷的java實現  

       所謂遍歷(Traversal)是指沿著某條搜尋路線,依次對樹中每個結點均做一次且僅做一次訪問,對二叉樹的遍歷就是將非線性結構的二叉樹中的節點排列在一個線性序列上的過程。訪問結點所做的操作依賴於具體的應用問題。 遍歷是二叉樹上最重要的運算之一,是二叉樹上進行其它運算之基礎。

1.順序儲存的二叉樹遍歷

    直接遍歷底層陣列,沒有什麼難度。

2.採用連結串列儲存的二叉樹遍歷

    有兩種遍歷方式:

  • 深度優先遍歷:先訪問樹中最深層次的節點   
  1. DLR:前序遍歷(PreorderTraversal亦稱(先序遍歷))
  2. LDR:中序遍歷(InorderTraversal)
  3. LRD:後序遍歷(PostorderTraversal)     

        深度遍歷的先序遍歷、中序遍歷、後序遍歷這三種遍歷方式都是針對根節點(D)而言的。先處理根節點的就是先序遍歷,其  次處理根節點的就是中序遍歷,最後處理根節點的就是後序遍歷。

        從根結點出發,逆時針沿著二叉樹外緣移動,對每個結點均途徑三次,最後回到根結點。

  • 廣度優先遍歷:逐層訪問每層節點,先訪問根節點,然後訪問第二層的節點。。。以此類推。因此廣度優先遍歷又稱為按層遍歷。

      先遍歷第一層(根節點),再遍歷根節點的兩個子節點(第二層)。。。逐層遍歷二叉樹的所有節點。

      為了實現廣度優先遍歷,可以藉助具有“FIFO”特徵的佇列實現,如下:

    (1)建立一個佇列(先進先出),把樹的根節點壓入佇列;

    (2)從佇列中彈出一個節點(第一次彈出的就是根節點),然後把該節點的左、右節點壓入佇列,如果沒有子節點,則說明 已經到達葉子節點;

    (3)迴圈重複執行第(2)步,直到佇列為空。當佇列為空時,說明所有的葉子節點都已經過了佇列,也就完成了遍歷。

深度優先遍歷的java程式碼實現:

import java.util.ArrayList;
import java.util.List;

import qiuzhitest.TwoLinkBinTree.Node;

/*
 * 這裡是利用二叉樹的二叉連結串列儲存來舉例子,具體的可行性做法可以使用一個Tree介面來實現複用性
 * */
public class TreeIterator {
	//先序遍歷
	public static List<Node> preIterator(TwoLinkBinTree tree){
		
		return preIterator(tree.getRoot());
	}
	private static List<Node> preIterator(Node node){
		
		List<Node> list = new ArrayList<Node>();
		
		//優先遍歷根節點(相對於樹和子樹來說)
		list.add(node);
		
		//如果節點的左孩子不為空,則遞迴遍歷左孩子,其遍歷順序在根節點之後
		if(node.left!=null){
			list.addAll(preIterator(node.left));
		}
		
		//如果節點的右孩子不為空,則遞迴遍歷右孩子,其遍歷順序在左孩子之後
		if(node.right!=null){
			list.addAll(preIterator(node.right));
		}
		return list;
	}
	
	//中序遍歷
	public static List<Node> inIterator(TwoLinkBinTree tree){
		return inIterator(tree.getRoot());
	}
	private static List<Node> inIterator(Node node){
		List<Node> list=new ArrayList<Node>();
		
		//優先遞迴遍歷左孩子節點
		if(node.left!=null){
			list.addAll(inIterator(node.left));
		}
		
		//再來遍歷根節點(左孩子節點遍歷的盡頭就是當前需要遍歷的結點)
		list.add(node);
		
		//最後遞迴遍歷右孩子節點
		if(node.right!=null){
			list.addAll(inIterator(node.right));
		}
		
		//將遍歷結果返回
		return list;
	}
	
	//後序遍歷
	public static List<Node> postIterator(TwoLinkBinTree tree){
		return postIterator(tree.getRoot());
	}
	private static List<Node> postIterator(Node node){
		List<Node> list = new ArrayList<Node>();
		
		//優先遞迴遍歷左孩子節點
		if(node.left!=null){
			list.addAll(postIterator(node.left));
		}
		
		//再來遞迴遍歷右孩子節點
		if(node.right!=null){
			list.addAll(postIterator(node.right));
		}
		
		//當不存在左右節點後,遍歷根節點
		list.add(node);
		
		return list;
	}
}

廣度優先遍歷的java程式碼實現:

public List<TreeNode> breadthFirst(){
        //定義一個佇列,佇列裡面存放的元素為節點
		Queue<TreeNode> queue = new ArrayDeque<TreeNode>();
        
        //定義一個集合,用來儲存遍歷的結果
		List<TreeNode> list = new ArrayList<TreeNode>();
		
        //第一步將根節點進佇列
		if(root != null){
			//將根元素加入到“佇列”
			queue.offer(root);
		}
		
        //只要佇列不為空則迴圈
		while(!queue.isEmpty()){
			//將該佇列的“隊尾”的元素新增到List中
			list.add(queue.peek());
            
            //將佇列的尾元素出佇列
			TreeNode p = queue.poll();

			//如果左子節點不為null,將它加入到“佇列”
			if(p.left != null){
				queue.offer(p.left);
			}
			
            //如果右子節點不為null,將它加入到“佇列”
			if(p.right != null){
				queue.offer(p.right);
			}
		}
		
		return list;
}

參考文章如下: 

上次忘記先把佇列的實現寫了,所以接下來先把佇列的java實現給完成了。加油!