玩轉資料結構(08)--二分搜尋樹
阿新 • • 發佈:2018-12-09
二分搜尋樹(Binary Search Tree)
一、樹結構
使用樹結構的原因:
1.樹結構是一種天然的組織結構
2.資料使用樹結構儲存後,查詢高效
二叉樹:是動態資料結構【不需要在建立資料結構的時候就決定好要儲存多少資料,要新增元素就 new 一個新的空間加入到其中即可,刪除二、基礎概念同理】
節點 Node 中,除了要存放元素 e 之外,還要儲存兩個指向其他節點的引用 left【左孩子】 和 right 【右孩子】
二叉樹要點:
1.二叉樹具有唯一的根節點;
2.二叉樹中每個節點最多有兩個孩子,每個節點最多有一個父親節點;一個孩子也沒有的叫做葉子節點
3.二叉樹具有天然的遞迴結構【每個節點的左子樹也是二叉樹、每個節點的右子樹也是二叉樹】
4.二叉樹不一定都是“滿”的【滿二叉樹:除葉子節點外,每個節點都有兩個孩子】
5.一個節點、甚至 NULL 也是二叉樹
二分搜尋樹:
1.二分搜尋樹是二叉樹
2.二分搜尋樹的每個節點的值:大於其左子樹的所有節點的值且小於其右子樹的所有節點的值
3.二分搜尋樹的每個子樹也是二分搜尋樹
4.儲存的元素必須具有可比較性【儲存自定義資料型別,必須自定義好資料的比較方式】
示例程式碼:BST.java【實現基本二分搜尋樹結構】
public class BST<E extends Comparable<E>> { //E 要滿足Comparable介面,要有可比較性 private class Node { //宣告對應的節點型別 public E e; public Node left, right; public Node(E e) { this.e = e; //e為使用者傳來的e left = null; //左孩子初始化 right = null; //右孩子初始化 } } private Node root; //根節點root private int size; //size 記錄當前二叉樹儲存元素的數量 public BST(){ //二分搜尋樹的建構函式 root = null; size = 0; } public int size(){ return size; } public boolean isEmpty(){ //二分搜尋樹為空 return size == 0; } }
三、向二分搜尋樹中新增元素
圖解步驟
特殊情況(有重複的話,該元素就相當於已經存在於樹中,不做任何改變)
如果想要包含重複元素,只需定義:左子樹 <= 節點;右子樹 >= 節點【只需將 = 關係放到定義中即可】
程式碼實現:BST.java
public class BST<E extends Comparable<E>> { private class Node { public E e; public Node left, right; public Node(E e) { this.e = e; left = null; right = null; } } private Node root; private int size; public BST(){ root = null; size = 0; } public int size(){ return size; } public boolean isEmpty(){ return size == 0; } // 向二分搜尋樹中新增新的元素e public void add(E e){ if(root == null){ root = new Node(e); //根節點直接指向新建的元素即可 size ++; } else add(root, e); //從根節點新增新元素e } // 向以node為根的二分搜尋樹中插入元素e,遞迴演算法 private void add(Node node, E e){ //傳入引數 Node 與 e if(e.equals(node.e)) //【遞迴的終止條件】傳入的e已經存在於樹中 return; else if(e.compareTo(node.e) < 0 && node.left == null){ //插入的e比Node節點中的e小,插入左子樹中 node.left = new Node(e); //左子樹為空,直接讓node的左孩子為新插入的e size ++; return; } else if(e.compareTo(node.e) > 0 && node.right == null){//插入的e比Node節點中的e大,插入右子樹中 node.right = new Node(e);//右子樹為空,直接讓node的右孩子為新插入的e size ++; return; } if(e.compareTo(node.e) < 0) //遞迴呼叫,插入的e比Node節點中的e小,e插入左子樹 add(node.left, e); else //e.compareTo(node.e) > 0 add(node.right, e); //node 的右孩子成為元素e } }
精簡程式碼:BST.java( NULL 也是一個子樹)
public class BST<E extends Comparable<E>> {
private class Node {
public E e;
public Node left, right;
public Node(E e) {
this.e = e;
left = null;
right = null;
}
}
private Node root;
private int size;
public BST(){
root = null;
size = 0;
}
public int size(){
return size;
}
public boolean isEmpty(){
return size == 0;
}
// 向二分搜尋樹中新增新的元素e
public void add(E e){
root = add(root, e);
}
// 向以node為根的二分搜尋樹中插入元素e,遞迴演算法
// 返回插入新節點後二分搜尋樹的根
private Node add(Node node, E e){
if(node == null){ //只要node 為null,則必須新插入節點
size ++;
return new Node(e); //將節點與二叉樹掛接起來
}
if(e.compareTo(node.e) < 0)
node.left = add(node.left, e); //插入元素e
else if(e.compareTo(node.e) > 0)
node.right = add(node.right, e);
return node;
}
}
四、 二分搜尋樹的查詢操作
示例程式碼:BST.java
public class BST<E extends Comparable<E>> {
private class Node {
public E e;
public Node left, right;
public Node(E e) {
this.e = e;
left = null;
right = null;
}
}
private Node root;
private int size;
public BST(){
root = null;
size = 0;
}
public int size(){
return size;
}
public boolean isEmpty(){
return size == 0;
}
// 向二分搜尋樹中新增新的元素e
public void add(E e){
root = add(root, e);
}
// 向以node為根的二分搜尋樹中插入元素e,遞迴演算法
// 返回插入新節點後二分搜尋樹的根
private Node add(Node node, E e){
if(node == null){
size ++;
return new Node(e);
}
if(e.compareTo(node.e) < 0)
node.left = add(node.left, e);
else if(e.compareTo(node.e) > 0)
node.right = add(node.right, e);
return node;
}
// 看二分搜尋樹中是否包含元素e(新增程式碼)
public boolean contains(E e){
return contains(root, e);
}
// 看以node為根的二分搜尋樹中是否包含元素e, 遞迴演算法(新增程式碼)
private boolean contains(Node node, E e){
if(node == null) // 節點為空,必然不存在
return false;
if(e.compareTo(node.e) == 0) //插入元素e 與節點中的e相同
return true;
else if(e.compareTo(node.e) < 0)
return contains(node.left, e); //去node左子樹中查詢
else // e.compareTo(node.e) > 0
return contains(node.right, e);//去node右子樹中查詢
}
}