数据结构与算法——哈希函数与哈希表等

Posted wwj99

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法——哈希函数与哈希表等相关的知识,希望对你有一定的参考价值。

认识哈希函数和哈希表的实现

MD5 表达16^16范围的值 SHal 表达16^32范围的值

输入相同,即输出相同,不随机

不同的输出,输出相同

均匀性,离散性

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(map.get("zuo"));
        System.out.println(map.get("chengyun"));

        System.out.println(map.isEmpty());
        System.out.println(map.size());

        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());

        map.put("zuo", "31");
        System.out.println(map.get("zuo"));
        map.put("zuo", "32");
        System.out.println(map.get("zuo"));

        map.put("zuo", "31");
        map.put("cheng", "32");
        map.put("yun", "33");

        for (String key : map.keySet()) {
            System.out.println(key);
        }

        for (String values : map.values()) {
            System.out.println(values);
        }

        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);
        }
        // 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);
        }
    }
}

设计RandomPool结构

设计一种结构,在该结构中有如下三个功能:

insert (key):将某个key加入到该结构,做到不重复加入 delete (key):将原本在结构中的某个key移除 getRandom():等概率随机返回结构中的任何一个key。

【要求】

Insert、 delete和getRandom方法的时间复杂度都是0 (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());
    }
}

详解布隆过滤器

n=样本量 p=失误率

m = -n * ln p / (ln 2)^2 空间大小

k = ln 2 * m/n 约等于 0.7 * m/n

p真 = (1 - e ^ (-n * k真 / m真))^k真

位图

public class BitMap {
    public static void main(String[] args) {

        int a = 0;      
        // a  32 bit
        int[] arr = new int[10]; // 32bit * 10 -> 320 bits
        
        // arr[0]  int  0  ~ 31
        // arr[1]  int  32 ~ 63
        // arr[2]  int  64 ~ 95

        int i = 178; // 想取得178个bit的状态
        int numIndex = i / 32;
        int bitIndex = i % 32;
        
        // 拿到178位的状态
        int s = (      (arr[numIndex] >> (bitIndex))        & 1);
        // 请把178位的状态改成1
        arr[numIndex] = arr[numIndex] | (1 << (bitIndex));
        i = 178; // 请把178位的状态改成0
        arr[numIndex] = arr[numIndex] & (~   (1 << bitIndex)  );
        i = 178; // 请把178位的状态拿出来
        // bit 0 1
        int bit = (arr[i / 32] >> (i % 32)) & 1;
    }
}

详解一致性哈希原理

https://www.jianshu.com/p/e968c081f563

岛问题

一个矩阵中只有。和1两种值,每个位置都可以和自己的上、下、左、右 四个位置相连,如 果有一片1连在一起,这个部分叫做一个岛,求一个矩阵中有多少个岛?

【举例】

001010

111010 100100 000000

这个矩阵中有三个岛 【进阶】如何设计一个并行算法解决这个问题

public class Code03_Islands {

    public static int countIslands(int[][] m) {
        if (m == null || m[0] == null) {
            return 0;
        }
        int N = m.length;
        int M = m[0].length;
        int res = 0;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                if (m[i][j] == 1) {
                    res++;
                    infect(m, i, j, N, M);
                }
            }
        }
        return res;
    }

    public static void infect(int[][] m, int i, int j, int N, int M) {
        if (i < 0 || i >= N || j < 0 || j >= M || m[i][j] != 1) {
            return;
        }
        // i,j没越界,并且当前位置值是1
        m[i][j] = 2;
        infect(m, i + 1, j, N, M);
        infect(m, i - 1, j, N, M);
        infect(m, i, j + 1, N, M);
        infect(m, i, j - 1, N, M);
    }

    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(countIslands(m1));

        int[][] m2 = {  { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 
                        { 0, 1, 1, 1, 1, 1, 1, 1, 0 }, 
                        { 0, 1, 1, 1, 0, 0, 0, 1, 0 },
                        { 0, 1, 1, 0, 0, 0, 1, 1, 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(countIslands(m2));
    }
}

并查集结构的详解和实现

import java.util.HashMap;
import java.util.List;
import java.util.Stack;

public class Code04_UnionFind {

    // 样本进来会包一层,叫做元素
    public static class Element<V> {
        public V value;

        public Element(V value) {
            this.value = value;
        }
    }

    public static class UnionFindSet<V> {
        public HashMap<V, Element<V>> elementMap;
        // key  某个元素  value 该元素的父
        public HashMap<Element<V>, Element<V>> fatherMap;
        // key 某个集合的代表元素   value 该集合的大小
        public HashMap<Element<V>, Integer> sizeMap;

        public UnionFindSet(List<V> list) {
            elementMap = new HashMap<>();
            fatherMap = new HashMap<>();
            sizeMap = new HashMap<>();
            for (V value : list) {
                Element<V> element = new Element<V>(value);
                elementMap.put(value, element);
                fatherMap.put(element, element);
                sizeMap.put(element, 1);
            }
        }

        // 给定一个ele,往上一直找,把代表元素返回
        private Element<V> findHead(Element<V> element) {
            Stack<Element<V>> path = new Stack<>();
            while (element != fatherMap.get(element)) {
                path.push(element);
                element = fatherMap.get(element);
            }
            while (!path.isEmpty()) {
                fatherMap.put(path.pop(), element);
            }
            return element;
        }

        public boolean isSameSet(V a, V b) {
            if (elementMap.containsKey(a) && elementMap.containsKey(b)) {
                return findHead(elementMap.get(a)) == findHead(elementMap.get(b));
            }
            return false;
        }

        public void union(V a, V b) {
            if (elementMap.containsKey(a) && elementMap.containsKey(b)) {
                Element<V> aF = findHead(elementMap.get(a));
                Element<V> bF = findHead(elementMap.get(b));
                if (aF != bF) {
                    Element<V> big = sizeMap.get(aF) >= sizeMap.get(bF) ? aF : bF;
                    Element<V> small = big == aF ? bF : aF;
                    fatherMap.put(small, big);
                    sizeMap.put(big, sizeMap.get(aF) + sizeMap.get(bF));
                    sizeMap.remove(small);
                }
            }
        }
    }
}

以上是关于数据结构与算法——哈希函数与哈希表等的主要内容,如果未能解决你的问题,请参考以下文章

C# 通俗说 哈希表

HashMap原理:哈希函数的设计

数据结构与算法实例(哈希表实现)

算法与数据结构之哈希表

哈希表与哈希(Hash)算法

手撸golang 基本数据结构与算法 哈希表