目錄
整體結構思維導圖
-------------------------------------------------------------------------------- 回到目錄
二分搜索樹也可叫二分排序樹,二分查找樹。
關於比較的問題:
- 二叉排序樹要求所有的項都能排序,要寫出一個一般的類,我們需要實現 Comparable 接口,使得可以使用泛型來比較任意的數據類型。
- 因爲不是基礎類型所以不能直接用 equals 比較。因爲大E是滿足Comparable 接口的,所以用 compareTo 比較。
關於操作的問題:
- 增和刪都用遞歸。
- 遍歷問題其實就是在什麼時候 System.out.println(node.e) 打印節點值而已。
- 前序遍歷的非遞歸,用棧,先壓右孩子再壓左孩子,再逐個彈出來。
- 廣度優先遍歷,用隊列,先進左孩子再進右孩子,再逐個出隊。
關於 BST 的時間複雜度:
注意:爲了避免出現如上圖所示的最差的情況,就有了平衡二叉樹的出現。
完整源碼
import java.util.Queue; //也可以用自己實現的Queue類
import java.util.Stack; //也可以用自己實現的Stack類
import java.util.LinkedList; //也可以用自己實現的List類
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 void add(E e) {
root = add(root, 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;
}
//刪
public void remove(E e) {
root = remove(root, e);
}
public Node remove(Node node, E e) {
if (node == null) return null;
if (e.compareTo(node.e) < 0) {
node.left = remove(node.left, e);
return node;
}
else if (e.compareTo(node.e) > 0) {
node.right = remove(node.right, e);
return node;
}
else {
if (node.left == null) {
Node rightNode = node.right;
node.right = null;
size--;
return rightNode; //直接連接上即可
}
if (node.right == null) {
Node leftNode = node.left;
node.left = null;
size--;
return leftNode;
}
//左右孩子都不爲空的情況,找到待刪除節點的後繼節點
Node successor = minimum(node.right); //先找到最小節點
successor.right = removeMin(node.right); //然後去掉最小的節點後,後繼節點接上整棵右子樹
successor.left = node.left; //在接上整棵左子樹就完成了
node.left = node.right = null;
return successor;
//或者找到待刪除的前驅節點
/*
Node precursor = maximum(node.left);
precursor.left = removeMax(node.left);
precursor.right = node.right;
node.left = node.right = null;
return precursor;
*/
}
}
//刪除最小元素所在節點
public E removeMin() {
E ret = minimum();
root = removeMin(root);
return ret;
}
private Node removeMin(Node node) {
if (node.left == null) {
Node rightNode = node.right;
node.right = null;
size--;
return rightNode;
}
node.left = removeMin(node.left);
return node;
}
//刪除最大元素所在節點
public E removeMax() {
E ret = maximum();
root = removeMax(root);
return ret;
}
private Node removeMax(Node node) {
if (node.right == null) {
Node leftNode = node.left;
node.left = null;
size--;
return leftNode;
}
node.right = removeMax(node.right);
return node;
}
//查
public int getSize(){
return size;
}
public boolean isEmpty(){
return size == 0;
}
//尋找最小元素
public E minimum() {
if (size == 0)
throw new IllegalArgumentException("empty");
return minimum(root).e;
}
private Node minimum(Node node) {
if (node.left == null) return node;
return minimum(node.left);
}
//尋找最大元素
public E maximum() {
if (size == 0)
throw new IllegalArgumentException("empty");
return maximum(root).e;
}
private Node maximum(Node node) {
if (node.right == null) return node;
return maximum(node.right);
}
public boolean contains(E e) {
return contains(root, e);
}
private boolean contains(Node node, E e) {
if (node == null) return false;
if (e.compareTo(node.e) == 0) return true;
else if(e.compareTo(node.e) < 0)
return contains(node.left, e);
else return contains(node.right, e);
}
//遍歷
//前序遍歷
public void preOrder(){
preOrder(root);
}
private void preOrder(Node node){
if (node == null) return;
System.out.println(node.e);
preOrder(node.left);
preOrder(node.right);
}
//中序遍歷(順序遍歷)
public void inOrder() {
inOrder(root);
}
private void inOrder(Node node) {
if (node == null) return;
inOrder(node.left);
System.out.println(node.e);
inOrder(node.right);
}
//後序遍歷
public void postOrder() {
postOrder(root);
}
private void postOrder(Node node) {
if (node == null) return;
postOrder(node.left);
postOrder(node.right);
System.out.println(node.e);
}
//前序遍歷的非遞歸寫法(其他兩個的非遞歸基本不用)
public void preOrderNR() {
Stack<Node> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
Node cur = stack.pop();
System.out.println(cur.e);
if (cur.right != null)
stack.push(cur.right);
if (cur.left != null)
stack.push(cur.left);
}
}
//廣度優先遍歷(層序遍歷)
//因爲Queue是一個接口,所以實現它的時候需要選擇一個具體的底層數據結構
public void levelOrder() {
Queue<Node> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()) {
Node cur = queue.remove();
System.out.println(cur.e);
if (cur.left != null)
queue.add(cur.left);
if (cur.right != null)
queue.add(cur.right);
}
}
-------------------------------------------------------------------------------- 回到目錄