Author:Once day Date:2022年7月31日
漫漫长路刚刚开始,不要甘于平凡。
本算法基于C语言环境。
可以只依靠基本的位级运算来提取位级表示的最高位。
如值0xFF00,返回0x8000,值0x6600,返回0x4000。
简单的处理是从最高位向右依次判断,不过存在一种无需判断,且复杂度为对数级别的方法。
假设一共32位,即0x00707000,看成32位的向量 b 31 b n 30 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ b 1 b 0 b_{31}bn_{30}······b_1b_0 b31bn30⋅⋅⋅⋅⋅⋅b1b0。
那么可以将其分成两部分,利用折半查找的思想,即 u 1 = b 31 b 30 ⋅ ⋅ ⋅ b 17 b 16 u_1=b_{31}b_{30}···b_{17}b_{16} u1=b31b30⋅⋅⋅b17b16和 u 2 = b 15 b 14 ⋅ ⋅ ⋅ b 1 b 0 u_2=b_{15}b_{14}···b_{1}b_{0} u2=b15b14⋅⋅⋅b1b0。
直接进行与运算,判断u1和u2里是否含有1:
unsigned x=0x00707000;
x=(x&0xffff0000)||(x&0x0000ffff);
根据与运算符的规则,如果最高位1在
u
1
u_1
u1, 那么x的值为x&0xffff0000
,所有
u
2
u_2
u2部分值都会被抹去。反之,x的值为x&0x0000ffff
,所有
u
1
u_1
u1部分值都会被抹去。
因此其值变为0x00700000。此时再折半判断:
这两种情况实际上使互斥的,即 u 11 u_{11} u11和 u 12 u_{12} u12会同时有可能,但 u 11 u_{11} u11和 u 21 u_{21} u21不可能同时发生。
因此合并成两种判断情况:
x&(0xff00ff00)
。x&(0x00ff00ff)
。以此类推,则可表示为:
unsigned x=0x00707000;
x=(x&0xffff0000)||(x&0x0000ffff);
x=(x&0xff00ff00)||(x&0x00ff00ff);
x=(x&0xf0f0f0f0)||(x&0x0f0f0f0f);
x=(x&0xbbbbbbbb)||(x&0x33333333);
x=(x&0xaaaaaaaa)||(x&0x55555555);
其复杂度为 l o g 2 w log_2w log2w,w为位级表示的位数。
完…