1. 程式人生 > >二叉排序樹的構造、深度優先遍歷、廣度優先遍歷

二叉排序樹的構造、深度優先遍歷、廣度優先遍歷

        之前面試官總是會問到二叉樹的遍歷,自己回答的很不好。甚至可以說想都想不起來。真的應了老師應常說的那句話,你們學的東西都還給老師了啊。。。這兩天在看mysql優化的時候看到了B樹,然後去查閱B樹的知識,又知道B樹又跟二叉排序樹脫不了關係。於是就整理了這篇關於二叉排序樹的相關知識。
        首先我們知道,二叉排序樹的特徵有:(1)如果一個節點的左子樹不空,那麼左子樹的所有節點的值均小於該節點的值;                                                                      (2)如果一個節點的右子樹不空,那麼右子樹的所有節點的值均大於該節點的值;
        1.構造排序二叉樹的基本思想為(使用前序插入)
            (1)首先定義一個根節點,初始化為null             (2)將插入的第一個元素通過節點類打包給根節點             (3)將根節點賦給currentNode這個節點             (4)繼續插入元素,如果該元素大於currentNode.value,那麼就將該元素賦給currentNode.right,把currentNode.right當作currentNode;否則將該元素賦給currentNode.left,把currentNode.left當作currentNode
            (5)重複(4)
       2.二叉樹的遍歷有兩種方式:深度優先遍歷、廣度優先遍歷
           2.1深度優先遍歷

              沿著樹的深度遍歷二叉樹。可以使用前序遍歷(遞迴、非遞迴)、中序遍歷(遞迴、非遞迴)、後續遍歷(遞迴、非遞迴)

           2.2廣度優先遍歷

               一層一層的遍歷,先訪問一個節點,再訪問該節點的鄰接節點

      3.具體程式碼實現(參考文章http://blog.csdn.net/fantasy_lin_/article/details/52751559
package Tree;

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

/*
Created By guolujie in 2017年9月15日
 */
public class MyTree {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		BinaryOrderTree<Integer> tree = new BinaryOrderTree<Integer>();
		tree.insertTreeNode(2);
		tree.insertTreeNode(1);
		tree.insertTreeNode(0);
		tree.insertTreeNode(9);
		tree.insertTreeNode(6);
		tree.insertTreeNode(7);
		tree.insertTreeNode(5);
		tree.insertTreeNode(8);
		tree.insertTreeNode(3);
		tree.insertTreeNode(4);
		System.out.print("前序遍歷(遞迴):");
		tree.preOrderTraverse(tree.getRoot());
		System.out.println();
		System.out.print("中序遍歷(遞迴):");
		tree.midOrderTraverse(tree.getRoot());
		System.out.println();
		System.out.print("後序遍歷(遞迴):");
		tree.postOrderTraverse(tree.getRoot());
		System.out.println();
		System.out.print("前序遍歷(非遞迴):");
		tree.preOrderTraverseNo(tree.getRoot());
		System.out.println();
		System.out.print("中序遍歷(非遞迴):");
		tree.midOrderTraverseNo(tree.getRoot());
		System.out.println();
		System.out.print("後序遍歷(非遞迴):");
		tree.postOrderTraverseNo(tree.getRoot());
		System.out.println();
		System.out.print("廣度優先遍歷:");
		tree.breadthFirstTraverse(tree.getRoot());
	}

}
//首先定義節點類
class TreeNode<E extends Comparable<E>>{
	E value;
	TreeNode<E> left;
	TreeNode<E> right;
	TreeNode(E value){
		this.value = value;
		left = null;
		right = null;
	}
}
//通過前序插入節點,構造二叉排序樹
class BinaryOrderTree<E extends Comparable<E>>{
	private TreeNode<E> root;
    BinaryOrderTree() {
		root=null;
	}
    
