二叉搜尋樹(Binary Search Tree)(Java實現)
阿新 • • 發佈:2021-07-07
@
目錄1、二叉搜尋樹
1.1、 基本概念
二叉樹的一個性質是一棵平均二叉樹的深度要比節點個數N小得多。分析表明其平均深度為\(\mathcal{O}(\sqrt{N})\),而對於特殊型別的二叉樹,即二叉查詢樹(binary search tree),其深度的平均值為\(\mathcal{O}(log N)\)
二叉查詢樹的性質: 對於樹中的每個節點X,它的左子樹中所有項的值小於X中的項,而它的右子樹中所有項的值大於X中的項。
由於樹的遞迴定義,通常是遞迴地編寫那些操作的例程。因為二叉查詢樹的平均深度為\(\mathcal{O}(log N)\),所以一般不必擔心棧空間被用盡。
1.2、樹的節點(BinaryNode)
二叉查詢樹要求所有的項都能夠排序,有兩種實現方式;
- 物件實現介面 Comparable, 樹中的兩項使用compareTo方法進行比較;
- 使用一個函式物件,在構造器中傳入一個比較器;
本篇文章採用了構造器過載,並定義了myCompare方法,使用了泛型,因此兩種方式都支援,在後續的程式碼實現中可以看到。
節點定義:
/** * 節點 * * @param <AnyType> */ private static class BinaryNode<AnyType> { BinaryNode(AnyType theElement) { this(theElement, null, null); } BinaryNode(AnyType theElement, BinaryNode<AnyType> left, BinaryNode<AnyType> right) { element = theElement; left = left; right = right; } AnyType element; // the data in the node BinaryNode<AnyType> left; // Left child BinaryNode<AnyType> right; // Right child }
1.3、構造器和成員變數
private BinaryNode<AnyType> root;
private Comparator<? super AnyType> cmp;
/**
* 無參構造器
*/
public BinarySearchTree() {
this(null);
}
/**
* 帶參構造器,比較器
*
* @param c 比較器
*/
public BinarySearchTree(Comparator<? super AnyType> c) {
root = null;
cmp = c;
}
關於比較器的知識可以參考下面這篇文章:
Java中Comparator的使用
關於泛型的知識可以參考下面這篇文章:
如何理解 Java 中的 <T extends Comparable<? super T>>
1.3、公共方法(public method)
主要包括插入,刪除,找到最大值、最小值,清空樹,檢視元素是否包含;
/**
* 清空樹
*/
public void makeEmpty() {
root = null;
}
public boolean isEmpty() {
return root == null;
}
public boolean contains(AnyType x){
return contains(x,root);
}
public AnyType findMin(){
if (isEmpty()) throw new BufferUnderflowException();
return findMin(root).element;
}
public AnyType findMax(){
if (isEmpty()) throw new BufferUnderflowException();
return findMax(root).element;
}
public void insert(AnyType x){
root = insert(x, root);
}
public void remove(AnyType x){
root = remove(x,root);
}
1.4、比較函式
如果有比較器,就使用比較器,否則要求物件實現了Comparable介面;
private int myCompare(AnyType lhs, AnyType rhs) {
if (cmp != null) {
return cmp.compare(lhs, rhs);
} else {
return lhs.compareTo(rhs);
}
}
1.5、contains 函式
本質就是一個樹的遍歷;
private boolean contains(AnyType x, BinaryNode<AnyType> t) {
if (t == null) {
return false;
}
int compareResult = myCompare(x, t.element);
if (compareResult < 0) {
return contains(x, t.left);
} else if (compareResult > 0) {
return contains(x, t.right);
} else {
return true;
}
}
1.6、findMin
因為二叉搜尋樹的性質,最小值一定是樹的最左節點,要注意樹為空的情況。
/**
* Internal method to find the smallest item in a subtree
* @param t the node that roots the subtree
* @return node containing the smallest item
*/
private BinaryNode<AnyType> findMin(BinaryNode<AnyType> t) {
if (t == null) {
return null;
}
if (t.left == null) {
return t;
}
return findMin(t.left);
}
1.7、findMax
最右節點;
/**
* Internal method to find the largest item in a subtree
* @param t the node that roots the subtree
* @return the node containing the largest item
*/
private BinaryNode<AnyType> findMax(BinaryNode<AnyType> t){
if (t == null){
return null;
}
if (t.right == null){
return t;
}
return findMax(t.right);
}
1.8、insert
這個主要是根據二叉搜尋樹的性質,注意當樹為空的情況,就可以加入新的節點了,還有當該值已經存在時,預設不進行操作;
/**
* Internal method to insert into a subtree
* @param x the item to insert
* @param t the node that roots the subtree
* @return the new root of the subtree
*/
private BinaryNode<AnyType> insert(AnyType x, BinaryNode<AnyType> t){
if (t == null){
return new BinaryNode<>(x,null,null);
}
int compareResult = myCompare(x,t.element);
if (compareResult < 0){
t.left = insert(x,t.left);
}
else if (compareResult > 0){
t.right = insert(x,t.right);
}
else{
//Duplicate; do nothing
}
return t;
}
1.9、remove
注意當空樹時,返回null;
最後一個三元表示式,是在之前已經排除掉節點有兩個兒子的情況下使用的。
/**
* Internal method to remove from a subtree
* @param x the item to remove
* @param t the node that roots the subtree
* @return the new root of the subtree
*/
private BinaryNode<AnyType> remove(AnyType x, BinaryNode<AnyType> t){
if (t == null){
return t; // Item not found ,do nothing
}
int compareResult = myCompare(x,t.element);
if (compareResult < 0){
t.left = remove(x,t.left);
}
else if (compareResult > 0){
t.right = remove(x,t.right);
}
else if (t.left !=null && t.right!=null){
//Two children
t.element = findMin(t.right).element;
t.right = remove(t.element,t.right);
}
else
t = (t.left !=null) ? t.left:t.right;
return t;
}
二、完整程式碼實現(Java)
/**
* @author LongRookie
* @description: 二叉搜尋樹
* @date 2021/6/26 19:41
*/
import com.sun.source.tree.BinaryTree;
import java.nio.BufferUnderflowException;
import java.util.Comparator;
/**
* 二叉搜尋樹
*/
public class BinarySearchTree<AnyType extends Comparable<? super AnyType>> {
/**
* 節點
*
* @param <AnyType>
*/
private static class BinaryNode<AnyType> {
BinaryNode(AnyType theElement) {
this(theElement, null, null);
}
BinaryNode(AnyType theElement, BinaryNode<AnyType> left, BinaryNode<AnyType> right) {
element = theElement;
left = left;
right = right;
}
AnyType element; // the data in the node
BinaryNode<AnyType> left; // Left child
BinaryNode<AnyType> right; // Right child
}
private BinaryNode<AnyType> root;
private Comparator<? super AnyType> cmp;
/**
* 無參構造器
*/
public BinarySearchTree() {
this(null);
}
/**
* 帶參構造器,比較器
*
* @param c 比較器
*/
public BinarySearchTree(Comparator<? super AnyType> c) {
root = null;
cmp = c;
}
/**
* 清空樹
*/
public void makeEmpty() {
root = null;
}
public boolean isEmpty() {
return root == null;
}
public boolean contains(AnyType x){
return contains(x,root);
}
public AnyType findMin(){
if (isEmpty()) throw new BufferUnderflowException();
return findMin(root).element;
}
public AnyType findMax(){
if (isEmpty()) throw new BufferUnderflowException();
return findMax(root).element;
}
public void insert(AnyType x){
root = insert(x, root);
}
public void remove(AnyType x){
root = remove(x,root);
}
private int myCompare(AnyType lhs, AnyType rhs) {
if (cmp != null) {
return cmp.compare(lhs, rhs);
} else {
return lhs.compareTo(rhs);
}
}
private boolean contains(AnyType x, BinaryNode<AnyType> t) {
if (t == null) {
return false;
}
int compareResult = myCompare(x, t.element);
if (compareResult < 0) {
return contains(x, t.left);
} else if (compareResult > 0) {
return contains(x, t.right);
} else {
return true;
}
}
/**
* Internal method to find the smallest item in a subtree
* @param t the node that roots the subtree
* @return node containing the smallest item
*/
private BinaryNode<AnyType> findMin(BinaryNode<AnyType> t) {
if (t == null) {
return null;
}
if (t.left == null) {
return t;
}
return findMin(t.left);
}
/**
* Internal method to find the largest item in a subtree
* @param t the node that roots the subtree
* @return the node containing the largest item
*/
private BinaryNode<AnyType> findMax(BinaryNode<AnyType> t){
if (t == null){
return null;
}
if (t.right == null){
return t;
}
return findMax(t.right);
}
/**
* Internal method to remove from a subtree
* @param x the item to remove
* @param t the node that roots the subtree
* @return the new root of the subtree
*/
private BinaryNode<AnyType> remove(AnyType x, BinaryNode<AnyType> t){
if (t == null){
return t; // Item not found ,do nothing
}
int compareResult = myCompare(x,t.element);
if (compareResult < 0){
t.left = remove(x,t.left);
}
else if (compareResult > 0){
t.right = remove(x,t.right);
}
else if (t.left !=null && t.right!=null){
//Two children
t.element = findMin(t.right).element;
t.right = remove(t.element,t.right);
}
else
t = (t.left !=null) ? t.left:t.right;
return t;
}
/**
* Internal method to insert into a subtree
* @param x the item to insert
* @param t the node that roots the subtree
* @return the new root of the subtree
*/
private BinaryNode<AnyType> insert(AnyType x, BinaryNode<AnyType> t){
if (t == null){
return new BinaryNode<>(x,null,null);
}
int compareResult = myCompare(x,t.element);
if (compareResult < 0){
t.left = insert(x,t.left);
}
else if (compareResult > 0){
t.right = insert(x,t.right);
}
else{
//Duplicate; do nothing
}
return t;
}
}