散列表学习

散列函数 一个把查找表中的关键字映射成该关键字对应的地址的函数,记作Hash(key)=Addr(这里的地址可能为数组下标、索引、或者内存地址)
冲突 散列表可能把两个或者两个以上的不一样关键字映射到同一地址,这种状况成为冲突
散列表 根据关键字直接进行访问的数据结构(散列表创建了关键字与存储地址之间的映射关系)html

散列表构造方法

1>散列表定义域需包含所有须要存储的关键字
2>散列函数计算的地址应该等几率、均匀的分布整个地址空间
3>散列函数应尽可能简单,在较短期内计算出任意关键字对应的散列地址java

常见的几种散列函数:
1 直接地址法
直接取关键字的某个线性函数值为散列地址,散列函数为:
H(key) = a*key+b
这种计算方法简单,而且不会产生冲突,适合关键字的分布基本连续,若关键字不连续,容易形成较多空位,形成存储空间的浪费。算法

2除留余数法
假设散列表表长为m,取一个不大于m但接近或等于m的质数p,利用一下公式
H(key)=key%p
除留余数法要选好p,使得每一个关键字经过该函数转换后等几率映射到散列空间的任意地址。数组

3数字分析法
4平方取中法
5折叠法数据结构

下面谈下java中的hashcode()函数

总结几个关键点:this

一、HashCode的存在主要是为了查找的快捷性,HashCode是用来在散列存储结构中肯定对象的存储地址的code

二、若是两个对象equals相等,那么这两个对象的HashCode必定也相同htm

三、若是对象的equals方法被重写,那么对象的HashCode方法也尽可能重写对象

四、若是两个对象的HashCode相同,不表明两个对象就相同,只能说明这两个对象在散列存储结构中,存放于同一个位置

例子:
1 假设内存中有8个位置,一、二、三、四、五、六、七、8,将数据A 存入8个位置中,若是随机存放,查找就从头遍历,
2 若是使用HashCode则效率会快不少,把A的HashCode%8,而后把ID存放在取得余数的那个位置
3 若是A的 HashCode%8算出来的位置上自己已经有数据了。这就取决于算法的实现了,好比ThreadLocal中的作法就是从算出来的位置向后查找第一个为空的位置,放置数据;HashMap的作法就是经过链式结构连起来。反正,只要保证放的时候和取的时候的算法一致就好了。
四、若是ID的 HashCode%8相等怎么办(这种对应的是第三点说的链式结构的场景)?这时候就须要定义equals了。先经过HashCode%8来判断类在哪一 个位置,再经过equals来在这个位置上寻找须要的类。对比两个类的时候也差很少,先经过HashCode比较,假如HashCode相等再判断 equals。若是两个类的HashCode都不相同,那么这两个类一定是不一样的。

还有一个是set的例子
咱们都知道List 存放的元素是有序能够重复的,而Set存放的是无序且不重复的
可是Set怎样实现不重复呢,若是Set中数据不少,则调用equals方法效率很低,可是HashSet底层基于HashCode,咱们向集合中添加一个元素,
首先调用Hashcode方法,定位到一个位置,若是该位置为空,则直接插入。反之注意比较,先比较Hashcode是否相同,相同的话不存。Hashcode不一样则经过equals方法比较
若是不一样则插入该元素。

再谈重写Object的equals(Object obj)方法为何尽可能要重写Object的hashCode()方法

首先

public class HashCodeClass
{
    private String str0;
    private double dou0;
    private int       int0;
    
    public boolean equals(Object obj)
    {
        if (obj instanceof HashCodeClass)
        {
            HashCodeClass hcc = (HashCodeClass)obj;
            if (hcc.str0.equals(this.str0) && 
                hcc.dou0 == this.dou0 &&
                hcc.int0 == this.int0)
            {
                return true;
            }
            return false;
        }
        return false;
    }
}

打印出复写equals方法后的该类的hashcode

public class TestMain
{
    public static void main(String[] args)
    {
        System.out.println(new HashCodeClass().hashCode());
        System.out.println(new HashCodeClass().hashCode());
        System.out.println(new HashCodeClass().hashCode());
        System.out.println(new HashCodeClass().hashCode());
        System.out.println(new HashCodeClass().hashCode());
        System.out.println(new HashCodeClass().hashCode());
    }
}

值为

1901116749
1807500377
355165777
1414159026
1569228633
778966024

如上述代码没有复写hashCode值,那么将几个类存入Set中因为hashCode不相同,则set中存入多个HashCodeClass,这样不合理,因此要复写Hashcode()

Integer 复写Hashcode()

public int hashCode() {
    return value;
    }

public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
    }

String复写Hashcode()

public int hashCode() {
    int h = hash;
    if (h == 0) {
        int off = offset;
        char val[] = value;
        int len = count;

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

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = count;
        if (n == anotherString.count) {
        char v1[] = value;
        char v2[] = anotherString.value;
        int i = offset;
        int j = anotherString.offset;
        while (n-- != 0) {
            if (v1[i++] != v2[j++])
            return false;
        }
        return true;
        }
    }
    return false;
    }

entity 复写Hashode()

public final int hashCode() {
            return (key==null   ? 0 : key.hashCode()) ^
                   (value==null ? 0 : value.hashCode());
        }

public final boolean equals(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry e = (Map.Entry)o;
            Object k1 = getKey();
            Object k2 = e.getKey();
            if (k1 == k2 || (k1 != null && k1.equals(k2))) {
                Object v1 = getValue();
                Object v2 = e.getValue();
                if (v1 == v2 || (v1 != null && v1.equals(v2)))
                    return true;
            }
            return false;
        }

参考连接为http://www.javashuo.com/article/p-rpxsvsde-eh.html

相关文章
相关标签/搜索