定義:
二叉樹(Binary Tree)是n(n>=0)個節點的有限集合,該集合或者空集(稱為空二叉樹),或者由一個根節點和兩棵互不相交的,分別稱為根節點的左子樹和右子樹的二叉樹組成。
特點:
- 每個結點最多有兩棵子樹,所以二叉樹中不存在度大於2的結點。注意不是只有兩棵子樹,而是最多有。沒有子樹或者有一棵子樹都是可以的。
- 左子樹和右子樹是有順序的,次序不能任意顛倒。就像人是雙手、雙腳,但顯然左手、左腳和右手、右腳是不一樣的,右手戴左手套、右腳穿左鞋都會極其別扭和難受。
- 即使樹中某結點只有一棵子樹,也要區分它是左子樹還是右子樹。
二叉樹的五種形態:
- 空二叉樹
- 只有一個根節點
- 根節點只有左子樹
- 根節點只有右子樹
- 根節點既有左子樹又有右子樹
特殊二叉樹:
- 斜樹:所有的節點都只有左子樹的二叉樹叫做左斜樹,所有的節點都只有右子樹的二叉樹叫做右斜樹。這兩者統稱為斜樹。
- 滿二叉樹:在一棵二叉樹中,如果所有分支節點都存在左子樹和右子樹,並且所有葉子都在同一層,這樣的二叉樹稱為滿二叉樹
- 完全二叉樹:對一棵具有n個結點的二叉樹按層序編號,如果編號為i (1<=i<=n)的結點與同樣深度的滿二叉樹中編號為i的結點在二叉樹中位置完全相同,則這棵二叉樹稱為完全二叉樹。
二叉樹性質:
- 性質1:在二叉樹的第i層上至多有2^(i-1)個節點(i>=1)
- 性質2:深度為k的二叉樹至多有2^k-1個節點(k>=1)
- 性質3:對任何一棵二叉樹T,如果其終端節點數為n0,度為2的節點數為n2,則n0=n2+1
二叉樹遍歷:
二叉樹的遍歷( traversing binary tree )是指從根結點出發,按照某種次序依次訪問二叉樹中所有結點,使得每個結點被訪問一次且僅被訪問一次。
二叉樹遍歷方法:
- 前序遍歷:規則是若二叉樹為空,則空操作返回,否則先訪問根結點,然后前序遍歷左子樹,再前序遍歷右子樹。如圖所示,遍歷的順序為:ABDGHCEIF。
- 中序遍歷:規則是若樹為空,則空操作返回,否則從根結點開始(注意並不是先訪問根結點),中序遍歷根結點的左子樹,然后是訪問根結點,最后中序遍歷右子樹。如圖所示,遍歷的順序為:GDHBAEICF。
- 后序遍歷:規則是若樹為空,則空操作返回,否則從左到右先葉子后結點的方式遍歷訪向左右子樹,最后是訪問根結點。如圖所示,遍歷的順序為:GHDBIEFCA。
- 層序遍歷:規則是若樹為空,則空操作返回,否則從樹的第一層, 也就是根結點開始訪問,從上而下逐層遍歷,在同一層中,按從左到右的順序對結點逐個訪問。如圖所示,遍歷的順序為:ABCDEFGHI。
二叉搜索樹的實現:
定義:
若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; 若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值; 它的左、右子樹也分別為二叉排序樹。如下圖所示:

