二分查找位运算——32位整数中寻找第一个为1的位

问题描述


在程序设计中经常会遇到这样一个问题,即在一个32位整数中,从右到左寻找第一个为1的位。这样的问题是很常见的,而面对这样一个问题,一种常见的解法就是逐位的遍历这个整数中的所有位,直到遇到了为1的位。若第一个为1的位出现在高位区域,逐位查找比较的方法会比较浪费 时间。


换一种思路


当我们在一个数组中寻找某数的时候,我们有什么办法?简单的顺序的遍历整个数组的思想是可行的,这样的时间复杂度是o(n)。若数组是一个有序的数组呢?我们一般会采用2分查找的方式在一个数组中寻找某数,这样找起来就比较快了,时间复杂度是o(logn)。那在一个32位的int中寻找第一个为1的数,能否使用2分查找法呢?

在查找第一个为1的位时是可以使用2分查找法的,那么要如何使用2分法呢?关于位相关的操作一定不要忘了位运算,有效的运用位运算是可以实现对该问题的2分查找法。

究竟如何进行2分查找呢? 

判断某一位是否为1时可以使用&操作,那么要判断32位中的16位是否有1时要如何做到呢?用data & 0xFFFF即可。要判断8位是否有1时可以data & 0xFF,判断4位是否有1可以data & 0xF,那么判断2位是否有1就可以用data & 0x3了。

分析到这里,就已经有思路了,通过data与 0xFFFF,0xFF,0xF以及 0x3等做&操作即可。
从左到右

int binarysearch(int data)
{
	int pos=0;
	if ((data & 0xFFFF0000) == 0)
		pos += 16;
	else
		data >>= 16;
	
	if ((data & 0xFF00) == 0)
		pos += 8;
	else
		data >>= 8;
	
	if ((data & 0xF0) == 0)
		pos += 4;
	else
		data >>= 4; 

	if ((data & 0xC) == 0)		// 0b1100
		pos += 2;
	else
		data >>= 2; 

	if ((data & 0x2) == 0)		// 0b10
		pos += 1;

	return pos;
}


从右到左

int binarysearch(int data)
{
        int pos=0;
        if ((data & 0x0000FFFF) == 0){
                data >>= 16;
                pos += 16;
        }

        if ((data & 0x00FF) == 0){
                data >>= 8;
                pos += 8;
        }

        if ((data & 0x0F) == 0){
                data >>= 4;
                pos += 4;
        }

        if ((data & 0x3) == 0){         // 0b1100
                data >>= 2;
                pos += 2;
        }

        if ((data & 0x1) == 0)          // 0b10
                pos += 1;

        return pos;
}


小结

位运算在C语言中是非常重要的,很多有技巧性的优化都是通过位运算来实现,需要熟练掌握才行。

当然针对特定的处理器还可以做些指令级的优化,比如在x86上记得有一条指令就可以完成这个功能了。

(从网友博客转帖过来,原来代码有误这里做了些修改)



评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值