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(读多,写少)