代碼如下:
二叉樹的節點類:
/**
* 二叉樹的結點類
* @author wydream
*
*/
public class Node {
int data;//節點數據
Node leftChild;//左子節點的引用
Node rightChild;//右子節點的引用
boolean isDelete;//表示節點是否被刪除
public Node(int data) {
this.data=data;
}
//打印節點內容
public void display() {
System.out.println(data);
}
}
二叉樹的接口:
/**
* 二叉樹的具體方法
* @author wydream
*
*/
public interface Tree {
//查找節點
public Node find(int key);
//插入新節點
public boolean insert(int data);
//中序遍歷
public void infixOrder(Node current);
//前序遍歷
public void preOrder(Node current);
//后序遍歷
public void postOrder(Node current);
//查找最大值
public Node findMax();
//查找最小值
public Node findMin();
//刪除節點
public boolean delete(int key);
}
二叉樹的具體實現:
import org.junit.jupiter.api.Test;
public class BinaryTree implements Tree {
private Node root;//根節點
@Override
public Node find(int key) {
Node current=root;
while(current!=null) {
if(current.data>key) {//當前值比查找值大,搜索左子樹
current=current.leftChild;
}else if(current.data<key) {//當前值比查找值小,搜索右子樹
current=current.rightChild;
}else {
return current;
}
}
return null;//遍歷完整個樹沒找到,返回null
}
@Override
public boolean insert(int key) {
Node newNode=new Node(key);
if(root==null) {//當前樹為空樹,沒有任何節點
root=newNode;
return true;
}else {
Node current=root;
Node parentNode=null;
while(current!=null) {
parentNode=current;
if(current.data>key) {//當前值比插入值大,搜索左子節點
current=current.leftChild;
if(current==null) {//左孩子為空,則插入該節點到左孩子
parentNode.leftChild=newNode;
return true;
}
}else {//當前值比插入值小,搜索右子節點
current=current.rightChild;
if(current==null) {//右孩子為空,則插入該節點到右孩子
parentNode.rightChild=newNode;
return true;
}
}
}
}
return false;
}
//刪除節點
@Override
public boolean delete(int key) {
Node current=root;
Node parent=root;
boolean isLeftChild=false;
//查找刪除值,找不到直接返回false
while(current.data!=key) {
parent=current;
if(current.data>key) {
isLeftChild=true;
current=current.leftChild;
}else {
isLeftChild=false;
current=current.rightChild;
}
if(current==null) {
return false;
}
}
//如果當前節點沒有子節點
if(current.leftChild==null&¤t.rightChild==null) {
if(current==root) {
root=null;
}else if(isLeftChild) {
parent.leftChild=null;
}else {
parent.rightChild=null;
}
return true;
}else if(current.leftChild==null&¤t.rightChild!=null){//當前節點有一個子節點,右子節點
if(current==root) {
root=current.rightChild;
}else if(isLeftChild) {
parent.leftChild=current.rightChild;
}else {
parent.rightChild=current.rightChild;
}
return true;
}else if(current.rightChild==null&¤t.leftChild!=null) {//當前節點有一個子節點,左子節點
if(current==root) {
root=current.leftChild;
}else if(isLeftChild) {
parent.leftChild=current.leftChild;
}else {
parent.rightChild=current.leftChild;
}
return true;
}else {//當前節點存在兩個子節點
Node successor = getSuccessor(current);
if(current == root){
root= successor;
}else if(isLeftChild){
parent.leftChild = successor;
}else{
parent.rightChild = successor;
}
successor.leftChild = current.leftChild;
}
return false;
}
//中序遍歷:左子樹——》根節點——》右子樹
public void infixOrder(Node current) {
if(current!=null) {
infixOrder(current.leftChild);
System.out.println(current.data);
infixOrder(current.rightChild);
}
}
//前序遍歷:根節點——》左子樹——》右子樹
public void preOrder(Node current) {
if(current!=null) {
System.out.println(current.data);
preOrder(current.leftChild);
preOrder(current.rightChild);
}
}
//后序遍歷:左子樹——》右子樹——》根節點
public void postOrder(Node current) {
if(current!=null) {
postOrder(current.leftChild);
postOrder(current.rightChild);
System.out.println(current.data);
}
}
//查找最小值
public Node findMin() {
Node current=root;
Node minNode=current;
while(current!=null) {
minNode=current;
current=current.leftChild;
}
return minNode;
}
//查找最大值
public Node findMax() {
Node current=root;
Node maxNode=current;
while(current!=null) {
maxNode=current;
current=current.rightChild;
}
return maxNode;
}
public Node getSuccessor(Node delNode) {
Node successorParent=delNode;
Node successor=delNode;
Node current=delNode.rightChild;
while(current!=null) {
successorParent=successor;
successor=current;
current=current.leftChild;
}
//后繼節點不是刪除節點的右子節點,將后繼節點替換刪除節點
if(successor!=delNode.rightChild) {
successorParent.leftChild=successor.rightChild;
successor.rightChild=delNode.rightChild;
}
return successor;
}
//測試
@Test
public void test() {
BinaryTree bt = new BinaryTree();
bt.insert(50);
bt.insert(20);
bt.insert(80);
bt.insert(10);
bt.insert(30);
bt.insert(60);
bt.insert(90);
bt.insert(25);
bt.insert(85);
bt.insert(100);
bt.delete(10);//刪除沒有子節點的節點
bt.delete(30);//刪除有一個子節點的節點
bt.delete(80);//刪除有兩個子節點的節點
System.out.println(bt.findMax().data);
System.out.println(bt.findMin().data);
System.out.println(bt.find(100));
System.out.println(bt.find(200));
System.out.println("=====中序遍歷=====");
infixOrder(bt.root);
System.out.println("=====前序遍歷=====");
preOrder(bt.root);
System.out.println("=====后序遍歷=====");
postOrder(bt.root);
}
}
測試結果:
100 20 com.alibaba.test11.tree.Node@ed7f8b4 null =====中序遍歷===== 20 25 50 60 85 90 100 =====前序遍歷===== 50 20 25 85 60 90 100 =====后序遍歷===== 25 20 60 100 90 85 50
本博客代碼參考:https://www.cnblogs.com/ysocean/p/8032642.html#_label9




