資料結構-二叉樹的遍歷(Java實現)
二叉樹介紹
二叉樹的概念:一棵二叉樹是節點的一個有限集合,該集合或者為空,或者由一個根節點加上兩棵左子樹和右子樹組成
二叉樹具有如下特點:
1、每個結點最多有兩棵子樹,結點的度最大為2。
2、左子樹和右子樹是有順序的,次序不能顛倒。
3、即使某結點只有一個子樹,也要區分左右子樹。
二叉樹是遞迴定義的,其結點有左右子樹之分,邏輯上二叉樹有五種基本形態:
(1)空二叉樹——如圖(a);
(2)只有一個根結點的二叉樹——如圖(b);
(3)只有左子樹——如圖(c);
(4)只有右子樹——如圖(d);
(5)完全二叉樹——如圖(e)。
注意:儘管二叉樹與樹有許多相似之處,但二叉樹不是樹的特殊情形。
型別
(1)完全二叉樹——若設二叉樹的高度為h,除第 h 層外,其它各層 (1~h-1) 的結點數都達到最大個數,第h層有葉子結點,並且葉子結點都是從左到右依次排布,這就是完全二叉樹。
(2)滿二叉樹——除了葉結點外每一個結點都有左右子葉且葉子結點都處在最底層的二叉樹。
(3)平衡二叉樹——平衡二叉樹又被稱為AVL樹(區別於AVL演算法),它是一棵二叉排序樹,且具有以下性質:它是一棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,並且左右兩個子樹都是一棵平衡二叉樹。
二叉排序樹的遍歷
二叉排序樹(Binary Sort Tree),又稱二叉查詢樹(Binary Search Tree),亦稱二叉搜尋樹。
二叉排序樹或者是一棵空樹,或者是具有下列性質的二叉樹:
(1)若左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
(2)若右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;
(3)左、右子樹也分別為二叉排序樹;
(4)沒有鍵值相等的節點。
注:遍歷順序根據根節點遍歷順序而定
先序遍歷 (根 –> 左 –> 右)
首先訪問根,再先序遍歷左子樹,最後先序遍歷右子樹
升序中序遍歷 (左 –> 根 –> 右)
首先中序遍歷左子樹,再訪問根,最後中序遍歷右子樹
無序後序遍歷 (左 –> 右 –> 根)
首先後序遍歷左子樹,再後序遍歷右子樹,最後訪問根
上圖遍歷結果
先序遍歷:8 6 3 7 10 12
中序遍歷:3 6 7 8 10 12
後序遍歷:3 7 6 12 10 8
程式碼如下:
/**
* @author zjj
* 二叉排序樹類
*/
public class BinaryTree {
/**
* 先序
*/
public static final int PRE_ORDER = 0;
/**
* 中序
*/
public static final int IN_ORDER = 1;
/**
* 後序
*/
public static final int POST_ORDER = 2;
/**
* root節點
*/
private Node root;
/**
* 新增節點
* @param data
*/
public void add(int data){
if (root == null){
root = new Node(data);
}else{
root.addNode(data);
}
}
/**
* 根據指定的順序遍歷二叉樹
* PRE_ORDER :先序遍歷
* IN_ORDER :中序遍歷
* POST_ORDER :後序遍歷
* @param order
*/
public void printBinaryTree(int order){
switch (order){
case PRE_ORDER:
root.preOrderTraversal();
break;
case IN_ORDER:
root.inOrderTraversal();
break;
case POST_ORDER:
root.postOrderTraversal();
break;
default:
System.out.println("傳入的遍歷順序錯誤!");
}
}
/**
* 節點類
*/
class Node{
/**
資料
*/
private int data;
/**
* 左節點
*/
private Node left;
/**
* 右節點
*/
private Node right;
Node(int data) {
this.data = data;
}
/**
* 新增節點(左 or 右)
* @param data
*/
void addNode(int data){
// 左子樹
if (this.data > data){
if (this.left == null){
this.left = new Node(data);
}else {
// 遞迴
this.left.addNode(data);
}
}else { // 右子樹
if (this.right == null){
this.right = new Node(data);
}else {
this.right.addNode(data);
}
}
}
// 三種遍歷方式
/**
* 先序遍歷
* 根 -> 左 -> 右
*/
void preOrderTraversal(){
// 根
System.out.print(this.data + "\t");
// 遞迴遍歷左
if (this.left != null){
this.left.preOrderTraversal();
}
// 遞迴遍歷右
if (this.right != null) {
this.right.preOrderTraversal();
}
}
/**
* 中序遍歷
* 左 -> 根 -> 右
*/
void inOrderTraversal(){
// 遞迴遍歷左
if (this.left != null){
this.left.inOrderTraversal();
}
// 根
System.out.print(this.data + "\t");
// 遞迴遍歷右
if (this.right != null) {
this.right.inOrderTraversal();
}
}
/**
* 後序遍歷
* 左 -> 右 -> 根
*/
void postOrderTraversal(){
// 遞迴遍歷左
if (this.left != null){
this.left.postOrderTraversal();
}
// 遞迴遍歷右
if (this.right != null) {
this.right.postOrderTraversal();
}
// 根
System.out.print(this.data + "\t");
}
}
}
/**
* 測試類
* @author zjj
*/
public class BinaryTreeTest {
public static void main(String[] args) {
BinaryTree tree = new BinaryTree();
tree.add(8);
tree.add(6);
tree.add(3);
tree.add(7);
tree.add(10);
tree.add(12);
System.out.println("=============中序============");
tree.printBinaryTree(BinaryTree.IN_ORDER);
System.out.println("\n=============先序============");
tree.printBinaryTree(BinaryTree.PRE_ORDER);
System.out.println("\n=============後序============");
tree.printBinaryTree(BinaryTree.POST_ORDER);
}
}
程式執行結果:
=============中序============
3 6 7 8 10 12
=============先序============
8 6 3 7 10 12
=============後序============
3 7 6 12 10 8