二叉查找树总结

来源:互联网 发布:幕墙下料软件 编辑:程序博客网 时间:2024/05/30 07:13

1. 二叉查找树的数据结构

解析:

public class BST<Key extends Comparable<Key>, Value> {    private Node root; //二叉查找树的根节点    private class Node {        private Key key; //键        private Value val; //值        private Node left, right; //指向子树的链接        private int size; //以该节点为根的子树中的节点总数        public Node(Key key, Value val, int size) {            this.key = key;            this.val = val;            this.size = size;        }    }    // 初始化一个空的符号表    public BST() {    }    ......}

树由Node对象组成,每个对象都包含有一对键值、两条链接和一个结点计数器N。root变量指向二叉查找树的根节点

Node对象(这棵树包含了符号表中的所有键值对)。其中,size(x)=size(x.left)+size(x.right)=1。


2. 结点插入

解析:

public void put(Key key, Value val) {    if (key == null) throw new IllegalArgumentException("calledput() with a null key");    if (val == null) {        delete(key);        return;    }    this.root = put(this.root, key, val);    assert check();}private Node put(Node x, Key key, Value val) {    if (x == null) return new Node(key, val, 1);    int cmp = key.compareTo(x.key);    if (cmp < 0) x.left = put(x.left, key, val);    else if (cmp > 0) x.right = put(x.right, key, val);    else x.val = val;    x.size = 1 + size(x.left) + size(x.right);    return x;}

(1)当根节点为null时直接返回以key和val新建的节点;

(2)如果当被插入的key小于根节点的key时,递归在左子树中执行插入操作;

(3)如果被插入的key大于根节点的key时,递归在右子树中执行插入操作;

(4)如果被插入的key等于根节点的key时更新此根节点的val。


3. 结点查找

解析:

public Value get(Key key) {    return get(root, key);}private Value get(Node x, Key key) {    if (key == null) throw new IllegalArgumentException("called get() with a null key");    if (x == null) return null;    int cmp = key.compareTo(x.key);    if (cmp < 0) return get(x.left, key);    else if (cmp > 0) return get(x.right, key);    else return x.val;}

(1)如果键值位于符号表中,那么返回相应的值;

(2)如果键值不在符号表中,那么返回null;

(3)如果为空树,那么直接返回null;

(4)如果被查找的key和根节点相同,那么命中返回根节点对应的val;

(5)如果被查找的key大于根节点的key,那么递归在其右子树上查找;

(6)如果被查找的key小于根节点的key,那么递归在其左子树上查找。


4. 结点删除

解析:

public void delete(Key key) {    if (key == null) throw new IllegalArgumentException("called delete() with a null key");    root = delete(root, key);    assert check();}private Node delete(Node x, Key key) {    if (x == null) return null;    int cmp = key.compareTo(x.key);    if (cmp < 0) x.left = delete(x.left, key);    else if (cmp > 0) x.right = delete(x.right, key);    else {        if (x.right == null) return x.left;        if (x.left == null) return x.right;        Node t = x;        x = min(t.right);        x.right = deleteMin(t.right);        x.left = t.left;    }    x.size = size(x.left) + size(x.right) + 1;    return x;}

deleteMin函数,如下所示:

public void deleteMin() {    if (isEmpty()) throw new NoSuchElementException("Symbol table underflow");    root = deleteMin(root);    assert check();}private Node deleteMin(Node x) {    if (x.left == null) return x.right;    x.left = deleteMin(x.left);    x.size = size(x.left) + size(x.right) + 1;    return x;}
当删除一个有两个子结点的结点时,在删除结点x后用它的后继节点填补它的位置。如下所示:

(1)将指向即将被删除的结点的链接保存为t;

(2)将x指向它的后继节点min(t.right);

(3)将x的右链接(原本指向一颗所有结点都大于x.key的二叉查找树)指向deleteMin(t.right),也就是在删除后所有

结点仍然都大于x.key的子二叉查找树;

(4)将x的左链接(本为空)设为t.left(其下所有的键都小于被删除的结点和它的后继结点)。


5. 时间复杂度分析

解析:

(1)在由N个随机键构造的二叉查找树中,查找命中平均所需的比较次数为2ln(N)约等于1.39lg(N)。

(2)在由N个随机数构造的二叉查找树中,插入操作和查找未命中平均所需的比较次数为2ln(N)约等于1.39lg(N)。

(3)在一棵二叉查找树中,所有操作在最坏情况下所需时间和树的高度成正比。 


参考文献:

[1] 算法(第4版):二叉查找树