有序数组实现符号表

本文介绍了一种使用有序数组实现符号表的方法,通过二分查找提高查询效率,适用于读多写少的应用场景,如session管理。文章提供了完整的Java实现代码,并讨论了其优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0 概述

本文主要讲述使用有序数组实现符号表;由于数组是有序的,故查询的时候可以使用二分查找法,这样查询时候可以大大提高查询效率。相关符号表说明以及接口定义可以见无序链表实现符号表

1.代码实现

在含有N个键的有序数据中,查询时最多需要(lgN+1)次比较
插入一个新元素最坏情况下需要访问2N次数组。
值得强调是:

  • 如果使用Key不是Java 自定义类型的话必须要覆写equals()方法以及实现Comparable<T>接口,否则的话会报java.lang.ClassCastException。
  • key 不能为null ,value 可以为null

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Created by hsc on 17/6/17.
 */
public class BinarySearchST<Key, Value> implements SymbolTable<Key, Value> {

    private static final int INIT_CAPACITY = 1 << 4; //16
    private Key[] keys;
    private Value[] vals;
    private int size = 0;

    public BinarySearchST() {
        this(INIT_CAPACITY);
    }

    @SuppressWarnings("unchecked")
    public BinarySearchST(int initialCapacity) {
        if (initialCapacity < 0) {
            throw new IllegalArgumentException("Illegal Capacity: " +
                    initialCapacity);
        }

        keys = (Key[]) new Object[initialCapacity];
        vals = (Value[]) new Object[initialCapacity];
    }

    @Override
    public Value put(Key key, Value value) {
        checkKey(key);
        int pos = rank(key);
        if (pos < size && compare(keys[pos], key) == 0) {
            vals[pos] = value;
            return vals[pos];
        }
        if (size == keys.length) {
            resize(keys.length * 2);
        }
        for (int i = size; i > pos; i--) {
            keys[i] = keys[i - 1];
            vals[i] = vals[i - 1];
        }
        keys[pos] = key;
        vals[pos] = value;
        size++;
        return vals[pos];
    }

    @Override
    public Value get(Key key) {
        checkKey(key);
        int pos = rank(key);
        if (pos < size && compare(keys[pos], key) == 0) {
            return vals[pos];
        }
        return null;
    }

    @Override
    public Value delete(Key key) {
        checkKey(key);
        int pos = rank(key);
        if (pos < size && compare(keys[pos], key) != 0) {
            return null;
        }
        Value tempV = vals[pos];
        for (int i = pos; i < size - 1; i++) {
            keys[i] = keys[i + 1];
            vals[i] = vals[i + 1];
        }
        size--;
        if (size > 0 && size == keys.length / 4) {
            resize(keys.length / 2);
        }
        return tempV;
    }

    @Override
    public boolean containsKey(Key key) {
        checkKey(key);
        int pos = rank(key);
        if (pos < size && compare(keys[pos], key) == 0) {
            return true;
        }
        return false;
    }

    @Override
    public boolean isEmpty() {
        return size() == 0;
    }

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

    @Override
    public Iterator<Key> keys() {
        List<Key> list = new ArrayList<>(size);
        for (Key key : keys) {
            list.add(key);
        }
        return list.iterator();
    }

    private void checkKey(Key key) {
        if (key == null) {
            throw new IllegalArgumentException("argument is null");
        }
    }
    private int rank(Key key) {
        int low = 0;
        int high = size - 1;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            int cmp = compare(key, keys[mid]);
            if (cmp < 0) {
                high = mid - 1;
            } else if (cmp > 0) {
                low = mid + 1;
            } else {
                return mid;
            }
        }
        return low;
    }

    @SuppressWarnings("unchecked")
    private void resize(int capacity) {
        Key[] tempk = (Key[]) new Comparable[capacity];
        Value[] tempv = (Value[]) new Object[capacity];
        for (int i = 0; i < size; i++) {
            tempk[i] = keys[i];
            tempv[i] = vals[i];
        }
        vals = tempv;
        keys = tempk;
    }

    @SuppressWarnings("unchecked")
    private int compare(Object k1, Object k2) {
        return ((Comparable<? super Key>) k1).compareTo((Key) k2);
    }
}

测试代码:

public class TestMain {
    public static void main(String[] args) {
        SymbolTable<Integer, Integer> binarySearchST = new BinarySearchST<>();
        for (int i = 0; i < 30; i++) {
            binarySearchST.put(i, i);
        }
        for (int i = 0; i < 30; i++) {
            System.out.println(binarySearchST.delete(i));
        }
        for (int i = 0; i < 30; i++) {
            binarySearchST.put(i, i);
        }
        binarySearchST.put(1, null);
        for (int i = 0; i < 30; i++) {
            System.out.println(binarySearchST.get(i));
        }
        System.out.println("size"+binarySearchST.size());
    }
}

2 总结

可以看出,有序数组实现符号表比较适合读频繁,插入不频繁的场景。典型如session(读多,写少)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值