二叉樹
二叉樹(Binary Tree)是n(n>=0)個節點的有限集合,該集合或者為空集,或者有一個根節點和兩顆互不相交的分別稱為根節點的左子樹和右子樹的二叉樹組成。
特點
- 每個節點最多有兩顆子樹。
- 左子樹和右子樹是有順序的,次序不能任意顛倒。
- 即使樹中某結點只有一個子樹,也要區分是左子樹還是右子樹。
在一棵二叉樹中,如果分支節點都存在左子樹和右子樹,並且所有葉子都在同一層上,這樣的二叉樹稱為滿二叉樹。
對一棵具有n個結點的二叉樹按層編號,如果編號為i(1<= i <=n)的結點與同樣深度的滿二叉樹編號為i的結點在二叉樹中位置完全相同,則這棵二叉樹稱為完全二叉樹。
二叉樹的性質
- 在二叉樹的第i層上至多有 2^(i-1)個結點
- 深度為k的二叉樹至多有2^k - 1個結點
如果有一層 至多有 2^0 - 1 = 1個結點
如果有二層 至多有 1+2 = 2^2 - 1 個結點 - 具有n個結點的完全二叉樹的深度為[log(2)n] +1 ([x] 不大於x的最大整數)
-如果對一棵有n個結點的完全二叉樹的結點按層編號,對任一結點i
1、如果 i= 1則結點i是二叉樹的根
2、如果2i>n 則結點無左結點
3、如果2i+1>n 則結點i無右結點
二叉樹的遍歷
- 前序遍歷
public void preOrderTraverse(){
preOrderTraverse(root);
}
//前序遍歷 根 --> 左 --->右
public void preOrderTraverse(Node root){
if (root == null)return;
System.out.println(root.val);
preOrderTraverse(root.left);
preOrderTraverse(root.right);
}
- 中序遍歷
// 左-->根--->右
public void inOrderOrderTraverse(){
inOrderOrderTraverse(root);
}
public void inOrderOrderTraverse(Node root){
if (root == null)return;
inOrderOrderTraverse(root.left);
System.out.println(root.val);
inOrderOrderTraverse(root.right);
}
-
後續遍歷
//左--->右--->中
public void postOrderOrderTraverse(){
postOrderOrderTraverse(root);
}
public void postOrderOrderTraverse(Node root){
if (root == null)return;
postOrderOrderTraverse(root.left);
postOrderOrderTraverse(root.right);
System.out.println(root.val);
}
//結點類
private class Node{
private String val;
private Node left,right;
public Node(String val) {
this.val = val;
}
}
二叉查詢樹
一棵二叉查詢樹(BST)是一個二叉樹,其中每個結點都含有一個Comparable的鍵(以及相關的值)且每個節點的鍵都大於其左子樹的任意結點的鍵而小於右子樹的任意結點的鍵。
- 結點類
適合查詢樹
private class Node{
private Key key; //按照key來排序
private Value val; // 相關聯的值
private Node left,right; //左右子結點
private int size; //結點個數
public Node(Key key, Value val, int size) {
this.key = key;
this.val = val;
this.size = size;
}
}
- 插入子節點
public void put(Key key,Value val){
if (key == null)throw new IllegalArgumentException("calls put() with a null key");
if (val == null){
delete(key); // 刪除沒有值的結點
return;
}
root = put(root,key,val);
}
//遞迴插入
private Node put(Node x,Key key,Value val){
if (x == null)return new Node(key,val,1);
int cmp = key.compareTo(x.key); // 比較一個結點的鍵
if (cmp < 0)x.left = put(x.left,key,val); // 小 則往左插入
else if(cmp > 0)x.right = put(x.right,key,val); // 大 則往右插入
else x.val = val; // 相等則更新
x.size = 1+size(x.left)+size(x.right); //重新計算相關的結點的size
return x;
}
- 獲取鍵對應的值
public Value get(Key key) {
return get(root, key);
}
private Value get(Node x,Key key){
if (key == null)throw new IllegalArgumentException("calls get() with a null key");
if (x == null) return null;
//二叉樹的分叉查詢
int cmp = key.compareTo(x.key);
// 左子樹
if (cmp < 0)return get(x.left,key);
// 右子樹
else if(cmp > 0)return get(x.right,key);
else return x.val;
}
- 最大鍵和最小鍵
如果根結點的左連線為null,那麼一棵樹的二叉查詢樹中最小的鍵解釋根節點;如果非空,那麼樹中的最小鍵就是左子樹中的最小鍵。同樣道理適用於最大鍵
public Key min(){
if (isEmpty()) throw new NoSuchElementException("calls min() with empty symbol table");
return min(root).key;
}
private Node min(Node x){
if (x.left == null)return x;
else return min(x.left);
}
//最大
public Key max(){
if (isEmpty()) throw new NoSuchElementException("calls max() with empty symbol table");
return max(root).key;
}
private Node max(Node x){
if (x.right == null) return x;
else return max(x.right);
}
- 刪除最大鍵和最小鍵
二叉查詢樹中最難實現的是delete()方法。即從符號表中刪除一個鍵值對。
刪除最小鍵所對應的鍵值對,就是不斷深入跟結點的左子樹直至出現一個空連結,然後將指向該節點的連結指向該節點的右子樹。
public void deleteMin(){
if (isEmpty()) throw new NoSuchElementException("Symbol table underflow");
root = deleteMin(root);
}
private Node deleteMin(Node x){
if (x.left == null) return x.right; // 借宿遞迴
x.left = deleteMin(x.left); // 進入遞迴
x.size = size(x.left)+size(x.right)+1;
return x;
}
public void deleteMax(){
if (isEmpty()) throw new NoSuchElementException("Symbol table underflow");
root = deleteMax(root);
}
private Node deleteMax(Node x){
if (x.right == null)return x.left;
x.right = deleteMax(x.right);
x.size = size(x.left)+size(x.right)+1;
return x;
}
- 刪除指定的鍵的鍵值對
在刪除一個x結點後 需要用它的後續結點填補位置。因x可能有一個右子節點和左子結點。其右子節點就是其右子樹中最小的結點。因此具體的補位順序如下:
1、將指向即將被刪除的結點的連結儲存為t
2、將x指向它的後繼結點min(t.right)
3、將x的右連結指向deleteMin(t.right),也就是在刪除後所有結點仍然都大於x.key的子二叉查詢樹
4、將x的左連線設為t.left
public void delete(Key key) {
if (key == null) throw new IllegalArgumentException("calls delete() with a null key");
root = delete(root, key);
}
private Node delete(Node x,Key key){
if (x == null) return null;
int cmp = key.compareTo(x.key);
if (cmp < 0)x.left = delete(x.left,key);
else if (cmp > 0)x.right = delete(x.right,key); // 查詢到要刪除的鍵
else {
if (x.right == null)return x.left;
if (x.left == null)return x.right;
Node t =x;
x = min(t.right);
x.right = deleteMin(t.right );
x.left = t.left;
}
x.size = size(x.left)+size(x.right);
return x;
}
相關文章
- 滿二叉樹、完全二叉樹、平衡二叉樹、二叉搜尋樹(二叉查詢樹)和最優二叉樹二叉樹
- 排序二叉樹和平衡二叉樹排序二叉樹
- 二叉樹(順序儲存二叉樹,線索化二叉樹)二叉樹
- 手擼二叉樹——AVL平衡二叉樹二叉樹
- 手擼二叉樹——二叉查詢樹二叉樹
- 資料結構之樹結構概述(含滿二叉樹、完全二叉樹、平衡二叉樹、二叉搜尋樹、紅黑樹、B-樹、B+樹、B*樹)資料結構二叉樹
- 【LeetCode-二叉樹】二叉樹前序遍歷LeetCode二叉樹
- 判斷二叉樹是否為滿二叉樹二叉樹
- 資料結構中的樹(二叉樹、二叉搜尋樹、AVL樹)資料結構二叉樹
- 自己動手作圖深入理解二叉樹、滿二叉樹及完全二叉樹二叉樹
- 二叉樹、B樹以及B+樹二叉樹
- 平衡二叉樹,B樹,B+樹二叉樹
- 平衡二叉樹(AVL樹)和 二叉排序樹轉化為平衡二叉樹 及C語言實現二叉樹排序C語言
- 相同二叉樹和鏡面二叉樹問題二叉樹
- 深入學習二叉樹 (一) 二叉樹基礎二叉樹
- 樹和二叉樹簡介二叉樹
- Chapter 3 樹與二叉樹APT二叉樹
- n叉樹vs二叉樹二叉樹
- 重建二叉樹二叉樹
- 二叉樹深度二叉樹
- 迭代二叉樹二叉樹
- javascript二叉樹JavaScript二叉樹
- 12、二叉樹二叉樹
- 滿二叉樹二叉樹
- 平衡二叉樹二叉樹
- Java二叉樹Java二叉樹
- 二叉樹---深度二叉樹
- 二叉樹的子結構、深度以及重建二叉樹二叉樹
- js實現完全排序二叉樹、二叉搜尋樹JS排序二叉樹
- 二叉搜尋樹和二叉樹的最近公共祖先二叉樹
- 資料結構(樹):二叉樹資料結構二叉樹
- C++樹——遍歷二叉樹C++二叉樹
- JavaScript 二叉搜尋樹以及實現翻轉二叉樹JavaScript二叉樹
- 程式碼隨想錄——二叉樹-12.平衡二叉樹二叉樹
- 5分鐘瞭解二叉樹之二叉查詢樹二叉樹
- 重建二叉樹[by Python]二叉樹Python
- 二叉樹實現二叉樹
- 平衡二叉樹(AVL)二叉樹