定義:
二叉查找樹(Binary Search Tree),(又:二叉搜索樹,二叉排序樹)它或者是一棵空樹,或者是具有下列性質的[二叉樹]: 若它的左子樹不空,則左子樹上所有結點的值均小于它的根結點的值; 若它的右子樹不空,則右子樹上所有結點的值均大于它的根結點的值; 它的左、右子樹也分別為[二叉排序樹]
結點的結構代碼:
public Node root;
protect int size;
public static class Node {
public Node(Integer value, Node parent, Node left, Node right) {
super();
this.value = value;
this.parent = parent;
this.left = left;
this.right = right;
}
public Integer value;
public Node parent;
public Node left;
public Node right;
public boolean isLeaf() {
return left == null && right == null;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Node other = (Node) obj;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
}
查詢:
#######原理:
如果插入的值比當前結點小,就繼續向其左子樹繼續查找,大就繼續向其右子樹繼續查找,相等就返回當前結點
#######代碼:
public Node search(int element) {
Node node = root;
while (node != null && node.value != null && node.value != element) {
if (element < node.value) {
node = node.left;
} else {
node = node.right;
}
}
return node;
}
插入:
#######原理:
如果root是空,則直接插入當前結點到root,否則
定義兩個變量,一個searchNode賦值root,一個是insertParent賦值為空,先查詢要插入的值,查詢過程即搜索二叉樹的查詢過程,在搜索到結點為空時跳出循環,而insertParent存儲每次循環查詢前serathNode的值,跳出循環說明,要插入的結點不是在insertParent的左孩子就是右孩子,然后比較大小,大右孩子,小左孩子。
#######代碼:
public Node insert(int element) {
if (root == null) {
root = createNode(element, null, null, null);
size++;
return root;
}
Node insertParentNode = null;
Node searchTempNode = root;
while (searchTempNode != null && searchTempNode.value != null) {
insertParentNode = searchTempNode;
if (element < searchTempNode.value) {
searchTempNode = searchTempNode.left;
} else {
searchTempNode = searchTempNode.right;
}
}
Node newNode = createNode(element, insertParentNode, null, null);
if (insertParentNode.value > newNode.value) {
insertParentNode.left = newNode;
} else {
insertParentNode.right = newNode;
}
size++;
return newNode;
}
刪除:
#######原理:
看代碼注釋,總體原理是刪除分情況
第一種,要刪除結點,他只有左孩子或者右孩子,那么就讓他的唯一那個孩子來代替他的環境即可
第二種,要刪除的結點他既有左孩子又有右孩子,那么就要選要刪除結點的后繼節點來替代他的環境,因為他的后繼結點就是要刪除節點的右子樹中最左邊的結點,這個結點是他整個右子樹的做小的樹,而且他還比要刪除的結點大,所以選這個結點。在替換環境的時候,要注意全方位替換,即刪除結點的左子樹環境,右子樹環境,父環境都要替換,具體看代碼
#######代碼:
public Node delete(int element) {
//先查找要刪除的結點是否存在
Node deleteNode = search(element);
if (deleteNode != null) {
return delete(deleteNode);
} else {
return null;
}
}
protected Node delete(Node deleteNode) {
if (deleteNode != null) {
Node nodeToReturn = null;
if (deleteNode != null) {
//如果要刪除結點的左孩子為空,直接用刪除結點的右孩子代替他的位置即可
if (deleteNode.left == null) {
//transplant的作用就是用后面的參數代替前面參數的父環境
nodeToReturn = transplant(deleteNode, deleteNode.right);
} else if (deleteNode.right == null) {
nodeToReturn = transplant(deleteNode, deleteNode.left);
} else {
//獲取要刪除結點的后繼節點,也就是刪除結點右孩子的左子樹最左的結點,他比要刪除的檢點大,他是要刪除結點右子樹的最小值
//所以用它來代替要刪除結點的位置
Node successorNode = getMinimum(deleteNode.right);
//又分兩中情況,如果要刪除結點右孩子的左子樹最左的結點就是他自己,就直接用這個節點代替刪除結點的環境即可
//否則如下
if (successorNode.parent != deleteNode) {
//用succ結點的右孩子先代替suss結點的父環境
transplant(successorNode, successorNode.right);
//安排要刪除結點的右邊的子環境,即讓刪除結點的后繼結點succ的右孩子是刪除結點的右孩子
successorNode.right = deleteNode.right;
//雙向處理,上面一行處理的是讓父指向右,這一步是讓右指向父
successorNode.right.parent = successorNode;
}
//讓succ代替刪除節點的父環境
transplant(deleteNode, successorNode);
//讓succ代替刪除結點的左孩子環境
successorNode.left = deleteNode.left;
successorNode.left.parent = successorNode;
nodeToReturn = successorNode;
}
size--;
}
return nodeToReturn;
}
return null;
}
private Node transplant(Node nodeToReplace, Node newNode) {
if (nodeToReplace.parent == null) {
this.root = newNode;
//要替代結點是他父節點的左孩子
} else if (nodeToReplace == nodeToReplace.parent.left) {
//新節點就變成他父節點新的左孩子
nodeToReplace.parent.left = newNode;
} else {
nodeToReplace.parent.right = newNode;
}
//雙向處理
if (newNode != null) {
newNode.parent = nodeToReplace.parent;
}
return newNode;
}
protected Node getMinimum(Node node) {
while (node.left != null) {
node = node.left;
}
return node;
}