在O(log n)时间内反转n位数字

上周,在撰写我以前的文章时 ,我遇到了一个有趣的逆整数算法。 例如,它需要10100011并将其转换为11000101 。 该算法的优点在于它是在O(log n)迭代中完成的。 这是代码:

反转O(log n)中的n位数字。 来自http://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel

是。 9行,包括签名和右括号。 让我们看看它是如何工作的。

下一部分将逐行研究代码。 如果您对技术无聊,可以随意跳到最后的动画

更新: O(log n)运行时间复杂度仅适用于n≤机器字大小,今天通常为64位。 感谢所有引起我注意的人。

技术:递归块交换

该算法通过递归交换相邻的位块来工作,从而在每次迭代时减小块大小。 首先交换2个n / 2位的块,然后交换4个n / 4位的块,8个n / 8位的块,依此类推,最后交换n个1位的块。 在每次迭代中,所有相邻块对都并行交换。 结果是倒数。 为了并行交换块,算法使用按 运算位掩码

注意 :原始代码使用32位输入。 我们将使用8位整数使事情更容易理解。

交换相邻的位块

并行交换块是通过特制的位掩码完成的。

对于块大小 s ,位掩码masks零和s个交替的块组成。 例如,对于s = 4mask == 00001111 。 对于s = 2mask == 00110011

该行使用掩码来并行交换所有对块:

num = ((num >> s) & mask) | ((num << s) & ~mask);
  • (num >> s) & mask)偶数块 s位置向右移动,并使用该掩码清除奇数块
  • (num << s) & ~mask奇数块 s位置向左移动,并使用掩码的按位NOT清除偶数块
  • 按位或用于将这些结果加到交换的数字中。

非常简单,不是吗?

一朵对自己异或的花。 山姆·奥特(Sam Oth)原创(用户:World Trekker)—自己的作品,CC BY-SA 2.5, https ://commons.wikimedia.org/w/index.php?curid = 863943
创建遮罩

另一个很酷的技巧是如何创建maskmask由大小为s的0和1的交替块组成。 掩码以全1的数字开头,并在循环的第一行进行更新:

while ((s >>= 1) > 0) {
mask ^= (mask << s);
...

这是在s减半后立即发生的,因此smask块大小的一半。 在第一次迭代中, mask == 11111111s == 4 。 通过将自身与另一个自身的副本进行XOR运算来对掩码进行左移s位:

mask = 
11111111 XOR // mask
11110000 // mask << s
= 00001111

如果两个位彼此不相等 ,则两个位的XOR为1。 在掩码更新的每次迭代中,所有块都向左移动其大小的一半。 当一个块与前一个掩码进行异或时,该块的一半与零重叠,另一半与一重叠。 这将在新蒙版中创建2个块,每个块的大小均为先前块的一半。 这是一个例子:

0000000011111111  // original mask, 8-bit blocks
0000111111110000 // mask shifted left by block-size/2
0000111100001111 // XORed: new mask, 4-bit blocks

绑在一起

这是一个简短的动画,展示了运行中的算法:

令人惊讶的是,在9行代码中可以找到多少深度。 如果您想让我探索一段有趣的代码,请下面留下答复

From: https://hackernoon.com/reversing-an-n-bit-number-in-o-log-n-time-9bf69363d452

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值