Redis二进制反转算法分析

Posted evenleo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis二进制反转算法分析相关的知识,希望对你有一定的参考价值。

在 redis 源码中 dictScan 算法中用到了用到了非常经典的二进制反转算法,该算法对二进制的反转高效而实用,同时对于理解位运算也有非常大的帮助。先呈现源码:

/* Function to reverse bits. Algorithm from:
 * http://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel */
static unsigned long rev(unsigned long v) {
    unsigned long s = 8 * sizeof(v); // bit size; must be power of 2, 此处为32
    unsigned long mask = ~0;  //11111111111111111111111111111111
    while ((s >>= 1) > 0) {  //循环5次
        mask ^= (mask << s); // 取得想要局部对换的掩码
        // 左移s位并保留低位,右移s位并保留高位,然后两部分或运算
        // 这里是实现移位的精华所在,结合下面打印信息有助于理解
        v = ((v >> s) & mask) | ((v << s) & ~mask);
    }
    return v;
}

源码的总体思路是:用迭代的思想将32位的二进制数先将前16位和后16位对换,然后将前16位二进制数的前8位和后8位对换,后16位类似,再讲前8位的二进制数的前4位和后4位对换。。。最终实现整个二进制的反转。当然这里的实现过程非常巧妙,这也是位运算神秘而神奇的特点,理解这个过程,对于理解计算机的原理都有很大的帮助。

但上面的描述得还是比较抽象,还不足以帮助理解上面的算法实现,下面来对算法的实现过程加一些打印,以便更好的理解算法的实现原理。

#include <iostream>

using namespace std;

// 打印二进制
void printBits(const unsigned long v) {
    unsigned long mask = 1 << 31;
    while ((mask) > 0) {
        int bit = (v & mask) ? 1 : 0;
        cout << bit;
        mask >>= 1;
    }
    cout << endl;
}

static unsigned long rev_test(unsigned long v) {
    unsigned long s = 8 * sizeof(v); // bit size; must be power of 2
    unsigned long mask = ~0;
    cout << "s      : ";
    printBits(s);
    cout << "mask   : ";
    printBits(mask);

    while ((s >>= 1) > 0) {
        cout << endl;
        cout << "s      : ";
        printBits(s);
        cout << "mask   : ";
        printBits(mask);
        cout << "mask<<s: ";
        printBits(mask << s);
        mask ^= (mask << s);
        cout << "mask^= : ";
        printBits(mask);
        v = ((v >> s) & mask) | ((v << s) & ~mask);
        cout << "v      : ";
        printBits(v);
    }

    return v;
}

int main() {
    unsigned long v = 8;
    cout << "v      : ";
    printBits(v);
    cout << endl;
    v = rev_test(v);
    cout << endl;
    cout << "v      : ";
    printBits(v);

    cout << endl << endl << endl;

    system("pause");
    return 0;
}

 运行上述程序结果如下:

 

 

以上是关于Redis二进制反转算法分析的主要内容,如果未能解决你的问题,请参考以下文章

使用 C++ 反转句子中的每个单词需要对我的代码片段进行代码优化

如何在 BackStack 上反转片段动画?

整数反转-算法详细分析

算法LeetCode 反转链表(递归)关键步骤理解

算法练习2之单链表求和

2021-09-11:给你一个32位的有符号整数x,返回将x中的数字部分反转后的结果。反转后整数超过 32 位的有符号整数的范围就返回0,假设环境不允许存储 64 位整数(有符号或无符号)。(代码片段