符号表API
1.使用 泛型2.键不能为空
3.get方法是否返回空来测试给定的键是否存在于符号表中
4.关于删除 :延时删除---》将键对应的值置为空
即使删除---》立即从表中删除指定的键如put(key,null)
5.迭代:所有实现必须包含 iterator方法来返回一个迭代器
6. 所有对象都继承了equals()方法,自定义的键需要重写equals()方法
package Chapter3_1.SymbolTable;
/*符号表API
* 1.使用泛型
* 2.键不能为空
* 3.get方法是否返回空来测试给定的键是否存在于符号表中
* 4.关于删除 :延时删除---》将键对应的值置为空
* 即使删除---》立即从表中删除指定的键如put(key,null)
* 5.迭代:所有实现必须包含iterator方法来返回一个迭代器
* 6.所有对象都继承了equals()方法,自定义的键需要重写equals()方法
* */
public interface ST<Key,Value> {
public void put(Key key,Value value);
public Value get(Key key);
public void delete(Key key);
public boolean contains(Key key);
public boolean isEmpty();
public int size();
Iterable<Key> keys();//包含迭代器以方便用例遍历所有的键
}
基本实现
/*符号表的简单实现:测试时,用例的输出中键的顺序是不确定的*/package Chapter3_1.SymbolTable;
import com.sun.corba.se.impl.oa.poa.ActiveObjectMap.Key;
import jdk.internal.org.objectweb.asm.tree.analysis.Value;
public class SybolTable implements ST<Key, Value> {
@Override
public void put(Key key, Value value) {
//防御性代码
if (value == null) {
delete(key);
return;
}
}
@Override
public Value get(Key key) {
// TODO Auto-generated method stub
return null;
}
@Override
public void delete(Key key) {
put(key, null);
}
@Override
public boolean contains(Key key) {
return get(key) != null;
}
@Override
public boolean isEmpty() {
return size() == 0;
}
@Override
public int size() {
// TODO Auto-generated method stub
return 0;
}
@Override
public Iterable<Key> keys() {
// TODO Auto-generated method stub
return null;
}
}
有序符号表
/*有序符号表:测试用例的时候会将键按顺序打印出来,是一种索引用例*/package Chapter3_1.SymbolTable;
/*Ordered symbol tables.
* 有序符号表*/
public interface ST_puls<Key,Value> {
public void put(Key key,Value value);
public Value get(Key key);
public void delete(Key key);
public boolean contains(Key key);
public boolean isEmpty();
public int size();
public Key min();
public Key max();
public Key floor(Key key);//小于等于key的最大值
public Key ceiling(Key key);//大于等于key的最小值
public int rank(Key key);//小于key键的数量
public Key select(int k);//排名为k的键
public void deleteMin();
public void deleteMax();
public int size(Key lo,Key hi);//lo..hi之间键的数量
public Iterable<Key> keys(Key lo,Key hi);//lo..hi之间的所有键(已排序)
Iterable<Key> keys();//包含迭代器以方便用例遍历所有的键,所有键的集合,已排序
}
基本实现
package Chapter3_1.SymbolTable;
import com.sun.corba.se.impl.oa.poa.ActiveObjectMap.Key;
import jdk.internal.org.objectweb.asm.tree.analysis.Value;
public class SybolTable_puls<Key extends Comparable<Key>, Value> {
public void put(Key key, Value value) {
// 防御性代码
if (value == null) {
delete(key);
return;
}
}
public Value get(Key key) {
// TODO Auto-generated method stub
return null;
}
public void delete(Key key) {
put(key, null);
}
public boolean contains(Key key) {
return get(key) != null;
}
public boolean isEmpty() {
return size() == 0;
}
public int size() {
// TODO Auto-generated method stub
return 0;
}
public Iterable<Key> keys() {
return null;
}
public Key min() {
return null;
}
public Key max() {
return null;
}
public Key floor(Key key) {
return null;
}
public Key ceiling(Key key) {
return null;
}
public int rank(Key key) {
return 0;
}
public Key select(int k) {
return null;
}
public void deleteMin() {
delete(min());
}
public void deleteMax() {
delete(max());
}
public int size(Key lo, Key hi) {
if (lo.compareTo(lo) < 0) {
return 0;
} else if (contains(hi)) {
return rank(hi) - rank(lo) + 1;
} else {
return rank(hi) - rank(lo);
}
}
public Iterable<Key> keys(Key lo, Key hi) {
return keys(min(), max());
}
}
顺序查找(基于无序链表)
效率非常低效,无法满足处理庞大输入问题的需求,比较的总次数和查找次数与插入次数的乘积成正比package Chapter3_1.SymbolTable;
public class SequentialSearchST<Key, Value> {
/*
* 顺序查找 基于无序链表
* 随机命中(查找表中的每个键)---》~N/2
* 效率非常低效,无法满足处理庞大输入问题的需求,比较的总次数和查找次数与插入次数的乘积成正比
*/
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);
}
}
}
二分查找(基于有序数组)
package Chapter3_1.SymbolTable;
import edu.princeton.cs.algs4.Queue;
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
/*二分查找(基于有序数组)
* 该段符号表的实现用两个数组来保存键和值
* */
public class BinarySearchST<Key extends Comparable<Key>, Value> {
private static final int INIT_CAPACITY = 2;
private Key[] keys;
private Value[] vals;
private int N;
public BinarySearchST() {
this(INIT_CAPACITY);
}
@SuppressWarnings("unchecked")
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 int size() {
return N;
}
public Value get(Key key) {
if (isEmpty()) {
return null;
}
int i = rank(key);
if (i < N && keys[i].compareTo(key) == 0) {
return vals[i];
}
else {
return null;
}
}
public int rank(Key key) {// 二分查找运用开始
/*
* 首先将key和中间键比较,如果相等则返回其索引 如果小于中间键则在左半部分查找,大于则在右半部份查找
*/
int lo = 0, hi = N - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
int cmp = key.compareTo(keys[mid]);
if (cmp < 0)
hi = mid - 1;
else if (cmp > 0)
lo = mid + 1;
else
return mid;
}
return lo;
}
public void put(Key key, Value val) {
/* 此方法会在插入新元素前将所有较大的键向后移动一格 */
if (key == null)
throw new IllegalArgumentException("first argument to put() is null");
if (val == null) {
delete(key);
return;
}
int i = rank(key);
if (i < N && keys[i].compareTo(key) == 0) {
vals[i] = val;
return;
}
if (N == keys.length)
resize(2 * keys.length);
for (int j = N; j > i; j--) {
// 注意j>i的条件,代表是较大的键需要排在前面,循环其他键向后移动
keys[j] = keys[j - 1];
vals[j] = vals[j - 1];
}
keys[i] = key;
vals[i] = val;
N++;
}
public void delete(Key key) {
put(key, null);
}
public Key min() {
return keys[0];
}
public Key max() {
return keys[N - 1];
}
public Key select(int k) {
return keys[k];
}
public Key ceiling(Key key) {
int i = rank(key);
return keys[i];
}
public Key floor(Key key) {
int i = rank(key);
return keys[i];
}
public boolean contains(Key key) {
return get(key) != null;
}
public Iterable<Key> keys(Key lo, Key hi) {
if (lo == null)
throw new IllegalArgumentException("first argument to keys() is null");
if (hi == null)
throw new IllegalArgumentException("second argument to keys() is null");
Queue<Key> queue = new Queue<Key>();
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;
}
public boolean isEmpty() {
return size() == 0;
}
public Iterable<Key> keys() {
Queue<Key> q = new Queue<Key>();
for (int i = 0; i < keys.length; i++) {
q.enqueue(keys[i]);
}
return q;
}
public static void main(String[] args) {
BinarySearchST<String, Integer> st = new BinarySearchST<String, Integer>();
for (int i = 0; !StdIn.isEmpty(); i++) {
String key = StdIn.readString();
st.put(key, i);
}
for (String s : st.keys())
StdOut.println(s + " " + st.get(s));
}
}