实战总结
Lab 8: HashMap
/******************************************************************************
* Compilation: javac SeparateChainingHashST.java
* Execution: java SeparateChainingHashST < input.txt
* Dependencies: StdIn.java StdOut.java
* Data files: https://algs4.cs.princeton.edu/34hash/tinyST.txt
*
* A symbol table implemented with a separate-chaining hash table.
*
******************************************************************************/
/**
* The {@code SeparateChainingHashST} class represents a symbol table of generic
* key-value pairs.
* It supports the usual <em>put</em>, <em>get</em>, <em>contains</em>,
* <em>delete</em>, <em>size</em>, and <em>is-empty</em> methods.
* It also provides a <em>keys</em> method for iterating over all of the keys.
* A symbol table implements the <em>associative array</em> abstraction:
* when associating a value with a key that is already in the symbol table,
* the convention is to replace the old value with the new value.
* Unlike {@link java.util.Map}, this class uses the convention that
* values cannot be {@code null}—setting the
* value associated with a key to {@code null} is equivalent to deleting the key
* from the symbol table.
* <p>
* This implementation uses a separate chaining hash table. It requires that
* the key type overrides the {@code equals()} and {@code hashCode()} methods.
* The expected time per <em>put</em>, <em>contains</em>, or <em>remove</em>
* operation is constant, subject to the uniform hashing assumption.
* The <em>size</em>, and <em>is-empty</em> operations take constant time.
* Construction takes constant time.
* <p>
* For additional documentation, see <a href="https://algs4.cs.princeton.edu/34hash">Section 3.4</a> of
* <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne.
* For other implementations, see {@link ST}, {@link BinarySearchST},
* {@link SequentialSearchST}, {@link BST}, {@link RedBlackBST}, and
* {@link LinearProbingHashST},
*
* @author Robert Sedgewick
* @author Kevin Wayne
*/
public class SeparateChainingHashST<Key, Value> {
private static final int INIT_CAPACITY = 4;
private int n; // number of key-value pairs
private int m; // hash table size
private SequentialSearchST<Key, Value>[] st; // array of linked-list symbol tables
/**
* Initializes an empty symbol table.
*/
public SeparateChainingHashST() {
this(INIT_CAPACITY);
}
/**
* Initializes an empty symbol table with {@code m} chains.
* @param m the initial number of chains
*/
public SeparateChainingHashST(int m) {
this.m = m;
st = (SequentialSearchST<Key, Value>[]) new SequentialSearchST[m];
for (int i = 0; i < m; i++)
st[i] = new SequentialSearchST<Key, Value>();
}
// resize the hash table to have the given number of chains,
// rehashing all of the keys
private void resize(int chains) {
SeparateChainingHashST<Key, Value> temp = new SeparateChainingHashST<Key, Value>(chains);
for (int i = 0; i < m; i++) {
for (Key key : st[i].keys()) {
temp.put(key, st[i].get(key));
}
}
this.m = temp.m;
this.n = temp.n;
this.st = temp.st;
}
// hash value between 0 and m-1
private int hash(Key key) {
return (key.hashCode() & 0x7fffffff) % m;
}
/**
* Returns the number of key-value pairs in this symbol table.
*
* @return the number of key-value pairs in this symbol table
*/
public int size() {
return n;
}
/**
* Returns true if this symbol table is empty.
*
* @return {@code true} if this symbol table is empty;
* {@code false} otherwise
*/
public boolean isEmpty() {
return size() == 0;
}
/**
* Returns true if this symbol table contains the specified key.
*
* @param key the key
* @return {@code true} if this symbol table contains {@code key};
* {@code false} otherwise
* @throws IllegalArgumentException if {@code key} is {@code null}
*/
public boolean contains(Key key) {
if (key == null) throw new IllegalArgumentException("argument to contains() is null");
return get(key) != null;
}
/**
* Returns the value associated with the specified key in this symbol table.
*
* @param key the key
* @return the value associated with {@code key} in the symbol table;
* {@code null} if no such value
* @throws IllegalArgumentException if {@code key} is {@code null}
*/
public Value get(Key key) {
if (key == null) throw new IllegalArgumentException("argument to get() is null");
int i = hash(key);
return st[i].get(key);
}
/**
* Inserts the specified key-value pair into the symbol table, overwriting the old
* value with the new value if the symbol table already contains the specified key.
* Deletes the specified key (and its associated value) from this symbol table
* if the specified value is {@code null}.
*
* @param key the key
* @param val the value
* @throws IllegalArgumentException if {@code key} is {@code null}
*/
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;
}
// double table size if average length of list >= 10
if (n >= 10*m) resize(2*m);
int i = hash(key);
if (!st[i].contains(key)) n++;
st[i].put(key, val);
}
/**
* Removes the specified key and its associated value from this symbol table
* (if the key is in this symbol table).
*
* @param key the key
* @throws IllegalArgumentException if {@code key} is {@code null}
*/
public void delete(Key key) {
if (key == null) throw new IllegalArgumentException("argument to delete() is null");
int i = hash(key);
if (st[i].contains(key)) n--;
st[i].delete(key);
// halve table size if average length of list <= 2
if (m > INIT_CAPACITY && n <= 2*m) resize(m/2);
}
// return keys in symbol table as an Iterable
public Iterable<Key> keys() {
Queue<Key> queue = new Queue<Key>();
for (int i = 0; i < m; i++) {
for (Key key : st[i].keys())
queue.enqueue(key);
}
return queue;
}
/**
* Unit tests the {@code SeparateChainingHashST} data type.
*
* @param args the command-line arguments
*/
public static void main(String[] args) {
SeparateChainingHashST<String, Integer> st = new SeparateChainingHashST<String, Integer>();
for (int i = 0; !StdIn.isEmpty(); i++) {
String key = StdIn.readString();
st.put(key, i);
}
// print keys
for (String s : st.keys())
StdOut.println(s + " " + st.get(s));
}
}
Copyright © 2000–2017, Robert Sedgewick and Kevin Wayne.
Last updated: Fri Oct 20 12:50:46 EDT 2017.
CLab8 Heaps and Hashes
- 声明和使用java 自带的 “import java.util.PriorityQueue;”
a. 引用 “import java.util.PriorityQueue;”包
b. 声明
PriorityQueue<Flight> minStartTime=new PriorityQueue<>(new ComparatorStartTime());
private class ComparatorStartTime implements java.util.Comparator<Flight>{
/**
* Compares its two arguments for order. Returns a negative integer,
* zero, or a positive integer as the first argument is less than,
* equal to, or greater than the second.
* */
@Override
public int compare(Flight o1, Flight o2){
return o1.startTime-o2.startTime;
}
}
若不在声明PQ时传入一个实现了Comparator的类,基于和HEAP 的PQ 会使用“natur order” 进行排序,既Java为每一个对象或数组默认实现的comparaTo方法。
2.关于HEAP 中排序的问题(从大到小还是从小到大)
希望heap以不同的顺序对队形进行排队,必须相应的在声明.PriorityQueue使用不同的实现了Comparator的类
该compare方法,用o1-o2,实现了从大到小排列
反之,o2-o1可以实现从小到大排列
private class ComparatorStartTime implements java.util.Comparator<Flight>{
/**
* Compares its two arguments for order. Returns a negative integer,
* zero, or a positive integer as the first argument is less than,
* equal to, or greater than the second.
* */
@Override
public int compare(Flight o1, Flight o2){
return o1.startTime-o2.startTime;
}
}
```
3.StringBuilder class中有很多可用的方法,例如```
```java
rollingString.append()
4.You may need to use comparators in your solution for comparing objects. You can construct a concrete class (which can be somewhat verbose) or use lambda functions instead. The syntax for declaring a lambda for a comparator is:
Comparator<Integer> intComparator = (i, j) -> i - j;
Comparator<Integer> intComparatorEquivalent = (i, j) -> {
int diff = i - j;
return diff;
};
5.Rolling hash:A rolling hash (also known as recursive hashing or rolling checksum) is a hash function where the input is hashed in a window that moves through the input.
A few hash functions allow a rolling hash to be computed very quickly—the new hash value is rapidly calculated given only the old hash value, the old value removed from the window, and the new value added to the window—similar to the way a moving average function can be computed much more quickly than other low-pass filters.
public void addChar(char c) {
/* FIX ME */
rollingString.insert(length,c);
preFirstChar=rollingString.charAt(0);
rollingString.deleteCharAt(0);
cachedHashValue-=preFirstChar*Math.pow(UNIQUECHARS,length-1);
cachedHashValue=cachedHashValue*UNIQUECHARS;
cachedHashValue+=c;
}
计算这种类型的HashCode,不用每次都计算全部的值,例如一个字符串,长度不变,每次向字符串尾部添加一个字符,同时去掉第一个字符,计算添加了一个新字符的新字符串的hashcode可以从老字符串中通过减去原字符串中第一个字符的hash值得到