二分查找实现符号表

二分查找实现符号表

算法原理

使用Keys[]Values[]两个数组分别存储键和值

实现的核心是rank() 方法,它返回表中小于给定键的数量

  • 对于get()方法,只要给定键存在于表中,rank()方法就能精确地告诉我们在哪里能够找到它(如果找不到,那么它肯定就不在表中)

  • 对于put()方法,只要给定键存在于表中,rank()方法就能精确的告诉我们到哪里去更新它的值,当键不存在表中时也能精确的知道需要将键值对存储于何处。

性能分析

  • N N N 个键的有序数组中进行二分查找最多需要 l o g 2 N + 1 log_2N + 1 log2N+1次比较
  • 向大小为 N N N的有序数组中插入一个新的元素在最坏情况下需要方位   2 N ~2N  2N次数组,因此像一个空符号表中插入 N N N个元素在最坏情况下需要访问   N 2 ~N^2  N2次数组

java 实现

/**
 * 有序数组的二分查找
 */
public class ArrayBinarySearchST<Key extends Comparable<Key>, Value> implements IOrderedSymbolTable<Key, Value> {

    private static final int INIT_CAPACITY = 2;

    private Key[] keys;

    private Value[] values;

    private int n;

    public ArrayBinarySearchST() {
        this(INIT_CAPACITY);
    }

    public ArrayBinarySearchST(int capacity) {
        keys = (Key[])new Comparable[capacity];
        values = (Value[])new Object[capacity];
        n = 0;
    }

    /**
     * 返回最小的键
     *
     * @return 最小的键
     */
    @Override
    public Key min() {
        if (isEmpty()) {
            return null;
        }

        return keys[0];
    }

    /**
     * 返回最大的键
     *
     * @return 最大的键
     */
    @Override
    public Key max() {
        if (isEmpty()) {
            return null;
        }

        return keys[n - 1];
    }

    /**
     * 返回小于等于key的最大键
     *
     * @param key
     *            键
     * @return 小于等于key的最大键
     */
    @Override
    public Key floor(Key key) {
        validKey(key);

        int i = rank(key);

        if (i < n && key.compareTo(keys[i]) == 0) {
            return keys[i];
        }

        if (i == 0) {
            return null;
        }

        return keys[i - 1];
    }

    /**
     * 返回大于等于key的最小键
     *
     * @param key
     *            键
     * @return 大于等于key的最小键
     */
    @Override
    public Key ceiling(Key key) {
        validKey(key);

        int i = rank(key);

        if (i == n) {
            return null;
        }

        return keys[i];
    }

    /**
     * 返回小于key的键的数量(键的排名)
     *
     * @param key
     *            键
     * @return 小于key的键的数量
     */
    @Override
    public int rank(Key key) {
        validKey(key);

        int low = 0;
        int high = n - 1;

        while (low <= high) {
            int mid = low + (high - low) / 2;

            int compare = key.compareTo(keys[mid]);

            if (compare < 0) {
                high = mid - 1;
            } else if (compare > 0) {
                low = mid + 1;
            } else {
                return mid;
            }
        }

        return low;
    }

    /**
     * 获取排名为k的键
     *
     * @param k
     *            排名
     * @return 排名为k的键
     */
    @Override
    public Key select(int k) {

        if (k < 0 || k >= size()) {
            throw new IllegalArgumentException("非法的select()参数: " + k);
        }

        return keys[k];
    }

    /**
     * 删除最小的键值对
     */
    @Override
    public void deleteMin() {
        delete(min());
    }

    /**
     * 删除最大的键值对
     */
    @Override
    public void deleteMax() {
        delete(max());
    }

    /**
     * 返回[low..high]之间键的数量
     *
     * @param low
     *            小键
     * @param high
     *            大键
     * @return [low..high]之间键的数量
     */
    @Override
    public int size(Key low, Key high) {
        validKey(low);
        validKey(high);

        if (low.compareTo(high) > 0) {
            return 0;
        }

        if (contains(high)) {
            return rank(high) - rank(low) + 1;
        }

        return rank(high) - rank(low);
    }

    /**
     * 返回[low..high]之间的所有键,已排序
     *
     * @param lo
     *            小键
     * @param hi
     *            大键
     * @return [low..high]之间的所有键
     */
    @Override
    public Iterable<Key> keys(Key lo, Key hi) {
        validKey(lo);
        validKey(hi);

        LinkedQueue<Key> queue = new LinkedQueue<>();
        if (lo.compareTo(hi) > 0) {
            return queue;
        }
        for (int i = rank(lo); i < rank(hi); i++) {
            queue.enqueue(keys[i]);
        }
        if (contains(hi)) {
            queue.enqueue(keys[rank(hi)]);
        }
        return queue;
    }

    /**
     * 将键值对存入符号表(如果值为空则将键从表中删除)
     *
     * @param key
     *            键
     * @param value
     *            值
     */
    @Override
    public void put(Key key, Value value) {
        // 查找键,找到则更新值,否则创建新的元素
        int i = rank(key);

        if (value == null) {
            delete(key);

            return;
        }

        if (i < n && keys[i].compareTo(key) == 0) {
            values[i] = value;
            return;
        }

        if (n >= keys.length) {
            resize(2 * keys.length);
        }

        // 将所有更大的键向后移动一格
        for (int j = n; j > i; j--) {
            keys[j] = keys[j - 1];
            values[j] = values[j - 1];
        }

        keys[i] = key;
        values[i] = value;

        n++;

    }

    /***
     * 获取键 key 的值(如果键 key 不存在则返回 null)
     *
     * @param key
     *            键
     * @return 对应的值
     */
    @Override
    public Value get(Key key) {
        if (isEmpty()) {
            return null;
        }

        int i = rank(key);

        if (i < n && keys[i].compareTo(key) == 0) {
            return values[i];
        }

        return null;
    }

    /**
     * 从符号表中删除键 key(以及对应的值)
     *
     * @param key
     *            键
     */
    @Override
    public void delete(Key key) {
        validKey(key);

        if (isEmpty()) {
            return;
        }

        int i = rank(key);

        if (i == n || key.compareTo(keys[i]) != 0) {
            return;
        }

        for (int j = i; j < n - 1; j++) {
            keys[j] = keys[j + 1];
            values[j] = values[j + 1];
        }

        n--;

        keys[n] = null;
        values[n] = null;

        if (n > 0 && n == keys.length / 4) {
            resize(keys.length / 2);
        }
    }

    /**
     * 键key是否在符号表中有对应的值
     *
     * @param key
     *            键
     * @return boolean
     */
    @Override
    public boolean contains(Key key) {

        return get(key) != null;
    }

    /**
     * 返回符号表是否为空
     *
     * @return boolean
     */
    @Override
    public boolean isEmpty() {
        return size() == 0;
    }

    /**
     * 返回符号表中键值对的个数
     *
     * @return 符号表中键值对的个数
     */
    @Override
    public int size() {
        return n;
    }

    /**
     * 返回符号表中所有键的(可迭代)集合
     *
     * @return 键的集合
     */
    @Override
    public Iterable<Key> keys() {
        return keys(min(), max());
    }

    private void validKey(Key key) {
        if (key == null) {
            throw new IllegalArgumentException();
        }
    }

    private void resize(int capacity) {
        Key[] tempk = (Key[])new Comparable[capacity];
        Value[] tempv = (Value[])new Object[capacity];
        for (int i = 0; i < n; i++) {
            tempk[i] = keys[i];
            tempv[i] = values[i];
        }
        values = tempv;
        keys = tempk;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值