一段神奇的算法

一段神奇的算法

阅读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,与预期不符。

你可能感兴趣的:(一段神奇的算法)