二叉搜索树的定义
二叉查找树(Binary Search Tree),或者是一颗空树,或者是具有下列性质的二叉树:
1、若它的左子树不空,则其左子树上的所有结点的值均小于它根结点的值;
2、若它的右子树不空,则其右子树上的所有结点的值均大于它根结点的值;
3、它的左、右子树也分别为二叉查找树。
代码实现
树:
public interface Tree<Key extends Comparable & Serializable> {
/**
* 中序遍历
*/
static void inorderTreeWalk(Tree tree) {
if (tree != null) {
inorderTreeWalk(tree.getLeft());
System.out.println(String.valueOf(tree.getKey()));
inorderTreeWalk(tree.getRight());
}
}
/**
* 先序遍历
*/
static void preorderTreeWalk(Tree tree) {
if (tree != null) {
System.out.println(String.valueOf(tree.getKey()));
preorderTreeWalk(tree.getLeft());
preorderTreeWalk(tree.getRight());
}
}
/**
* 后序遍历
*/
static void postorderTreeWalk(Tree tree) {
if (tree != null) {
postorderTreeWalk(tree.getLeft());
postorderTreeWalk(tree.getRight());
System.out.println(String.valueOf(tree.getKey()));
}
}
Key getKey();
void setKey(Key key);
<T extends Tree> T getLeft();
<T extends Tree> T getRight();
}
二叉搜索树:
- 插入
- 前驱后继
- 搜索
- 最大最小
- 删除
当结点的左右子树都不空的时候,一般的删除策略是用其右子树的最小数据(容易找到)代替要删除的结点数据并递归删除该结点(此时为null),因为右子树的最小结点不可能有左孩子,所以第二次删除较为容易。 z的左子树和右子树均不空。找到z的后继y,因为y一定没有左子树,所以可以删除y,并让y的父亲节点成为y的右子树的父亲节点,并用y的值代替z的值.如图:
public class BinarySearchTree<Key extends Comparable & Serializable,Value> implements Tree<Key>{
private Node<Key, Value> node;
private BinarySearchTree<Key, Value> left;
private BinarySearchTree<Key, Value> right;
class Node<T extends Key, E extends Value> {
private T key;
private E value;
public Node(T key, E value) {
this.key = key;
this.value = value;
}
public T getKey() {
return key;
}
public void setKey(T key) {
this.key = key;
}
public E getValue() {
return value;
}
public void setValue(E value) {
this.value = value;
}
}
public void remove(Node<Key, Value> node) {
remove(this, node);
}
@SuppressWarnings("unchecked")
public BinarySearchTree<Key, Value> remove(BinarySearchTree<Key, Value> binarySearchTree, Node<Key, Value> node) {
if (binarySearchTree == null || node == null) {
return null;
}
BinarySearchTree current = binarySearchTree;
BinarySearchTree parent = null;
while (current != null) {
if (node.getKey().compareTo(current.getKey()) < 0) {
parent = current;
current = binarySearchTree.getLeft();
} else if (node.getKey().compareTo(current.getKey()) > 0){
parent = current;
current = binarySearchTree.getRight();
} else if (current.getLeft() != null && current.getRight() != null){
//当结点的左右子树都不空的时候,一般的删除策略是用其右子树的最小数据
//容易找到)代替要删除的结点数据并递归删除该结点(此时为null),因为
//右子树的最小结点不可能有左孩子,所以第二次删除较为容易。
current.setNode(current.getRight().getMin());
current.setRight(remove(current.getRight(), current.getNode()));
} else {
current = current.getLeft() != null ? current.getLeft() : current.getRight();
}
}
return binarySearchTree;
}
/**
* 插入
*/
public void insert(Node<Key, Value> node) throws IllegalArgumentException {
if (node == null) {
throw new IllegalArgumentException("Cannot insert null entity.");
}
insert(this, node);
}
public void insert(Key key, Value value) {
insert(this, new Node<>(key, value));
}
public void insert(BinarySearchTree<Key, Value> binarySearchTree, Node<Key, Value> node) {
if (binarySearchTree == null) {
throw new IllegalArgumentException("BinarySearchTree must not be null.");
}
BinarySearchTree<Key,Value> current = binarySearchTree;
BinarySearchTree<Key, Value> parent = binarySearchTree;
boolean isLeftChild = false;
while (current != null) {
parent = current;
if (node.getKey().compareTo(current.getKey()) < 0) {
current = current.getLeft();
isLeftChild = true;
} else {
current = current.getRight();
}
}
BinarySearchTree<Key, Value> insertTree = new BinarySearchTree<>(node);
if (isLeftChild) {
parent.setLeft(insertTree);
} else {
parent.setRight(insertTree);
}
}
/**
* 递归实现,资源消耗往往比较高
*/
public BinarySearchTree<Key, Value> search(BinarySearchTree<Key, Value> binarySearchTree, Key key) {
if (binarySearchTree == null || key == binarySearchTree.getKey()) {
return binarySearchTree;
}
if (key.compareTo(binarySearchTree.getKey()) < 0) {
return search(binarySearchTree.getLeft(), key);
} else {
return search(binarySearchTree.getRight(), key);
}
}
public BinarySearchTree<Key, Value> search(Key key) {
return search(this, key);
}
/**
* 迭代的方式往往更加省力
*/
public BinarySearchTree<Key, Value> iterativeTreeSearch(BinarySearchTree<Key, Value> binarySearchTree, Key key) {
while (binarySearchTree != null && key.compareTo(binarySearchTree.getKey()) != 0) {
if (key.compareTo(binarySearchTree.getKey()) < 0) {
binarySearchTree = binarySearchTree.getLeft();
} else {
binarySearchTree = binarySearchTree.getRight();
}
}
return binarySearchTree;
}
public BinarySearchTree<Key, Value> iterativeTreeSearch(Key key) {
return iterativeTreeSearch(this, key);
}
public Node<Key, Value> getMin() {
BinarySearchTree<Key, Value> binarySearchTree = this;
while (binarySearchTree.getLeft() != null) {
binarySearchTree = binarySearchTree.getLeft();
}
return binarySearchTree.getNode();
}
public Node<Key, Value> getMax() {
BinarySearchTree<Key, Value> binarySearchTree = this;
while (binarySearchTree.getRight() != null) {
binarySearchTree = binarySearchTree.getRight();
}
return binarySearchTree.getNode();
}
/**
* 后继:如果所有的关键字互不相同,则一个节点x的后继是大于x.key的最小关键字的节点
*/
public Node<Key, Value> successor(Key key) {
// 在二叉搜索树中查找 key 对应的节点
BinarySearchTree<Key, Value> binarySearchTree = search(key);
// 如果 key 对应的节点不存在,则 key 没有后继,返回 null
if (binarySearchTree == null)
return null;
// 如果key所在的节点右子树不为空,则其右子树的最小值为key的后继
if (binarySearchTree.getRight() != null) {
return binarySearchTree.getRight().getMin();
}
// 如果右边的树不存在,那么就找root节点到自己这个节点的路径上有没有后继
return successorFromAncestor(this, key);
}
private Node<Key, Value> successorFromAncestor(BinarySearchTree<Key, Value> binarySearchTree, Key key){
//该key就是根节点。
if (key.compareTo(binarySearchTree.getKey()) == 0){
return null;
}
if (key.compareTo(binarySearchTree.getKey()) > 0 ){
//key 在右边
return successorFromAncestor(binarySearchTree.getRight(), key);
}else {
// key 在左边
Node minNode = successorFromAncestor(binarySearchTree.getLeft(), key);
if (minNode != null)
// minNode和当前节点node取最小值返回
return minNode.getKey().compareTo(binarySearchTree.getKey()) > 0 ? binarySearchTree.getNode() : minNode;
else
// 如果minNode为空, 则当前节点即为结果
return binarySearchTree.getNode();
}
}
/**
* 随机构建二叉树
*/
public BinarySearchTree(List<Node<Key, Value>> nodeList) {
if (nodeList == null || nodeList.isEmpty()) {
throw new IllegalArgumentException("Illegal node list.");
}
BinarySearchTree<Key,Value> root = new BinarySearchTree<Key, Value>(nodeList.get(0));
for (int i = 1; i < nodeList.size(); i++) {
root.insert(nodeList.get(i));
}
}
public BinarySearchTree(Node<Key, Value> node) {
this.node = node;
}
public BinarySearchTree(Node<Key, Value> node, BinarySearchTree<Key, Value> left, BinarySearchTree<Key, Value> right) {
this.node = node;
this.left = left;
this.right = right;
}
public Node<Key, Value> getNode() {
return node;
}
public void setNode(Node<Key, Value> node) {
this.node = node;
}
@Override
public Key getKey() {
return getNode() != null ? getNode().getKey() : null;
}
@Override
public void setKey(Key key) {
if (getNode() != null) {
this.getNode().setKey(key);
}
}
public <T extends BinarySearchTree<Key, Value>> void setRight(T right) {
this.right = right;
}
public <T extends BinarySearchTree<Key, Value>> void setLeft(T left) {
this.left = left;
}
@SuppressWarnings("unchecked")
@Override
public BinarySearchTree<Key, Value> getLeft() {
return left;
}
@SuppressWarnings("unchecked")
@Override
public BinarySearchTree<Key, Value> getRight() {
return right;
}
}
时间复杂度
n个节点,h为二叉树的高度
操作 | 时间复杂度 |
中序/后序/前序遍历 | |
查找 | |
最大,最小关键字 | |
前驱后继 | |
插入 | |
删除 | |
随机构建 |
其实在实际情况中,二叉搜索树树往往要求做成二叉平衡搜索树。