(2)面试 --- 在元素的装载数量明确的时候HashMap的大小应该如何选择 || 二维数组打印对角线
2015-05-05 09:10
597 查看
今天看到美团招聘给出了一道小题目,关于HashMap的性能问题。问题如下:
java hashmap,如果确定只装载100个元素,new HashMap(?)多少是最佳的,why?
要回答这个问题,首先得知道影响HashMap性能的参数有哪些。咱们翻翻JDK。
在JDK6中是这么描述的:
HashMap的实例有两个参数影响其性能:初始容量和加载因子。
首先我们来看初始容量和加载因子的定义。
容量是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。
加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。
当哈希表中条目的数目超过 容量乘加载因子 的时候,则要对该哈希表进行rehash操作,从而哈希表将具有大约两倍的桶数。(以上摘自JDK6)
HashMap默认的加载因子是0.75 .它在时间和空间成本上寻求了一种折中。
回到本文的问题。根据JDK中的描述,如果这个只装载100个元素的HashMap没有特殊的用途,那么为了在时间和空间上达到最佳性能,
HashMap的初始容量可以设为 100/0.75 = 133.33。为了防止rehash,向上取整,为134。
但是还有另外一个问题,就是hash碰撞的问题。如果我们将HashMap的容量设置为134,那么如何保证其中的哈希碰撞会比较少呢?
除非重写hashcode()方法,否则,似乎没有办法保证。
那么这里不得不提HashMap如何为元素选择下标的方法了。
其中h为key哈希后得到的值,length为哈希表的长度。
134-1 = 128 + 6 -1;
那么 length-1的二进制值的最后3位为101;
假设这100个装载的元素中他们的key在哈希后有得到两个值(h),他们的二进制值除了低3位之外都相同,而第一个值的低3位为011,第二个值的低3位为001;
这时候进行java的&预算,011 & 101 = 001 ;001 & 101 = 001;
他们的值相等了,那么这个时候就会发生哈希碰撞。
除此之外还有一个更加严重的问题,由于在101中第二位是0,那么,无论我们的key在哈希运算之后得到的值h是什么,那么在&运算之后,得到的结果的倒数第二位均为0;
因此,对于hash表所有下标的二进制的值而言,只要低位第二位的值为1,(例如0010,0011,0111,1111)那么这个下标所代表的桶将一直是空的,因为代码中的&运算的结果永远不会产生低位第二位为1的值。这就大大地浪费了空间,同时还增加了哈希碰撞的概率。这无疑会降低HashMap的效率。
那么如何才能减少这种浪费呢?最佳的方法当然是让length-1的二进制值全部位均为1.那么length的值是多少合适呢?
没错,length=2^n。
只要将hash表的长度设为2的N次方,那么,所有的哈希桶均有被使用的可能。
再次回到美团提出的问题,与134最靠近的2^n无疑是128。
如果只修改HashMap的长度而不修改HashMap的加载因子的话,HashMap会进行rehash操作,这是一个代价很大的操作,所以不可取。
那么应该选择的就应该是256。
而由于空间加大和有效利用哈希桶,这时的哈希碰撞将大大降低,因此HashMap的读取效率会比较高。
所以,最后结论就是:HashMap的大小应该设置为256。
结果的补充:其实在Java中,无论你的HashMap(x)中的x设置为多少,HashMap的大小都是2^n。2^n是大于x的第一个数。因为HashMap的初始化代码中有以下这行代码:
但是这就带来了一个问题,如果x=100,那么HashMap的初始大小应该是128.但是100/128=0.78,已经超过默认加载因子的大小了。因此会resize一次,变成256。所以最好的结果还是256。
最后发个参考链接:http://www.iteye.com/topic/539465
原文地址:点击打开链接 http://www.cnblogs.com/coderxuyang/p/3718856.html
===================================================================================================================
1,二维数组(N*N),沿对角线方向,从右上角打印到左下角如N=4: 4*4二维数组
{ 1 2 3 4 }
{ 5 6 7 8 }
{ 9 10 11 12 }
{13 14 15 16 }
转载地址:点击打开链接 http://blog.csdn.net/liuwei063608/article/details/27342123
java hashmap,如果确定只装载100个元素,new HashMap(?)多少是最佳的,why?
要回答这个问题,首先得知道影响HashMap性能的参数有哪些。咱们翻翻JDK。
在JDK6中是这么描述的:
HashMap的实例有两个参数影响其性能:初始容量和加载因子。
首先我们来看初始容量和加载因子的定义。
容量是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。
加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。
当哈希表中条目的数目超过 容量乘加载因子 的时候,则要对该哈希表进行rehash操作,从而哈希表将具有大约两倍的桶数。(以上摘自JDK6)
HashMap默认的加载因子是0.75 .它在时间和空间成本上寻求了一种折中。
回到本文的问题。根据JDK中的描述,如果这个只装载100个元素的HashMap没有特殊的用途,那么为了在时间和空间上达到最佳性能,
HashMap的初始容量可以设为 100/0.75 = 133.33。为了防止rehash,向上取整,为134。
但是还有另外一个问题,就是hash碰撞的问题。如果我们将HashMap的容量设置为134,那么如何保证其中的哈希碰撞会比较少呢?
除非重写hashcode()方法,否则,似乎没有办法保证。
那么这里不得不提HashMap如何为元素选择下标的方法了。
static int indexFor(int h, int length) { return h & (length-1); }
其中h为key哈希后得到的值,length为哈希表的长度。
134-1 = 128 + 6 -1;
那么 length-1的二进制值的最后3位为101;
假设这100个装载的元素中他们的key在哈希后有得到两个值(h),他们的二进制值除了低3位之外都相同,而第一个值的低3位为011,第二个值的低3位为001;
这时候进行java的&预算,011 & 101 = 001 ;001 & 101 = 001;
他们的值相等了,那么这个时候就会发生哈希碰撞。
除此之外还有一个更加严重的问题,由于在101中第二位是0,那么,无论我们的key在哈希运算之后得到的值h是什么,那么在&运算之后,得到的结果的倒数第二位均为0;
因此,对于hash表所有下标的二进制的值而言,只要低位第二位的值为1,(例如0010,0011,0111,1111)那么这个下标所代表的桶将一直是空的,因为代码中的&运算的结果永远不会产生低位第二位为1的值。这就大大地浪费了空间,同时还增加了哈希碰撞的概率。这无疑会降低HashMap的效率。
那么如何才能减少这种浪费呢?最佳的方法当然是让length-1的二进制值全部位均为1.那么length的值是多少合适呢?
没错,length=2^n。
只要将hash表的长度设为2的N次方,那么,所有的哈希桶均有被使用的可能。
再次回到美团提出的问题,与134最靠近的2^n无疑是128。
如果只修改HashMap的长度而不修改HashMap的加载因子的话,HashMap会进行rehash操作,这是一个代价很大的操作,所以不可取。
那么应该选择的就应该是256。
而由于空间加大和有效利用哈希桶,这时的哈希碰撞将大大降低,因此HashMap的读取效率会比较高。
所以,最后结论就是:HashMap的大小应该设置为256。
结果的补充:其实在Java中,无论你的HashMap(x)中的x设置为多少,HashMap的大小都是2^n。2^n是大于x的第一个数。因为HashMap的初始化代码中有以下这行代码:
int capacity = 1; while (capacity < initialCapacity) capacity <<= 1;
但是这就带来了一个问题,如果x=100,那么HashMap的初始大小应该是128.但是100/128=0.78,已经超过默认加载因子的大小了。因此会resize一次,变成256。所以最好的结果还是256。
最后发个参考链接:http://www.iteye.com/topic/539465
原文地址:点击打开链接 http://www.cnblogs.com/coderxuyang/p/3718856.html
===================================================================================================================
1,二维数组(N*N),沿对角线方向,从右上角打印到左下角如N=4: 4*4二维数组
{ 1 2 3 4 }
{ 5 6 7 8 }
{ 9 10 11 12 }
{13 14 15 16 }
4 3 8 2 7 12 1 6 11 16 5 10 15 9 14 13主要是要找到数组下标的规律,先考虑一共生成几组结果,然后找到每组结果的规律//规律是第 K的 列号-行号=size-1-k
{ 1 2 3 4 } { 5 6 7 8 } { 9 10 11 12 } {13 14 15 16 } 2*4-1 行 列 列 -行 = len长度-第几行 4 1 03 3-0 = 4 - 1 3 8 2 02 13 2 = 4 - 2 2 7 12 3 01 12 23 1 = 4 - 3 1 6 11 16 4 00 11 22 33 0 = 4 - 4 5 10 15 5 10 21 32 -1 = 4 - 5 9 14 6 20 31 -2 = 4 - 6 13 7 30 -3 = 4 - 7
/** * Description:二维数组(N*N),沿对角线方向,从右上角打印到左下角 * @author liuwei DateTime 2014-5-27 下午4:13:56 * @param args */ public static void main(String[] args) {
int[][] a = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}, {13,14,15,16}}; // int[][] a = {{1,2,3}, // {4,5,6}, // {7,8,9}}; int size = a.length; int len = 2*a.length-1;//一共生成几行结果 for(int k=0;k<len;k++){ //规律是第 K的 列号-行号=size-1-k for(int i=0;i<size;i++){ for(int j=0;j<size;j++){ if(j-i == size-1-k){ System.out.print(a[i][j]+" "); } } } System.out.println(""); } }
转载地址:点击打开链接 http://blog.csdn.net/liuwei063608/article/details/27342123
相关文章推荐
- 在元素的装载数量明确的时候HashMap的大小应该如何选择。
- 作业: 选择某种Map集合保存学号从1到15的学员的学号(键)和姓名(值),学号用字符串表示,输入的时候要以学号乱序的方式存入Map集合,然后按照学号从大到小的顺序将Map集合中的元素输出打印。需要自
- 选择某种Map集合保存学号从1到15的学员的学号(键)和姓名(值),学号用字符串表示,输入的时候要以学号乱序的方式存入Map集合,然后按照学号从大到小的顺序将Map集合中的元素输出打印。需要自定义Ma
- 移动web——做适配的时候如何设置界面里面元素的大小
- 选择某种Map集合保存学号从1到15的学员的学号(键)和姓名(值),学号用字符串表示,输入的时候要以学号乱序的方式存入Map集合,然后按照学号从大到小的顺序将Map集合中的元素输出打印。需要自定义Ma
- 选择某种Map集合保存学号从1到15的学员的学号(键)和姓名(值),学号用字符串表示,输入的时候要以学号乱序的方式存入Map集合,然后按照学号从大到小的顺序将Map集合中的元素输出打印。需要自定义Ma
- 选择某种Map集合保存学号从1到15的学员的学号(键)和姓名(值),学号用字符串表示,输入的时候要以学号乱序的方式存入Map集合,然后按照学号从大到小的顺序将Map集合中的元素输出打印。需要自定义Ma
- 选择某种Map集合保存学号从1到15的学员的学号(键)和姓名(值),学号用字符串表示,输入的时候要以学号乱序的方式存入Map集合,然后按照学号从大到小的顺序将Map集合中的元素输出打印。需要自定义Ma
- 下面的代码告诉你返回的时候应该如何选择(返回的是数组还是对象)
- 程序员面试题目总结--数组(一)【递归求数组所有元素和、用一个for循环打印出一个二维数组、用递归判断数组是否是递增、有序数组中删除重复元素】
- 程序员应该如何打印log日志
- 面试时应该如何应答?
- js如何去除打印时候浏览器自带的页头页尾的信息
- 所谓"在表达式中,数组名总是被转换为指向该数组第一个元素的指针"应该如何理解?
- 数组作为hash元素的时候如何push
- 【 D3.js 入门系列 --- 2 】 如何使用数据和选择元素
- js 打印时如何 选择默认打印机
- JAVA中HashMap如何删除元素
- 如何用一层for循环打印出一个二维数组
- 高级候选人应该如何进行猎头公司的面试