题目描述:如何使用位逻辑(如与,或,移位)来实现位向量
因为这里假设的是每一个数都不同,所以int的32位的每一位可以存储一个数值,
对应位为0则表示不存在该数,为1则表示存在。
假设用int数组array来记录数是否存在及其存在的个数
因为int的32位刚好每一位都可以存一个数及其个数(个数这里只能为0或1);
所以
一方面我们对数值number/32进行分组,即array[number/32]找到对应存储数值number的数组元素
也就是说0-31用array[0]记录,32-63用array[1]记录,以此类推 ;
另一方面我们对32位也进行分组,因为每个数值只需一位来存储个数,所以就简单分为32组;
可以用0-31来表示一个数值需要哪一bit组存储个数,也可以发现,此时存储数值的那一组可以用
数值number%32来找到;
此外我们将每一个int的32位也进行分组,方便保存数值的个数,由于此处每个数只有
一 先说set操作,将一个数对应的存储位置为1
不放假设我们现在有1个32, 0个33,1个34,
34 33 32 //要存储的数
2 1 0 //对应存储数值个数的bit组号,可以通过数值number%32得到
1 0 1 //具体存储数值个数的位
(注:省略了前面35-63的存储情况)
如果此时想将33的个数置为1该怎办?
那么就直接加上0 1 0 就好了,即
34 33 32 //要存储的数
2 1 0 //对应存储数值个数的bit组号,可以通过数值number%32得到
1 0 1 //具体存储数值个数的位
+0 1 0
而0 1 0=1<<1(注:这个1就是bit组号),一般地就是1<<(number%32*1)
(注:对应存储数值个数的bit组号,可以通过数值number%32得到,1表示bit组的长度(或者说是需要多少位来保存一个数值的个数))
所以set也就浮现了
void set(int number){
array[number/32]+=1<<(number%32*1);//当然对某个数只能set一次
}
二、再说clr,目的是将数值的个数清零
接着一,此时我们有1个32, 1个33,1个34;
34 33 32 //要存储的数
2 1 0 //对应存储数值个数的bit组号,可以通过数值number%32得到
1 1 1 //具体存储数值个数的位
如果此时,我们想将34的个数置零该怎办?
当然只需将对应存储数值的bit组清零即可,
当然不能影响其他bit组
具体的只需与(前面省略29个1)0 1 1 进行与运算即可;
我们会发现1太多,不方便移位,此时进行~操作即可
~((前面省略29个1)0 1 1 )=(前面省略29个0)1 0 0
此时就方便用移位操作来得到了,所以要进行与操作的即为~(1<<(2*1))
一般地~(1<<( (number%32) *1))
所以clr也就明确了
void clr(int number ){
array[number/32] = array[number/32] & (~(1<<( (number%32) *1))) ;
}
三.再说test,目的是测试某一个数值存在的个数并返回
接着二,此时我们有1个32, 1个33,0个34
34 33 32 //要存储的数
2 1 0 //对应存储数值个数的bit组号,可以通过数值number%32得到
0 1 1 //具体存储数值个数的位
如果此时测试33存在的个数该怎么办?
方法一,将33将33的对应bit组移到最右边,然后将它前面的bit组清零
方法二,将33前面的bit组清零,然后将33的对应bit组移到最右边;
两者差不多
按照方法一来的话,要先将array[0]>>(1*1) (注前一为bit组组号,后一为为组长)
然后得到(前面省略29个数的对应bit位情况)0 1,因为目标就是得到(29个0) 0 1
所以再和1进行与操作就行了,然后一般化就得到test了
int test(int number) {
return (array[number/32]>>( (number%32)*1)&1
//另一种return ( ( 1<<(number%32)*1) )&array[number/32] )>>( (number%32)*1 )
}
再贴一下源码,其实第一章第六题和这题差不多,升级版应该叫
点此跳到编程珠玑第一章第六题
#include<iostream>
using namespace std;
#define HMVTS 32 //一个int要存数值的个数 ,how many values to save in each int
#define HMBTSN 1 //每个数值需要多少位来保存数值的个数,how many bits to save the number of the specific value
#define MASK 0X01//1111方便得到最后结果
unsigned int array[30];
void set (int number){
array[number/HMVTS] += (1<<((number%HMVTS)*HMBTSN));
}
void clr (int number){
array[number/HMVTS]=array[number/HMVTS]&(~(MASK<<HMBTSN*(number%HMVTS)));
}
int test(int number){
return array[number/HMVTS]>>(HMBTSN*(number%HMVTS))&(MASK);
}
int main(){
int index;
cout<<"未排序的数组为:\n";
unsigned int testArr[20]={ 11,44,56,45,78,
49,60,71,90,117,
148,22,33,47,91,
199,3,4,5,70};
for(index=0;index<20;index++){
set(testArr[index]);
cout<<testArr[index]<<" ";
}
cout<<endl;
cout<<"排序结果为:\n";
for(int i=0;i<200;i++){
if(test(i)>0){
for(int j=test(i);j>0;j--){
cout<<i<<" " ;
}
}}
cout<<endl;
clr(56);
cout<<"清除56后的排序结果为:\n ";
for(int i=0;i<200;i++){
if(test(i)>0){
for(int j=test(i);j>0;j--){
cout<<i<<" " ;
}
}}
cout<<endl;
}
![运行结果](http://img.blog.csdn.net/20160814121134800)