位串表示子集

/*
寻找与一个给定的数目有相同数目的1位的下一个大数的问题
它在使用位串来表示子集是有用。把一个集合的所有可能元素列成一个线性序列,
使用字或字的序列来表示子集,当集合的成员i属于该子集时设置字或字序列的第i位为1

R. W. Gosper [HAK, item 175]
 
  按32位无符号数算 33 = 32 + 1

  s = x & -x
  r = s + x
  y = r | ((x^r) >> 2)/s)

  或

  y = r | ((x^r) >> (2+ntz(x)))
  y = r | ((x^r) >> (33-nlz(s)))
  y = r | ((1 << (pop(x^r)-2))-1)
*/

 


#include "iostream"
#include "bitset"
#include "limits"

using namespace std;

 

 

#define out2(T) cout<<bitset<numeric_limits<unsigned short>::digits>(T)<<endl
#define SIZE(T) (numeric_limits<unsigned T>::digits)

 

 

unsigned short snoob(unsigned short x)
{
 unsigned short smallest, ripple, ones;
                                                      // XXX 表示任意
                                                 // x = XXX0 1111 0000
 smallest = x & -x;                          // 0000 0001 0000
 ripple = x + smallest;                    // XXX1 0000 0000
 ones = x ^ ripple;                         // 0001 1111 0000
 ones = (ones >> 2)/smallest;       // 0000 0000 0111
 return ripple | ones;                      // XXX1 0000 0111
}

 

 

unsigned short snoob1(unsigned short x)
{ unsigned short ntz(unsigned short x);
 unsigned short smallest, ripple, ones;
                                                 // XXX 表示任意
                                                   // x = XXX0 1111 0000
 smallest = x & -x;                            // 0000 0001 0000
 ripple = x + smallest;                      // XXX1 0000 0000
 ones = x ^ ripple;                           // 0001 1111 0000
 return ripple | (ones >> (2 + ntz(x)));
}

 

 

unsigned short snoob2(unsigned short x)
{ unsigned short nlz(unsigned short x);
 unsigned short smallest, ripple, ones;
 int t = SIZE(short)+1;
                                               // XXX 表示任意
                                                // x = XXX0 1111 0000
 smallest = x & -x;                          // 0000 0001 0000
 ripple = x + smallest;                    // XXX1 0000 0000
 ones = x ^ ripple;                         // 0001 1111 0000
 return ripple | (ones >> (t-nlz(smallest)));
}

 

 

unsigned short snoob3(unsigned short x)
{ unsigned short pop(unsigned short x);
 unsigned short smallest, ripple, ones;
                                              // XXX 表示任意
                                                 // x = XXX0 1111 0000
 smallest = x & -x;                           // 0000 0001 0000
 ripple = x + smallest;                     // XXX1 0000 0000
 ones = x ^ ripple;                          // 0001 1111 0000
 return ripple | ( (1<<(pop(ones)-2)) - 1 );
}

 

 

unsigned short ntz(unsigned short x) //计算后缀0数目
{
 int s = SIZE(short);
 int i = 0; while ( !(x&(unsigned short)(1)) && i < s) { x>>=1; i++; }
 return i;
}

 


unsigned short nlz(unsigned short x) //计算前导0数目
{
 int s = SIZE(short);
 int L = (unsigned short)(1) << (s-1);
 int i = 0; while ( !(x&L) && i < s) {x<<=1; i++;}
 return i;
}

 

 

unsigned short pop(unsigned short x) //种群计数函数
{
 int s = SIZE(short);
 int i = 0; while(s--) { (x&(unsigned short)(1)) ? ++i : 0; x>>=1; }
 return i;
}

 

 

void main()
{
 out2( snoob(0xF0) );
 out2( snoob1(0xF0) );
 out2( snoob2(0xF0) );
 out2( snoob3(0xF0) );

 cout << ntz(0x17A0) <<endl;
 cout << nlz(0x17F0) <<endl;
 cout << pop(0x359D) <<endl;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值