节点数据结构
public class Node {
private Node left;
private Node right;
private Node parent;
private Integer value;
/**
* 相同value的节点将挂在该list上
*/
private List<Integer> list = new ArrayList<Integer>();
@Override
public String toString() {
return "Node{" +
(this.getLeft() == null ? "" : "left=" + this.getLeft().getValue()) +
(this.getRight() == null ? "" : ",right=" + this.getRight().getValue()) +
(this.getParent() == null ? "" : ",parent=" + this.getParent().getValue()) +
", value=" + this.getValue() +
(this.getList().size() == 0 ? "" : ",list=" + this.getList()) +
'}';
}
}
BinarySearchTree api
/**
* BST
* RI(Represent Invariant):
* 假设X为某一节点,则有left(X).value < X.value and right(X).value > X.value
* @author haofan.whf
* @version $Id: BinarySearchTree.java, v 0.1 2018年12月09日 下午11:13 haofan.whf Exp $
*/
public class BinarySearchTree {
/**
* 查询树中与给定value相同的Node
* T(N) = O(h)
* h为树的高度(为啥不是lgN,因为BST不一定平衡,当极端情况下(元素完全有序)会退化为链表)
* @param value
* @return
*/
public Node query(Node root, int value){
if(root.getValue() < value){
if(root.getRight() != null){
return query(root.getRight(), value);
}else{
return null;
}
}else if(root.getValue() > value){
if(root.getLeft() != null){
return query(root.getLeft(), value);
}else{
return null;
}
}else{
return root;
}
}
/**
* 向树中添加一个节点
* 如果节点已经存在,将节点加入到相同节点的list中
* T(N) = O(h)要查找空位,相当于query
* @param value
* @return
*/
public void insert(Node root, int value){
if(root.getValue() == null){
root.setValue(value);
doAfterInsert(root);
return;
}
if(root.getValue() < value){
//应该放在当前节点的右边
if(root.getRight() == null){
//右子树为空,则直接挂在当前节点的右边即可
Node n = createNode();
n.setParent(root);
n.setValue(value);
root.setRight(n);
doAfterInsert(n);
}else{
insert(root.getRight(), value);
}
}else if(root.getValue() > value){
if(root.getLeft() == null){
Node n = createNode();
n.setParent(root);
n.setValue(value);
root.setLeft(n);
doAfterInsert(n);
}else{
insert(root.getLeft(), value);
}
}else{
root.getList().add(value);
}
}
public Node createNode(){
return new Node();
}
/**
* @param node 被插入的Node
*/
public void doAfterInsert(Node node){
}
/**
* 找出继任者(如果value在root中存在)
* T(N) = O(h)
* @return
*/
public Node findSuccessor(Node root, int value){
Node node = query(root, value);
if(node == null){
throw new RuntimeException("can not found node=" + node);
}
return findSuccessor(node);
}
/**
* 找出继任者(找出整个树中仅仅比node大的节点,即node rightSubTree的最小节点,如果rightSubTree不存在则比node.value大的第一个parent)
* T(N) = O(h)
* @return
*/
public Node findSuccessor(Node node){
if(node.getRight() != null){
return query(node, findMin(node.getRight()));
}else{
int value = node.getValue();
boolean foundSuccessor = false;
while(node.getParent() != null){
if(node.getParent().getValue() > value){
foundSuccessor = true;
break;
}
node = node.getParent();
}
return foundSuccessor ? node : null;
}
}
/**
* 删除节点
* 如果删除的节点list有值也直接把节点删除
* 如果要删除的节点不存在则直接跳过
* T(N) = O(h)
* @param root
* @param value
* @return
*/
public void delete(Node root, int value){
Node node = query(root, value);
if(node == null){
return;
}
int leftOrRight = leftOrRight(node);
if(node.getRight() == null && node.getLeft() == null){
//叶子结点,直接删除即可
doBeforeDelete(node);
if(leftOrRight == -1){
node.getParent().setLeft(null);
}else if(leftOrRight == 1){
node.getParent().setRight(null);
}else{
//也没有父节点,说明这棵树只有一个元素
root = null;
}
}else if(node.getRight() == null && node.getLeft() != null){
//只有左子树
doBeforeDelete(node);
node.getLeft().setParent(node.getParent());
if(leftOrRight == -1){
node.getParent().setLeft(node.getLeft());
}else if(leftOrRight == 1){
node.getParent().setRight(node.getLeft());
}else{
//也没有父节点
node.getLeft().setParent(null);
root = node.getLeft();
}
}else if(node.getRight() != null && node.getLeft() == null){
//只有右子树
doBeforeDelete(node);
node.getRight().setParent(node.getParent());
if(leftOrRight == -1){
node.getParent().setLeft(node.getRight());
}else if(leftOrRight == 1){
node.getParent().setRight(node.getRight());
}else{
//也没有父节点
node.getRight().setParent(null);
root = node.getRight();
}
}else{
Node successor = findSuccessor(node);
swap(successor, node);
//此时node被交换到了successor的位置
//该位置有两种可能,要么是叶子结点,要么只有右子树
delete(successor, successor.getValue());
}
}
/**
* @param node 即将被删除的Node
*/
public void doBeforeDelete(Node node){
}
/**
* 交换两个node的位置(仅仅是交换值,树实际结构没有变化)
* @param node1
* @param node2
*/
public void swap(Node node1, Node node2){
int value1 = node1.getValue();
List<Integer> list1 = node1.getList();
int value2 = node2.getValue();
List<Integer> list2 = node2.getList();
node1.setValue(value2);
node2.setValue(value1);
node1.setList(list2);
node2.setList(list1);
}
/**
* 查询给定node是其parent的左/右节点
* @param node
* @return
*/
public int leftOrRight(Node node){
if(node.getParent() == null){
//无父节点
return 0;
}else{
if(node.getParent().getLeft() != null
&& node.getParent().getLeft().getValue() == node.getValue()){
//左节点
return -1;
}else if(node.getParent().getRight() != null
&& node.getParent().getRight().getValue() == node.getValue()){
//右节点
return 1;
}else {
throw new RuntimeException("impossible!");
}
}
}
/**
* 查询最大值,顺着右子树一直向下
* T(N) = O(h)
* @param root
* @return
*/
public int findMax(Node root){
if(root.getRight() != null){
return findMax(root.getRight());
}else{
return root.getValue();
}
}
/**
* 查询最小值,顺着左子树一直向下
* T(N) = O(h)
* @param root
* @return
*/
public int findMin(Node root){
if(root.getLeft() != null){
return findMin(root.getLeft());
}else{
return root.getValue();
}
}
/**
* 对BST结构进行修改后调用此方法查看结构的完整性
* T(N) = O(N)
* 需要遍历每个节点与他左右自节点的大小关系是否满足
* @param root
*/
public void checkRI(Node root){
if(root == null){
return;
}
if(root.getRight() != null){
if(root.getValue() > root.getRight().getValue()){
System.err.println(root);
throw new RuntimeException("it's not a bst");
}
}
if(root.getLeft() != null){
if(root.getValue() < root.getLeft().getValue()){
System.err.println(root);
throw new RuntimeException("it's not a bst");
}
}
checkRI(root.getRight());
checkRI(root.getLeft());
}
public class BSTTest {
@Test
public void bstNormal(){
BinarySearchTree bst = new BinarySearchTree();
int[] array = new int[]{3,5,6,4,2};
Node root = new Node();
for (int i = 0; i < array.length; i++) {
bst.insert(root, array[i]);
}
bst.checkRI(root);
Assert.assertTrue(bst.query(root, 6).getValue() == 6);
Assert.assertTrue(bst.findMax(root) == 6);
Assert.assertTrue(bst.findMin(root) == 2);
Assert.assertTrue(bst.findSuccessor(root, 5).getValue() == 6);
Assert.assertTrue(bst.findSuccessor(root, 6) == null);
int[] insertArray = randomArray(100);
root = new Node();
for (int i = 0; i < insertArray.length; i++) {
bst.insert(root, insertArray[i]);
bst.checkRI(root);
}
int[] deleteArray = randomArray(50);
for (int i = 0; i < deleteArray.length; i++) {
bst.delete(root, deleteArray[i]);
bst.checkRI(root);
}
}
private static int[] randomArray(int size){
Random random = new Random();
int[] array = new int[size];
for (int i = 0; i < size; i++) {
array[i] = random.nextInt(size);
}
return array;
}
}
BST的优点在于无论什么操作时间复杂度都是O(h)
类BST结构的优势在于可以在节点中存储一些信息来优化某些操作,比如
MaxMinBinarySearchTree
网友评论