散列表

来源:互联网 发布:手机挡字幕软件 编辑:程序博客网 时间:2024/03/28 23:39

结合Java.util.HashMap中的代码,终于真正理解了散列表。

直接寻址:
一个题目是有n个数,且里面的数大于0且小于100,n也是大于0且小于100。用复杂度为n的算法计算出每个数出现的次数。
C++代码如下

int a[] = new int[100+5];Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();for(int i = 0; i < n; ++i){    int x = scanner.nextInt();    a[x]++;}

现在数组A中a[i]的值就是i出现的此时。
其实上面的代码就是直接寻址法。

散列表:
改动一下题目:
一个题目是有n(n大于0且小于10000)个数,且里面的数大于0且小于2的31次方-1。用复杂度最高为1000的算法来查看输入的数字中是否有x。(x大于0且小于2的31次方-1)
如果你还是用直接寻址就需要new int[2147483647]的内存空间,虚拟机是不会给你分配这么多内存的。

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space    at com.sdkd.hms.UserCaseTracker.main(UserCaseTracker.java:27)

即使不报错,也太浪费内存了,毕竟你只有10000个数。

1、这个时候就需要散列表,因为散列表使用一个长度与实际存储的关键字数目成比例的数组来存储。
2、在散列表中,不是直接把关键字作为数组的下标,而是根据关键字计算出相应的下标。这里因此而产生了一个问题,就是多个关键字映射到相同的下标,有“链接”方法、”开放寻址“、”完全散列“等方法来解决这个问题。
3、同时,当关键字是静态存储(即关键字集合一旦存入后就不再改变)时,完全散列能够在最坏O(1)的时间内完成关键字查找。

这里我用散列表实现上面这个题的解。

int n;//n是指要往散列表存储多少个数int m;//m是指散列表的大小double loaddfactor;//loadfactor = n*1.0/m;

有下列几步
1、确定要往散列表中存储多少数。这个题目中给出了,n = 100;
2、确定自己的loadfactor,这里为了体现出我用链接法来解决冲突(多个关键字映射同一个下标)问题,使loadfactor = 10000;
3、m = n/loadfactor;
4、散列函数
散列函数应当使关键字映射后映射成相同下标的可能性尽量小。(像Java中的HashCode()就是散列函数)。
散列函数也有多种,这里粗略列举三种:除法散列法、乘法散列法、全域散列法。这里我选择除法散列法:

h(k) = k % 83641;我下面的散列表是hashable[83641][1000+5]而不是hashable[83641][10000+5]。这里最坏的情况是10000个数全都映射到一个下表,那这个哈希表最多只能满足1000个数。但是我觉的好的散列函数可以避免这种问题。java.util.HashMapz中的HashMap中的HashCode()方法是native的,也就是用C++实现,在外部以.dll文件存在。并且还有hash(int k)再次运算后得出的。(也有可能是我理解的有问题,欢迎指教)

补充一下

----static int hash(int h) {        // This function ensures that hashCodes that differ only by        // constant multiples at each bit position have a bounded        // number of collisions (approximately 8 at default load factor).        h ^= (h >>> 20) ^ (h >>> 12);        return h ^ (h >>> 7) ^ (h >>> 4);    }这是JavaHashMap中的hash函数。请看它的注释----确保使哈希码最多的冲突上限是8.也就是不管有多少个相同的关键字,经过HashCode()得出哈希码再经过Hash()这个函数后,最多有8个数相同。

下面是我写的一个简单的上面这个题的解。散列函数太low了,粗鄙不堪~大家看看意思就行了

package com.sdkd.hms;import java.util.Scanner;public class Test {    public static int hashtable[][] = new int[83641][1000+5];    public static int input[] = new int[100+5];    public static int n;    public static boolean checkOut(int x){        int hk = x%83641;        for(int j = 0; j < 1000 + 5; ++j){            if(hashtable[hk][j] == x){                return true;            }        }        return false;    }    public static void main(String[] args) {        int input[] = new int[100+5];        Scanner scanner = new Scanner(System.in);        int n;        n = scanner.nextInt();        for(int i = 0; i < n; ++i){            input[i] = scanner.nextInt();            int hk = input[i]%83641;            for(int j = 0; j < 1000+5; ++j){                if(hashtable[hk][j] ==0){ hashtable[hk][j] = input[i]; break; }            }        }        while(true){            int x = scanner.nextInt();            if(x == -1) return ;            if(checkOut(x)){                System.out.println(x + "已经被存储了");            }else{                System.out.println(x + "还没有被存储");            }        }    }}

可以去这篇文章—-HashMap–基于散列表的实现

0 0
原创粉丝点击