class 5
DAY7
- 认识哈希函数和哈希表
- 哈希函数性质:1.输入域无穷大;2.输出域有穷大;3.若输入相等,则输出相等;4.若输入不相等,输出也可能相等(哈希碰撞)5.输出域上均匀分布
- 哈希函数特征:1.与输入规律无关;2.哈希函数生成16位的码每一位都是相互独立的(因此利用一个哈希函数可造出很多哈希函数)
- 哈希表的增删改查复杂度O(1)(哈希表的扩容复杂度log已n为底N,n为扩容的倍数,或者可以用离线扩容,因此哈希表的增删改查复杂度认为是O(1))
- 利用哈希函数做分流,处理大数据问题
package com.zuogod.java;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* @author quanquan
* @create 2020-04-30-11:46
*/
public class HashMapTest {
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("=========================");
}
}
- 设计RandomPool结构
【题目】 设计一种结构,在该结构中有如下三个功能:insert(key):将某个key加入到该结构,做到不重复加入。delete(key):将原本在结构中的某个key移除。 getRandom():等概率随机返回结构中的任何一个key。
【要求】 Insert、delete和getRandom方法的时间复杂度都是O(1)
package com.zuogod.java;
import java.util.HashMap;
/**
* @author quanquan
* @create 2020-04-30-13:24
*/
//使用两个哈希表
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 remove(K key){
if(this.keyIndexMap.containsKey(key)){
int deleteIndex = keyIndexMap.get(key);
int lastIndex = --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 index = (int)(Math.random() * this.size); //0 ~ size-1
return this.indexKeyMap.get(index);
}
}
public static void main(String[] args) {
Pool<String> pool = new Pool<String>();
pool.insert("zuo");
pool.insert("cheng");
pool.insert("yun");
pool.remove("zuo");
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());
}
}
-
认识布隆过滤器
-
某种类型的集合,但有失误率(不会把对的判错,但可能把不对的判对)
-
比特类型的map
数组大小:m = - (n * lnp) / (ln2)^2,其中,m为需要的bite位数,n为样本量,p为预期失误率;字节数为m/8
哈希函数的个数:K = ln2 * m/n = 0.7 * m/n
数组大小和哈希函数个数向上取整,真实失误率为:(1 - e ^ (- n*K/m))^K
-
-
认识一致性哈希
- 能够把数据迁移的代价变得很低,同时又负载均衡
- 虚拟节点技术
-
认识并查集结构
- 功能:1.快速查询两个元素是否属于一个集合,2.两个元素所在集合合并在一起
package com.zuogod.java;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;
public class UnionFind {
public static class Node {
// whatever you like,String\Int\Char...
}
public static class UnionFindSet {
public HashMap<Node, Node> fatherMap; //Key : child, value : father
public HashMap<Node, Integer> sizeMap; //某节点所在集合的节点数
public UnionFindSet(List<Node> nodes) {
makeSets(nodes);
}
public void makeSets(List<Node> nodes) {
fatherMap = new HashMap<Node, Node>();
sizeMap = new HashMap<Node, Integer>();
for (Node node : nodes) {
fatherMap.put(node, node);
sizeMap.put(node, 1);
}
}
private Node findHead(Node node) {
//非递归
// Stack<Node> stack = new Stack<>();
// Node cur = node;
// Node parent = fatherMap.get(cur);
// while (cur != parent){
// stack.push(cur);
// cur = parent;
// parent = fatherMap.get(cur);
// }
// while (!stack.isEmpty()){
// fatherMap.put(stack.pop(),parent);
// }
// return parent;
//递归
Node father = fatherMap.get(node);
if (father != node) {
father = findHead(father);
}
fatherMap.put(node, father);
return father;
}
public boolean isSameSet(Node a, Node b) {
return findHead(a) == findHead(b);
}
public void union(Node a, Node b) {
if (a == null || b == null) {
return;
}
Node aHead = findHead(a);
Node bHead = findHead(b);
if (aHead != bHead) {
int aSetSize= sizeMap.get(aHead);
int bSetSize = sizeMap.get(bHead);
if (aSetSize <= bSetSize) {
fatherMap.put(aHead, bHead);
sizeMap.put(bHead, aSetSize + bSetSize);
} else {
fatherMap.put(bHead, aHead);
sizeMap.put(aHead, aSetSize + bSetSize);
}
}
}
}
public static void main(String[] args) {
}
}
- 岛问题
一个矩阵中只有0和1两种值,每个位置都可以和自己的上、下、左、右四个位置相连,如果有一片1连在一起,这个部分叫做一个岛,求一个矩阵中有多少个岛?
举例:
0 0 1 0 1 0
1 1 1 0 1 0
1 0 0 1 0 0
0 0 0 0 0 0
这个矩阵中有三个岛。- 利用并查集,可以做到并行,多CPU
package com.zuogod.java;
/**
* 一般做法,单CPU
* @author quanquan
* @create 2020-04-30-21:37
*/
public class Islands {
public static int islands(int[][] matrix){
int M = matrix.length; //矩阵的行数
int N = matrix[0].length; //矩阵的列数
int res = 0;
for (int i = 0; i<M; i++){
for (int j = 0; j<N; j++){
if (matrix[i][j] == 1){
res++;
infect(matrix,i,j,M,N);
}
}
}
return res;
}
public static void infect(int[][] matrix,int i,int j,int M,int N){
if (i<0 || i>=M || j<0 || j>=N || matrix[i][j] == 0 || matrix[i][j] == 2){
return;
}
matrix[i][j] = 2;
infect(matrix,i+1,j,M,N);
infect(matrix,i-1,j,M,N);
infect(matrix,i,j+1,M,N);
infect(matrix,i,j-1,M,N);
}
public static void main(String[] args) {
int[][] m1 = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 1, 1, 0, 1, 1, 1, 0 },
{ 0, 1, 1, 1, 0, 0, 0, 1, 0 },
{ 0, 1, 1, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 0, 0, 1, 1, 1, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 }, };
System.out.println(islands(m1));
}
}