hash小讲

一、hash算法的基本思路

1.直接寻址法

取关键字或者其某个线性函数值为散列地址

2.数字分析法

分析数据后找出数字的规律进行构造

3.平方取中法

取关键字平方后的中间几位作为散列地址

4.折叠法

将关键字分割成位数相同的几部分,然后取这几部分的叠加和

5.随机数法

选择随机函数,取关键字的随机值

6.除留余数法

取关键字被某个不大于散列表长度的数p除后所得的余数,也可以与以上几种方法一起使用即先处理关键字再取余。一般p为素数。

二、具体的实现

MD5

  1. 填充输入信息长度使其=N*512+448
  2. 用64位记录填充之前信息长度,现在信息总长度变为(N+1)*512即512的倍数
  3. 装入四个幻数
  4. 把消息以512位为分组进行处理,每个分组进行4轮变换,第一组以四个幻数为起始变量,其余组以上一组的输出为变量,最后一组的输出即为MD5值

SHA

java Hashcode

Object.hashcode()

java默认实现的hashcode方法,是native方法,其实现原理是用对象的内存地址得到hash值

String

String对象的hash在刚创建时:

  1. 如果是由别的String拷贝而来,则将hash值赋值为拷贝对象的hash
  2. 否则,初始为0,延迟到使用hashCode函数时再进行计算

hashCode 的计算:
value中所有字符的加权值之和,每个字符的权值为$31^{index}$,index是字符在字符串中的下标

    private char value[];
    private int hash;
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

Integer等包装类

hashcode就是其封装值的值

数组

首先对数组中的数据类型进行判断,根据其类型进行调用

 public static int hashCode(Object obj) {
    if (obj == null) {
      return 0;
    }
    final Class<?> clazz = obj.getClass();
    if (!clazz.isArray()) {//非数组直接返回hashcode
      return obj.hashCode();
    }
    //获取数组的类型
    final Class<?> componentType = clazz.getComponentType();
    if (long.class.equals(componentType)) {
      return Arrays.hashCode((long[]) obj);
    } else if (int.class.equals(componentType)) {
      return Arrays.hashCode((int[]) obj);
    } else if (short.class.equals(componentType)) {
      return Arrays.hashCode((short[]) obj);
    } else if (char.class.equals(componentType)) {
      return Arrays.hashCode((char[]) obj);
    } else if (byte.class.equals(componentType)) {
      return Arrays.hashCode((byte[]) obj);
    } else if (boolean.class.equals(componentType)) {
      return Arrays.hashCode((boolean[]) obj);
    } else if (float.class.equals(componentType)) {
      return Arrays.hashCode((float[]) obj);
    } else if (double.class.equals(componentType)) {
      return Arrays.hashCode((double[]) obj);
    } else {
      return Arrays.hashCode((Object[]) obj);
    }
  }

但实际上不同类型数组的hashcode计算都大同小异,都是数组中所有元素的加权和+$31{n}$,n是数组的长度,每个元素的权值为$31$,index是元素在数组中的下标

    public static int hashCode(int a[]) {
        if (a == null)
            return 0;

        int result = 1;
        for (int element : a)
            result = 31 * result + element;

        return result;
    }

在hashmap中如何使用

hashmap中对key的hash值的计算不是直接使用其hash值,而是使用其hash值和hash值的前16位的按位或

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

在计算位置时,会将取hash与(length-1) 的按位与
在这里有一个小tip,即hashmap的length始终是2的n次方,也就是说length-1始终是这样的结构:n个0与m个1,因此与hash按位与后的值实际上就是取hash的后m位
与此同时在hash值匹配后,还会使用equals函数检验是否相等。

posted @ 2021-12-23 15:22  哥斯爪  阅读(49)  评论(0)    收藏  举报