    public void insertTreeNode(E value){
    	if(root==null)
    	{
    		root = new TreeNode<E>(value);
    		return;
    	}
    	TreeNode<E> currentNode = root;
    	while(true){
    		if(value.compareTo(currentNode.value)>0){
    			if(currentNode.right==null){
    				currentNode.right = new TreeNode<E>(value);
    				break;
    			}
    			currentNode = currentNode.right;
    		}
    		else{
    			if(currentNode.left==null){
    				currentNode.left = new TreeNode<E>(value);
    				break;
    			}
    			currentNode = currentNode.left;
    		}
    	}
    }
    public TreeNode<E> getRoot(){
    	return root;
    }
    //前序遍歷(遞迴)
    public void preOrderTraverse(TreeNode<E> node){
    	System.out.print(node.value+" ");
    	if(node.left!=null)
    		preOrderTraverse(node.left);
    	if(node.right!=null)
    		preOrderTraverse(node.right);
    }
    //中序遍歷(遞迴)
    public void midOrderTraverse(TreeNode<E> node){
    	if(node.left!=null)
    		midOrderTraverse(node.left);
    	System.out.print(node.value+" ");
    	if(node.right!=null)
    		midOrderTraverse(node.right);
    }
    //後序遍歷(遞迴)
    public void postOrderTraverse(TreeNode<E> node){
    	if(node.left!=null)
    		postOrderTraverse(node.left);
    	if(node.right!=null)
    		postOrderTraverse(node.right);
    	System.out.print(node.value+" ");
    }
    //前序遍歷(非遞迴)
    public void preOrderTraverseNo(TreeNode<E> root){
    	LinkedList<TreeNode<E>> list = new LinkedList<TreeNode<E>>();
    	TreeNode<E> currentNode = null;
    	list.push(root);
    	while(!list.isEmpty()){
    		currentNode = list.pop();
    		System.out.print(currentNode.value+" ");
    		if(currentNode.right!=null)
    			list.push(currentNode.right);
    		if(currentNode.left!=null)
    			list.push(currentNode.left);
    	}
    }
    public void midOrderTraverseNo(TreeNode<E> root){
    	LinkedList<TreeNode<E>> list = new LinkedList<TreeNode<E>>();
    	TreeNode<E> currentNode = root;
    	while(currentNode!=null||!list.isEmpty()){
    		while(currentNode!=null){
    			list.push(currentNode);
    			currentNode = currentNode.left;
    		}
    		currentNode = list.pop();
    		System.out.print(currentNode.value+" ");
    		currentNode = currentNode.right;
    	}
    }
    public void postOrderTraverseNo(TreeNode<E> root){
    	LinkedList<TreeNode<E>> list = new LinkedList<TreeNode<E>>();
    	TreeNode<E> currentNode = root;
    	TreeNode<E> rightNode = null;
    	while(currentNode!=null||!list.isEmpty()){
    		while(currentNode!=null){
    			list.push(currentNode);
    			currentNode = currentNode.left;
    		}
    		currentNode = list.pop();
    		while (currentNode.right == null || currentNode.right == rightNode) {
    			System.out.print(currentNode.value + " ");
    			rightNode = currentNode;
    			if (list.isEmpty()) {
    				return; //root以輸出,則遍歷結束
    			}
    			currentNode = list.pop();
    		}
    		list.push(currentNode); //還有右結點沒有遍歷
    		currentNode = currentNode.right;
    	}
    }
    
    //廣度優先遍歷,使用佇列
    public void breadthFirstTraverse(TreeNode<E> root){
    	Queue<TreeNode<E>> queue = new LinkedList<TreeNode<E>>();
    	TreeNode<E> currentNode = null;
    	queue.offer(root);
    	while(!queue.isEmpty()){
    		currentNode=queue.poll();
    		System.out.print(currentNode.value+" ");
    		if(currentNode.left!=null)
    			queue.offer(currentNode.left);
    		if(currentNode.right!=null)
    			queue.offer(currentNode.right);
    	}
    } 
}