二叉樹(Binary Tree):二叉樹是一棵樹,其中每個結點都不能有多於兩個的子結點;
特點:
(1) 每個結點最多有兩棵子樹,沒有子樹或者只有一棵子樹也是可以的;
(2)左子樹和右子樹是有順序的,次序不能任意顛倒;
(3)即使樹中只有一棵子樹,也要區分它是左子樹還是右子樹;
特殊的二叉樹:
(1)斜樹:顧名思義,斜樹一定是要斜的;所有的結點都只有左子樹的二叉樹叫左斜樹,所有的結點都只有右子樹的二叉樹叫右斜樹;其實,線性表就可以理解爲樹的一種特殊的表現形式;
(2)滿二叉樹:在一棵二叉樹中,如果所有分支結點都存在左子樹和右子樹,並且所有葉子都在同一層上,這樣的二叉樹稱爲滿二叉樹;如圖:
(3)完全二叉樹:對一棵具有n個結點的二叉樹按層序編號,如果編號爲i的結點與同樣深度的滿二叉樹中編號爲i的結點在二叉樹中位置完全相同,那麼這棵二叉樹稱爲完全二叉樹;或者這樣理解:在一棵二叉樹中,除最後一層外,若其餘層都是滿的,並且最後一層或者是滿的,或者是右邊缺少連續若干個結點,則稱此樹爲完全二叉樹;
所以我們可以這樣判斷完全二叉樹:那就是看着樹的示意圖,心中默默給每個結點按照滿二叉樹的結構逐層順序編號,如果編號出現空檔,就說明不是完全二叉樹,否則就是;
二叉樹的實現:同樣,二叉樹也可以通過順序存儲和鏈式存儲來實現;
二叉樹的順序存儲就是用一維數組存儲二叉樹中的結點,並且結點的存儲位置,也就是數組的下標要能體現結點之間的邏輯關係,比如父結點與子結點的邏輯關係,子結點 與子結點之間的關係;但順序存儲的實用性不強;
所以一般採用鏈式存儲;
二叉樹的遍歷:是指從根結點出發,按照某種次序,依次訪問二叉樹中所有結點,使得每個結點被訪問一次且僅被訪問一次;
二叉樹的遍歷方式有好多種,如果我們限制了從左到右的習慣方式,那麼主要就有以下幾種:
(1)前序遍歷:先訪問子結點,然後前序遍歷左子樹,再前序遍歷右子樹;如下圖,遍歷順序是:ABDGHCEIF
(2)中序遍歷:從根結點開始(但並不是先訪問根結點),中序遍歷根結點的左子樹,然後方式根結點,最後中序遍歷右樹,如圖,遍歷的順序是:GDHBAEICF
(3)後序遍歷:從左到右先葉子後結點的方式遍歷訪問左右子樹,最後是訪問根結點;如圖,遍歷的順序是:GHDBIEFCA
(4)層序遍歷:從樹的第一層,也就是根結點開始訪問,從上而下逐層遍歷,在同一層中,按從左到右的順序對結點進行逐個訪問;如圖,遍歷順序爲:ABCDEFGHI
代碼如下:
二叉樹結點
package binaryTree;
// 二叉樹節點
public class BTNode
{
private char key; // 數據
private BTNode left, right; // 左右子結點
public BTNode(char key)
{
this(key, null, null);
}
public BTNode(char key, BTNode left, BTNode right)
{
this.key = key;
this.left = left;
this.right = right;
}
public char getKey()
{
return key;
}
public void setKey(char key)
{
this.key = key;
}
public BTNode getLeft()
{
return left;
}
public void setLeft(BTNode left)
{
this.left = left;
}
public BTNode getRight()
{
return right;
}
public void setRight(BTNode right)
{
this.right = right;
}
}
二叉樹遍歷:
package binaryTree;
import java.util.Stack;
// 遍歷二叉樹
public class BinTree
{
protected BTNode root;
public BinTree(BTNode root)
{
this.root = root;
}
public BTNode getRoot()
{
return root;
}
// 初始化,構造二叉樹
public static BTNode init()
{
BTNode a = new BTNode('A');
BTNode b = new BTNode('B', null, a);
BTNode c = new BTNode('C');
BTNode d = new BTNode('D', b, c);
BTNode e = new BTNode('E');
BTNode f = new BTNode('F', e, null);
BTNode g = new BTNode('G', null, f);
BTNode h = new BTNode('H', d, g);
return h; // 根結點
}
// 訪問節點
public static void visit(BTNode p)
{
System.out.print(p.getKey() + " ");
}
// 遞歸實現前序遍歷
protected static void preorder(BTNode p)
{
if (p != null)
{
visit(p);
preorder(p.getLeft());
preorder(p.getRight());
}
}
// 遞歸實現中序遍歷
protected static void inorder(BTNode p)
{
if (p != null)
{
inorder(p.getLeft());
visit(p);
inorder(p.getRight());
}
}
// 遞歸實現後序遍歷
protected static void postorder(BTNode p)
{
if (p != null)
{
postorder(p.getLeft());
postorder(p.getRight());
visit(p);
}
}
// 非遞歸實現前序遍歷
protected static void iterativePreorder(BTNode p)
{
Stack<BTNode> stack = new Stack<BTNode>();
if (p != null)
{
stack.push(p);
while (!stack.empty())
{
p = stack.pop();
visit(p);
if (p.getRight() != null)
stack.push(p.getRight());
if (p.getLeft() != null)
stack.push(p.getLeft());
}
}
}
// 非遞歸實現後序遍歷
protected static void iterativePostorder(BTNode p)
{
BTNode q = p;
Stack<BTNode> stack = new Stack<BTNode>();
while (p != null)
{
// 左子樹入棧
for (; p.getLeft() != null; p = p.getLeft())
stack.push(p);
// 當前結點無右子結點或右子結點已經輸出
while (p != null && (p.getRight() == null || p.getRight() == q))
{
visit(p);
q = p; // 記錄上一個已輸出結點
if (stack.empty())
return;
p = stack.pop();
}
// 處理右子結點
stack.push(p);
p = p.getRight();
}
}
// 非遞歸實現中序遍歷
protected static void iterativeInorder(BTNode p)
{
Stack<BTNode> stack = new Stack<BTNode>();
while (p != null)
{
while (p != null)
{
if (p.getRight() != null)
stack.push(p.getRight()); // 當前結點右子結點入棧
stack.push(p); // 當前結點入棧
p = p.getLeft();
}
p = stack.pop();
while (!stack.empty() && p.getRight() == null)
{
visit(p);
p = stack.pop();
}
visit(p);
if (!stack.empty())
p = stack.pop();
else
p = null;
}
}
public static void main(String[] args)
{
BinTree tree = new BinTree(init());
System.out.print(" 遞歸實現前序遍歷:");
preorder(tree.getRoot());
System.out.println("\n");
System.out.print(" 遞歸實現中序遍歷:");
inorder(tree.getRoot());
System.out.println("\n");
System.out.print(" 遞歸實現後序遍歷:");
postorder(tree.getRoot());
System.out.println("\n");
System.out.print(" 非遞歸實現前序遍歷:");
iterativePreorder(tree.getRoot());
System.out.println("\n");
System.out.print(" 非遞歸實現中序遍歷:");
iterativeInorder(tree.getRoot());
System.out.println("\n");
System.out.print(" 非遞歸實現後序遍歷:");
iterativePostorder(tree.getRoot());
System.out.println("\n");
}
}