class5 哈希函数、哈希表和并查集(左程云左神算法 初级笔记 2018)

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));
    }
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值