无序链表中的顺序查找
import edu.princeton.cs.algs4.Stack;
/**
* 算法 3.1 顺序查找(基于无序链表)
* @author he
*/
public class SequentialSearchST<Key, Value> {
private Node first;// 链表首结点
private int N; // 链表元素个数
private class Node {
Key key;
Value value;
Node next;
public Node(Key key, Value value, Node next) {
this.key = key;
this.value = value;
this.next = next;
}
}
/**
* 根据键获取值
* @param key
* @return
*/
public Value get(Key key) {
if (key == null) {
throw new NullPointerException("key can't be null");
}
for (Node x = first; x != null; x = x.next) {
if (x.key.equals(key)) {
return x.value; // 命中
}
}
return null;// 未命中
}
/**
* 向链表中添加新的键值对
* @param key
* @param value
*/
public void put(Key key, Value value) {
if (key == null) {
throw new NullPointerException("key can't be null");
}
for (Node x = first; x != null; x = x.next) {
if (key.equals(x.key)) {
x.value = value;// 命中 更新value值
return;
}
}
first = new Node(key, value, first);// 未命中,新结点
N++;
}
// 元素个数
public int size() {
return N;
}
public boolean isEmpty() {
return N == 0;
}
public boolean contains(Key key) {
if (key == null)
throw new NullPointerException("key 不能为null");
return get(key) != null;
}
/**
* 根据键删除指定键值对
* @param key
*/
public void delete(Key key) {
if (key == null)
throw new NullPointerException("key 不能为 null");
first = delete(first, key);
}
private Node delete(Node x, Key key) {
if (x == null) {
return null;
}
if (x.key.equals(key)) {
N--;
return x.next;
}
x.next = delete(x.next, key);
return x;
}
/**
* 因为链表的实现时以栈的形式,所以这里使用栈,这样就能保证return后得到的顺序数put时的顺序
* @return
*/
public Iterable<Key> keys() {
Stack<Key> stack = new Stack<Key>();
for (Node x = first; x != null; x = x.next)
stack.push(x.key);
return stack;
}
public static void main(String[] args) {
SequentialSearchST<String, Integer> st = new SequentialSearchST<String, Integer>();
st.put("A", 3);
st.put("B", 2);
st.put("C", 1);
System.out.println(st.get("A"));
st.delete("A");
System.out.println(st.size());// 2
System.out.println(st.get("B"));// null
for (String s : st.keys()) {
System.out.print(s);
}
}
}
有序数组中的二分查找
import edu.princeton.cs.algs4.Queue;
/**
* P239 算法3.2 二分查找(基于有序数组)
* @author he
*/
public class BinarySearchST<Key extends Comparable<Key>, Value> {
private Key keys[];
private Value values[];
private int N = 0;// 元素数量
@SuppressWarnings("unchecked")
public BinarySearchST(int capacity) {
keys = (Key[]) new Comparable[capacity];
values = (Value[]) new Object[capacity];
}
public int size() {
return N;
}
public boolean isEmpty() {
return N == 0;
}
/**
* 根据Key返回对应的Value
* @param key
* @return
*/
public Value get(Key key) {
if (key == null) {
throw new RuntimeException("key can't be null");
}
if (isEmpty()) {
return null;
}
int i = rank(key);
if (i < N && keys[i].compareTo(key) == 0) {
return values[i];
} else {
return null;
}
}
/**
* 二分查找,如过存在返回键的index,如果不存在返回小于它的键的数量,因为lo在迭代时改变
* @param key
* @return
*/
public int rank(Key key) {
int lo = 0, hi = N - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
int t = key.compareTo(keys[mid]);
if (t > 0) {
lo = mid + 1;
} else if (t < 0) {
hi = mid - 1;
} else {
return mid;
}
}
return lo;
}
/**
* 向符号表中添加键值对
* @param key
* @param value
*/
public void put(Key key, Value value) {
if (key == null) {
throw new RuntimeException("key can't be null");
}
int i = rank(key);
// 命中,已存在,更新
if (i < N && keys[i].compareTo(key) == 0) {
values[i] = value;
return;
}
// 未命中添加,此时是有序添加
for (int j = N; j > i; j--) {
keys[j] = keys[j - 1];
values[j] = values[j - 1];
}
keys[i] = key;
values[i] = value;
N++;
}
/**
* 根据key删除键值对 将该键后面的键前移
* @param key
*/
public void delete(Key key) {
if (key == null) {
throw new RuntimeException("key can't be null");
}
int i = rank(key);
// 不包含key
if (i == N || keys[i].compareTo(key) != 0) {
return;
}
for (int j = i; j < N - 1; j++) {
keys[j] = keys[j + 1];
values[j] = values[j + 1];
}
keys[N - 1] = null;
values[N - 1] = null;
N--;
}
// 返回最小键
public Key min() {
return keys[0];
}
public Key max() {
return keys[N - 1];
}
/**
* 根据下标找key
* @param k
* 下标
* @return
*/
public Key select(int k) {
return keys[k];
}
/**
* 大于等于该键的最小键
* @param key
* @return
*/
public Key ceiling(Key key) {
// 因为rank做了处理,所以即使未找到key人能返回刚好比key大的index
int i = rank(key);
return keys[i];
}
/**
* 小于等于该键的最大键
* @param key
* @return
*/
public Key floor(Key key) {
// 有该键
if (get(key) != null) {
return keys[rank(key)];
} else if (get(key) == null && rank(key) != 0) {// 不存在该键且rank(key)不再数组最左边
return keys[rank(key) - 1];
} else {
return null;
}
}
public Iterable<Key> key(){
Queue<Key> queue=new Queue<Key>();
for(int i=0;i<N;i++){
queue.enqueue(keys[i]);
}
return queue;
}
public static void main(String[] args) {
BinarySearchST<String, Integer> st = new BinarySearchST<String, Integer>(10);
st.put("A", 3);
st.put("C", 2);
st.put("B", 1);
System.out.println(st.key());//A B C
System.out.println(st.get("B"));
System.out.println(st.ceiling("D"));// null
st.delete("A");
System.out.println(st.get("A"));// null
System.out.println(st.floor("A"));// null
System.out.println(st.key());// B C
}
}
递归的rank()保留了以下性质:
如果表中存在该键,rank()应该返回该键的位置,也就是表中小于它的键的数量;
如果表中不存在该键,rank()还是应该返回表中小于它的键的数量;