package cn.ywrby.Searches;
//二分查找,基于有序数组
import edu.princeton.cs.algs4.Queue;
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
import java.util.NoSuchElementException;
public class BinarySearchST,Value> {
private static final int INIT_CAPACITY=2; //定义数组的初始大小
private Key[] keys; //键数组
private Value[] vals; //值数组
private int n=0 ; //数组大小
//无参构造函数
public BinarySearchST(){
this(INIT_CAPACITY); //利用固定初始大小调用含餐构造函数
}
//含参构造函数
public BinarySearchST(int capacity){
keys=(Key[]) new Comparable[capacity];
vals=(Value[])new Object[capacity];
}
//动态调整数组大小
private void resize(int capacity){
assert capacity>=n:"不可以动态将数组调大"; //判断传入容量大小,不可以将容量调大。只通过put增加数组大小
//assert [boolean 表达式] : [错误表达式 (日志)] 返回一个报错
Key[] tempKey=(Key[]) new Comparable[capacity];
Value[] tempValue=(Value[]) new Object[capacity];
for(int i=0;i
tempKey[i]=keys[i];
tempValue[i]=vals[i];
}
vals=tempValue;
keys=tempKey;
}
public int size(){return n;}
public boolean isEmpty(){return size()==0;}
//判断键是否存在
public boolean contains(Key key) {
//如果键为null即报错,警告键不可能为null
if (key == null) throw new IllegalArgumentException("argument to contains() is null");
return get(key) != null;
}
public Value get(Key key){
if (key == null) throw new IllegalArgumentException("argument to get() is null"); //防止搜索null键
if(isEmpty()) return null; //防止搜索空数组
int i=rank(key); //获取对应键的索引值
if(i
return null; //未找到
}
/*
*查找目标键的值
* 如果存在,返回的对应键的索引值
*如果不存在,返回表中小于它的键的数量(即新键的位置)
* */
public int rank(Key key){
if(key==null) throw new IllegalArgumentException("argument to rank() is null"); //避免索引null值
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; //while循环结束条件是lo>hi此时lo的值即为小于key的键的数量
}
//插入元素
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
vals[i]=val;
return;
}
//如果键不存在
//判断是否需要动态调整数组大小
if(n==keys.length){
resize(keys.length*2);
}
//将值按键序放入
for(int j=n;j>i;j--){
keys[j]=keys[j-1];
vals[j]=vals[j-1];
}
keys[i]=key;
vals[i]=val;
n++;
assert check();
}
//删除对应键的元素
public void delete(Key key){
if (key == null) throw new IllegalArgumentException("argument to delete() is null");
if (isEmpty()) return;
int i=rank(key);
//不存在对应键
if(i==n || keys[i].compareTo(key)!=0 ) return;
//存在对应键
for(int j=i;j
keys[j]=keys[j+1];
vals[j]=vals[j+1];
}
n--;
keys[n]=null;
vals[n]=null;
//删减后动态调整数组大小
if (n > 0 && n == keys.length/4) resize(keys.length/2);
assert check();
}
//删除最小元素
public void deleteMin() {
if (isEmpty()) throw new NoSuchElementException("Symbol table underflow error");
delete(min());
}
//删除最大元素
public void deleteMax() {
if (isEmpty()) throw new NoSuchElementException("Symbol table underflow error");
delete(max());
}
//返回数组最小值
public Key min() {
if (isEmpty()) throw new NoSuchElementException("called min() with empty symbol table");
return keys[0];
}
//返回数组最大值
public Key max() {
if (isEmpty()) throw new NoSuchElementException("called max() with empty symbol table");
return keys[n-1];
}
//返回数组第k个键
public Key select(int k) {
if (k < 0 || k >= size()) {
throw new IllegalArgumentException("called select() with invalid argument: " + k);
}
return keys[k];
}
//向下取整,找出小于等于该键的最大键
public Key floor(Key key) {
if (key == null) throw new IllegalArgumentException("argument to floor() is null");
int i = rank(key);
if (i < n && key.compareTo(keys[i]) == 0) return keys[i];
if (i == 0) return null;
else return keys[i-1];
}
//向上取整,找出大于等于该键的最小键
public Key ceiling(Key key) {
if (key == null) throw new IllegalArgumentException("argument to ceiling() is null");
int i = rank(key);
if (i == n) return null;
else return keys[i];
}
//返回表中所有键的集合(已排序)
public Iterable keys() {
return keys(min(), max());
}
//返回表中从lo至hi的所有键的集合
public Iterable 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 queue = new Queue();
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;
}
//检查数组是否符合规定条件
private boolean check() {
return isSorted() && rankCheck();
}
//检查是否已经排序
private boolean isSorted() {
for (int i = 1; i < size(); i++)
if (keys[i].compareTo(keys[i-1]) < 0) return false;
return true;
}
//检查是否出现重复的键
private boolean rankCheck() {
for (int i = 0; i < size(); i++)
if (i != rank(select(i))) return false;
for (int i = 0; i < size(); i++)
if (keys[i].compareTo(select(rank(keys[i]))) != 0) return false;
return true;
}
public static void main(String[] args) {
BinarySearchST st = new BinarySearchST();
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));
}
}