哈希函数:
1.经典的哈希函数接受的输入域是无穷的,而输出域相对来说是有限的。比如MD5会返回一个哈希码它是16进制的,是2^64次方的范围;SHA-1会返回2^128的范围。不管什么范围,返回域是有限的。
2.哈希函数不是随机函数,相同的输入值一定得到相同的返回值。
3.由于哈希函数接受的输入域是无穷的,而输出域相对来说是有限的,可能会导致不同的输入也可能对应一个输出。把这种情况称为哈希碰撞。
4.(离散型!重要)虽然输入域是无穷大,输出域是一个s,但是不同的输入如果想得到s域上的返回值,在整个s域上得到的返回值会均匀分布。例如:input(0-99),output(0,1,2),如果输入域的数都不相同,正好出现了100个数,那么输出得到0的次数差不多是33次,得到1的次数差不多也是33次,得到2的次数差不多也是33次。当100个数都不同,得到的每一个数的次数基本维持在平均水平。(均衡性越好,则离散型越好,这个哈希函数越优良)哈希函数这种离散型是为了打乱输入规律。
哈希表:
假设一开始一个数组长度为17,假设要把一个东西放到这个哈希表中去,假设要放一个字符串“zuo”,“zuo”通过哈希函数算出来的哈希值是2^64范围的,将这个值mod17,最终会放到0-16位置中的一个。哈希表一开始就是一坨哈希域0到16,0到16每一个后面串上链表。当加的不同的数据没那么多时,因为哈希函数在0-16上算出来的返回值是均匀分布的,则0的链表长度,1的链表长度...一直到16的链表长度,几乎均匀的长。
java里面是怎么实现的呢?开头还是这么算,0到16就相当于桶,每一个桶后面串的是红黑树。在java里面会遇到hashset和hashmap,hashset往里加的时候只能加个key,而hashmap往里加的时候可以放(key,value)。这个hashset和hashmap在结构上其实是一样的,hashmap再多封装一个数据对象就可以了。比如0这个位置后面串着"zuo"->"cheng",用hashset可以查"zuo"在结构中有没有,用hashmap可以在0这个位置找到“zuo”再把对应的数据对象取出来。
(注意:hash函数不是排序的,跟排序一毛钱关系都没有,hash函数在java里面叫做hashmap,红黑树在java里面叫做treemap)
hashmap在面试时候如果要用它,可以认为增删改查都是O(1)的操作。但虽然可以默认为常用时间,但是常数项较大。和加入的数据量没关系,但是常数项比较大,因为hash函数在算的时候代价比较高。
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
public class HashMap {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put("zuo", "31");
System.out.println(map.containsKey("zuo"));
System.out.println(map.containsKey("chengyun"));
System.out.println("=========================");
System.out.println(map.get("zuo"));
System.out.println(map.get("chengyun"));
System.out.println("=========================");
System.out.println(map.isEmpty());
System.out.println(map.size());
System.out.println("=========================");
System.out.println(map.remove("zuo"));
System.out.println(map.containsKey("zuo"));
System.out.println(map.get("zuo"));
System.out.println(map.isEmpty());
System.out.println(map.size());
System.out.println("=========================");
map.put("zuo", "31");
System.out.println(map.get("zuo"));
map.put("zuo", "32");
System.out.println(map.get("zuo"));
System.out.println("=========================");
map.put("zuo", "31");
map.put("cheng", "32");
map.put("yun", "33");
for (String key : map.keySet()) {
System.out.println(key);
}
System.out.println("=========================");
for (String values : map.values()) {
System.out.println(values);
}
System.out.println("=========================");
map.clear();
map.put("A", "1");
map.put("B", "2");
map.put("C", "3");
map.put("D", "1");
map.put("E", "2");
map.put("F", "3");
map.put("G", "1");
map.put("H", "2");
map.put("I", "3");
for (Entry<String, String> entry : map.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "," + value);
}
System.out.println("=========================");
// you can not remove item in map when you use the iterator of map
// for(Entry<String,String> entry : map.entrySet()){
// if(!entry.getValue().equals("1")){
// map.remove(entry.getKey());
// }
// }
// if you want to remove items, collect them first, then remove them by
// this way.
List<String> removeKeys = new ArrayList<String>();
for (Entry<String, String> entry : map.entrySet()) {
if (!entry.getValue().equals("1")) {
removeKeys.add(entry.getKey());
}
}
for (String removeKey : removeKeys) {
map.remove(removeKey);
}
for (Entry<String, String> entry : map.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "," + value);
}
System.out.println("=========================");
}
}
题目:
设计一种结构,在该结构中有如下三个功能:
insert(key):将某个key加入到该结构,做到不重复加入。
delete(key):将原本在结构中的某个key移除。
getRandom():等概率随即返回结构中的任何一个key。
要求:insert,delete和getRandom方法的时间复杂度都是O(1)
import java.util.HashMap;
public class RandomPool {
public static class Pool<K> {
private HashMap<K, Integer> keyIndexMap;
private HashMap<Integer, K> indexKeyMap;
private int size;
public Pool() {
this.keyIndexMap = new HashMap<K, Integer>();
this.indexKeyMap = new HashMap<Integer, K>();
this.size = 0;
}
public void insert(K key) {
if (!this.keyIndexMap.containsKey(key)) {
this.keyIndexMap.put(key, this.size);
this.indexKeyMap.put(this.size++, key);
}
}
public void delete(K key) {
if (this.keyIndexMap.containsKey(key)) {
int deleteIndex = this.keyIndexMap.get(key);
int lastIndex = --this.size;
K lastKey = this.indexKeyMap.get(lastIndex);
this.keyIndexMap.put(lastKey, deleteIndex);
this.indexKeyMap.put(deleteIndex, lastKey);
this.keyIndexMap.remove(key);
this.indexKeyMap.remove(lastIndex);
}
}
public K getRandom() {
if (this.size == 0) {
return null;
}
int randomIndex = (int) (Math.random() * this.size); // 0 ~ size -1
return this.indexKeyMap.get(randomIndex);
}
}
public static void main(String[] args) {
Pool<String> pool = new Pool<String>();
pool.insert("zuo");
pool.insert("cheng");
pool.insert("yun");
System.out.println(pool.getRandom());
System.out.println(pool.getRandom());
System.out.println(pool.getRandom());
System.out.println(pool.getRandom());
System.out.println(pool.getRandom());
System.out.println(pool.getRandom());
}
}