一段神奇的算法
阅读hashmap源码时,看到了一段神奇的代码,如下所示:
static final int tableSizeFor(int cap) {
int n = cap - 1; // step 1
n |= n >>> 1; // step 2
n |= n >>> 2; // step 3
n |= n >>> 4; // step 4
n |= n >>> 8; // step 5
n |= n >>> 16; // step 6
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; // step 7
}
这段代码啥意思呢?这段代码是初始化容量时会调用的,用于计算扩容阈值。
这段代码的目的是为了计算大于等于cap的最小2的幂,如cap=2,输出2;cap=3,输出4;cap=17,输出32。
科普:
n >>> 1:是无符号右位移运算,向右位移1位,左边补0;
n |= n:位或运算,0 | 0 = 0;0 | 1 = 1;1 | 1 = 1;1 | 0 = 1。即只要有1则为1。
以下以cap=121为例:
step 1:n = 120
step 2:
120的二进制形式为:0111 1000
n >>> 1:0011 1100
n |= n:
0111 1000
0011 1100
——————————————————
0111 1100
输出:n = 124
step 3:
124的二进制形式为:0111 1100
n >>> 2:0001 1111
n |= n:
0111 1100
0001 1111
——————————————————
0111 1111
输出:n = 127
step 4:
124的二进制形式为:0111 1111
n >>> 4:0000 0111
n |= n:
0111 1111
0000 0111
——————————————————
0111 1111
输出:n = 127
step 5:
124的二进制形式为:0111 1111
n >>> 8:0000 0000
n |= n:
0111 1111
0000 0000
——————————————————
0111 1111
输出:n = 127
step 6:
124的二进制形式为:0111 1111
n >>> 16:0000 0000
n |= n:
0111 1111
0000 0000
——————————————————
0111 1111
输出:n = 127
step 7:127 > && 127 < MAXIMUM_CAPACITY,输出最终结果:128
此算法巧妙的地方在于,cap的最高位肯定是1,第一次向右位移1位后,再与原值进行位或操作,结果是最高的两位是1。接着向右位移2位再位或,得到最高的四位是1。同理,将得到一连串的1,即为结果。
至于step 1为何要先减去1,目的在于保证结果是大于等于cap的最小2的n次幂。如cap为8,预期的输出也应该为8。若不先减去1,则将输出16,与预期不符。
网友评论