统计十进制数的二进制表示中1的个数 ← 清华 邓俊辉

【题目描述】
统计十进制数的二进制表示中1的个数。

【算法分析】
虽然曾在 
https://blog.csdn.net/hnjzsyjyj/article/details/110148954 发过一篇关于“统计十进制数的二进制表示中1的个数”的博客,但本文实现了一种新的思路。此思路来源于清华大学邓俊辉版《数据结构》http://dsa.cs.tsinghua.edu.cn/~deng/ds/src_link/countones/countones_2.cpp.htm 中的内容。现分析如下:
● POW(x) 函数
自定义的 POW(x) 函数,运行后得到 2^x。

int POW(int x){
    return 1<<x; //2^x
}

● MASK(x) 函数
自定义的 MASK(x) 函数,运行后得到以 2^x 个 0 及 2^x 个 1 相间的32位的二进制数。这是本文算法的一个重要核心点。

int MASK(int x){
    int t=POW(x);
    return ((unsigned long) -1)/(POW(t)+1);
}

其中,MASK(0)、MASK(1)、MASK(2)、MASK(3)、MASK(4)的值如下所示。

MASK(0) = 01010101010101010101010101010101(b) = 55555555(h)
MASK(1) = 00110011001100110011001100110011(b) = 33333333(h)
MASK(2) = 00001111000011110000111100001111(b) = 0f0f0f0f(h)
MASK(3) = 00000000111111110000000011111111(b) = 00ff00ff(h)
MASK(4) = 00000000000000001111111111111111(b) = 0000ffff(h)

● ROUND(x,c) 函数
自定义的 ROUND(x,c) 函数,运行时以 2^c 位为单位进行分组,相邻的组两两捉对累加给定的十进制数对应的二进制数中 1 的个数。这个函数是导致本文算法时间复杂度低的重要原因。

int ROUND(int x,int c){
    int u=x&MASK(c);
    int v=(x>>POW(c))&MASK(c);
    return u+v;
}

● 系统自带的求以 2 为底的 x 的对数 log2(x)

#include <bits/stdc++.h>
using namespace std;

int main() {
    int x;
    cin>>x;
    cout<<log2(x);

    return 0;
}


/*
in:8
out:3
*/


【算法代码】

#include <bits/stdc++.h>
using namespace std;

int POW(int x){
    return 1<<x; //2^x
}

int MASK(int x){ //得到以2^x个0及2^x个1相间的32位的二进制数
    int t=POW(x);
    return ((unsigned long) -1)/(POW(t)+1);
}

int ROUND(int x,int c){
    int u=x&MASK(c);
    int v=(x>>POW(c))&MASK(c);
    return u+v;
}

int countOnes(unsigned int n){
    n=ROUND(n,0);
    n=ROUND(n,1);
    n=ROUND(n,2);
    n=ROUND(n,3);
    n=ROUND(n,4);
    return n;
}
    
int main() {
    int x;
    cin>>x;
    cout<<countOnes(x);

    return 0;
}


/*
in:123
out:6
*/





【参考文献】
https://blog.csdn.net/hnjzsyjyj/article/details/110148954
https://dsa.cs.tsinghua.edu.cn/~deng/ds/src_link/countones/countones_2.cpp.htm

https://vimsky.com/examples/usage/cpp-programming_library-function_cmath_log2.html





 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值