查找:链表顺序查找和有序数组二分查找

符号表

符号表是一种存储键值对的数据结构,支持两种操作:插入(put)和查找(get)。
可以分为无序符号表和有序符号表。

本节的实现基于

每个键只对应着一个值,表不允许存在重复的键
向表中存入新的键值对和已有的键冲突时,新的值会替代旧的值
键不能为空null
值不能为空null

无序链表中的顺序查找

非常的低效
向一个空表插入N个不同的键需要N^2/2次比较。

只适用于小型问题,对于大型符号表很慢

public class SequentialSearchST<Key,Value>{
    private Node first;  // 链表首结点
    private class Node{
        Key key;
        Value val;
        Node next;
        public Node(Key key, Value val, Node next){
            this.key = key;
            this.val = val;
            this.next = next;
        }
    }
    public Value get(Key key){
        for(Node x = first; x != null; x = x.next){
            if(key.equals(x.key))
                return x.val;
        }
        return null;
    }
    public void put(Key key, Value val){
        for(Node x = first; x != null; x = x.next){
            if(key.equals(x.key)){
                x.val = val;
                return ;
            }
        }
        first = new Node(key, val, first); // 放在首结点位置(链表)
    }
}

有序数组的二分查找

rank() 是核心
除了符号表的get/put等关键操作,还基于有序的数组实现其它方法

最优的查找效率和空间需求,进行有序性相关的操作。但是插入操作很慢
注:
有序数组在插入时就进行了排序。

package com.base;

public class BinarySearchST<Key extends Comparable<Key>, Value> {
    private static final int INIT_CAPACITY = 2;
    private Key[] keys;
    private Value[] vals;
    private int N = 0;

    // 默认容量初始化
    public BinarySearchST() { this(INIT_CAPACITY); }   

    // 给定容量初始化
    public BinarySearchST(int capacity) { 
        keys = (Key[]) new Comparable[capacity]; 
        vals = (Value[]) new Object[capacity]; 
    }   

    // 调整数组大小
    private void resize(int capacity) {
        assert capacity >= N;
        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] = vals[i];
        }
        vals = tempv;
        keys = tempk;
    }


    // 是否包含
    public boolean contains(Key key) {
        return get(key) != null;
    }

    // 键值对个数
    public int size() {
        return N;
    }

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

    // 根据键得到值
    public Value get(Key key) {
        if (isEmpty()) return null;
        int i = rank(key); 
        if (i < N && keys[i].compareTo(key) == 0) return vals[i];
        return null;
    } 

    // 返回比跟定键小的键
    public int rank(Key key) {
        int lo = 0, hi = N-1; 
        while (lo <= hi) { 
            int m = lo + (hi - lo) / 2; 
            int cmp = key.compareTo(keys[m]); 
            if      (cmp < 0) hi = m - 1; 
            else if (cmp > 0) lo = m + 1; 
            else return m; 
        } 
        return lo;
    } 


    // 更新值,或插入键值
    public void put(Key key, Value val)  {
        if (val == null) { delete(key); return; }

        int i = rank(key);

        // key is already in table
        if (i < N && keys[i].compareTo(key) == 0) {
            vals[i] = val;
            return;
        }

        // 扩展keys
        if (N == keys.length) resize(2*keys.length);

        for (int j = N; j > i; j--)  {
            keys[j] = keys[j-1];
            vals[j] = vals[j-1];
        }
        keys[i] = key;
        vals[i] = val;
        N++;
    } 


    // 删除键值对
    public void delete(Key key)  {
        if (isEmpty()) return;

        // compute rank
        int i = rank(key);

        // key not in table
        if (i == N || keys[i].compareTo(key) != 0) {
            return;
        }

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

        N--;
        keys[N] = null;  // to avoid loitering
        vals[N] = null;

        // resize if 1/4 full
        if (N > 0 && N == keys.length/4) resize(keys.length/2);

    } 

    // 删除最小键和关联的值
    public void deleteMin() {
        if (isEmpty()) throw new RuntimeException("Symbol table underflow error");
        delete(min());
    }

    // 删除最大键和关联的值
    public void deleteMax() {
        if (isEmpty()) throw new RuntimeException("Symbol table underflow error");
        delete(max());
    }


   /*****************************************************************************
    *  Ordered symbol table methods
    *  有序符号表的方法
    *****************************************************************************/
    // 最小
    public Key min() {
        if (isEmpty()) return null;
        return keys[0]; 
    }
    // 最大
    public Key max() {
        if (isEmpty()) return null;
        return keys[N-1];
    }
    // 排名在k的键
    public Key select(int k) {
        if (k < 0 || k >= N) return null;
        return keys[k];
    }
    // 小于等于key的最大键
    public Key floor(Key key) {
        int i = rank(key);
        if (i < N && key.compareTo(keys[i]) == 0) return keys[i];
        if (i == 0) return null;
        else return keys[i-1];
    }
    // 大于等于key的最小键
    public Key ceiling(Key key) {
        int i = rank(key);
        if (i == N) return null; 
        else return keys[i];
    }
    // lo--hi 之间的键的数量
    public int size(Key lo, Key hi) {
        if (lo.compareTo(hi) > 0) return 0;
        if (contains(hi)) return rank(hi) - rank(lo) + 1;
        else              return rank(hi) - rank(lo);
    }
    // 迭代
    public Iterable<Key> keys() {
        return keys(min(), max());
    }

    public Iterable<Key> keys(Key lo, Key hi) {
        Queue<Key> queue = new Queue<Key>(); 
        if (lo == null && hi == null) return queue;
        if (lo == null) throw new RuntimeException("lo is null in keys()");
        if (hi == null) throw new RuntimeException("hi is null in keys()");
        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; 
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值