有序符号表(数组实现,JAVA,算法(四),二分法)

数组实现的有序符号表介绍:
两个平行数组,相同的下标分别是键和值,由于查入和删除需要调整数组大小,所以和无序链表一样,这两个操作仍然是线性的。但是符号表最为频繁的操作应该是查询的,查询操作可以使用二分法实现,达到了logN的复杂度。二分法的实现需要排好序的键,所以有了泛型的存在,需要实现Comparable接口。rank函数用二分法查找键,在很多函数里面我们都会使用这个函数以达到快速查找的能力。由于有序符号表的实现可以基于多种数据结构,但是它们的操作都是符号表常见操作,故在这里抽象出一个SymbolTable类,包装好以后的符号表使用的函数声明原型。

Comparable:为了使任意类型可比较,JAVA包装好的Integer,Double..这些类都实现了这个接口。当前类的函数接受一个Comparable类型的参数,只要实现了这个接口的类都可以作为参数传递,这就是接口回调,类似于上转型对象。

有序符号表基类:

package com.lizi.datastructure.symboltable;
//有序符号表基类
public abstract class SymbolTable<Key extends Comparable<Key>,Value> {

    //将键值对存入表中(若值为空则将建key从表中删除)
    public abstract void put(Key key,Value value);

    //获取键Key对应的值(若键key不存在返回空)
    public abstract Value get(Key key);

    //从表中删去键key(及其对应的值)
    public abstract Value delete(Key key);

    //表中是否存在该键
    public boolean contains(Key key){
        return get(key)!=null;
    }

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

    //表中的键值对数量
    public abstract int size();

    //最小的键
    public abstract Key min();

    //最大的键
    public abstract Key max();

    //小于等于Key的最大键
    public abstract Key floor(Key key);

    //大于等于Key的最小键
    public abstract Key ceiling(Key key);

    //小于key的键的数量
    public abstract int rank(Key key);

    //删除最小的键
    public void deleteMin(){
        delete(min());
    }

    //删除最大的键
    public void deleteMax(){
        delete(max());
    }
    //返回下标为index的键
    public abstract Key select(int index);
    //[low....high]之间键的数量,包括相等元素
    public int size(Key low,Key high){
        if (high.compareTo(low)<0)
            return 0;
        else if (contains(high))
            return rank(high)-rank(low)+1;
        else 
            return rank(high)-rank(low);
    }

    //[low....high]之间键的集合,已经排序
    public abstract Iterable<Key> keys(Key low,Key high);

    //表中所有键的集合,已经排序
    public Iterable<Key> keys(){
        return keys(min(),max());
    }

}

以下是数组实现的符号表:

package com.lizi.datastructure.symboltable;

import java.util.ArrayList;
import java.util.List;
//二分搜索,基于排序数组
public class BinarySearchST<Key extends Comparable<Key>,Value> extends SymbolTable<Key, Value> {

    private Key[] keys;
    private Value[] values;
    private int size=0;
    @SuppressWarnings("unchecked")
    public BinarySearchST(int capacity) {
        keys=(Key[]) new Comparable[capacity];
        values=(Value[]) new Object[capacity];//java不允许泛型数组,只能创建Object再强制转换类型
        this.size=0;
    }
    @Override
    public void put(Key key, Value value) {
        if(value==null) {delete(key); return;}
        //如果键存在,则修改键值
        int pos=rank(key);
        if (pos<size&&keys[pos].compareTo(key)==0) {
            values[pos]=value;
            return;
        }
        //键值不存在,判断数组是否越界并将数组扩容
        if(size==keys.length) resize(2*keys.length);
        for (int i =size; i>pos; i--) {
            keys[i]=keys[i-1];
            values[i]=values[i-1];
        }
        keys[pos]=key;
        values[pos]=value;
        size++; 
    }

    @Override
    public Value get(Key key) {
        if(isEmpty()) return null;
        int pos=rank(key);
        if (pos<size&&keys[pos].compareTo(key)==0) 
            return values[pos];
        else return null;
    }

    @Override
    public Value delete(Key key) {
        int pos=rank(key);
        //没找到则返回空
        if (pos<size&&keys[pos].compareTo(key)!=0) {
            return null;
        }
        Value value = values[pos];
        if(size<keys.length/2) resize(keys.length/2);
        for (int i = pos; i < size - 1; i++) {
            keys[i] = keys[i + 1];
            values[i] = values[i + 1];
        }
        size--;
        return value;
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public Key min() {
        return keys[0];
    }

    @Override
    public Key max() {
        return keys[size-1];
    }

    @Override
    public Key floor(Key key) {
        int pos=rank(key);
        if (pos<size&&keys[pos].compareTo(key)==0) {
            return keys[pos];
        }
        return keys[pos-1];
    }

    @Override
    public Key ceiling(Key key) {
        int pos=rank(key);
        return keys[pos];
    }
    //非递归的二分查找
    @Override
    public int rank(Key key) {
        int low=0;
        int high=size-1;
        while (low<=high) {
            int middle=low+(high-low)/2;
            int cmp=key.compareTo(keys[middle]);
            if (cmp<0) high=middle-1;
            else if(cmp>0) low=middle+1;
            else return middle;
        }
        return low;
    }
    //递归的二分查找
    public int rank(Key key,int low,int high) {
        if(low>high) return low;
        int pos=rank(key);
        int cmp=key.compareTo(keys[pos]);
        if (cmp>0) return rank(key, pos+1, high);
        else if(cmp<0) return rank(key,low,pos-1);
        else return pos;
    }
    @Override
    public Key select(int index) {
        return keys[index];
    }
    @Override
    public Iterable<Key> keys(Key low, Key high) {
        List<Key> keys=new ArrayList<Key>(size);
        for (int i = 0; i <size; i++) {
            keys.add(this.keys[i]);
        }
        return keys;
    }
    //该函数仅仅将容量扩大,但是有效元素数量并未改变,所以大小还是size
    @SuppressWarnings("unchecked")
    public void resize(int capacity) {
        Key[] newKeys=(Key[]) new Comparable[capacity];
        Value[] newValues=(Value[]) new Object[capacity];
        for (int i = 0; i < size; i++) {
            newKeys[i]=keys[i];
            newValues[i]=values[i];
        }
        keys=newKeys;
        values=newValues;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_32483145/article/details/77159050
今日推荐