定義:
二叉樹(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