编程珠玑第一章第二题

题目描述:如何使用位逻辑(如与,或,移位)来实现位向量

因为这里假设的是每一个数都不同,所以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)   

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值