• 有序符号表(数组实现,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;
        }
    }
    
  • 相关阅读:
    常见的查找算法(七):哈希查找
    常见的查找算法(六):分块查找
    常见的查找算法(五):树表查找之一 ---- 二叉查找树
    让div充满整个body
    display:table的用法
    webpack-dev-server
    webpack--loader
    webpack nodejs npm关系
    js中==和===区别
    vue 的点击事件怎么获取当前点击的元素
  • 原文地址:https://www.cnblogs.com/lizijuna/p/11907422.html
Copyright © 2020-2023  润新知