-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFun1_12.cpp
More file actions
46 lines (40 loc) · 2.8 KB
/
Fun1_12.cpp
File metadata and controls
46 lines (40 loc) · 2.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//
/** countOnes1:统计整数n的二进制展开中数位1的总数*/
/********************************************************************************************************************
* Created by Geliang Tian on 2017/11/21. tglasd@163.com, gltian@bit.edu.cn
* Copyright (c) 2018. All rights reserved.
*
* ISBN: 7-302-33064-6 & 7-302-33065-3 & 7-302-29652-2 & 7-302-26883-3
* Junhui DENG, deng@tsinghua.edu.cn
* Computer Science & Technology, Tsinghua University
* Copyright (c) 2006-2013. All rights reserved.
*********************************************************************************************************************/
int countOnes1 ( unsigned int n ) { //统计整数二进制展开中数位1的总数:O(ones)正比于数位1的总数
int ones = 0; //计数器复位
while ( 0 < n ) { //在n缩减至0之前,反复地
ones++; //计数(至少有一位为1)
n &= n - 1; //清除当前最靠右的1
}
return ones; //返回计数
} //等效于glibc的内置函数int __builtin_popcount (unsigned int n)
/** O(logW), W = O(logn) 为整数的宽度 */
//一种可能的实现方法
#define POW(c) (1 << (c)) //2^c
#define MASK(c) (((unsigned long) -1) / (POW(POW(c)) + 1)) //以2^c位为单位分组,相间地全0和全1
// MASK(0) = 55555555(h) = 01010101010101010101010101010101(b)
// MASK(1) = 33333333(h) = 00110011001100110011001100110011(b)
// MASK(2) = 0f0f0f0f(h) = 00001111000011110000111100001111(b)
// MASK(3) = 00ff00ff(h) = 00000000111111110000000011111111(b)
// MASK(4) = 0000ffff(h) = 00000000000000001111111111111111(b)
//输入:n的二进制展开中,以2^c位为单位分组,各组数值已经分别等于原先这2^c位中1的数目
#define ROUND(n, c) (((n) & MASK(c)) + ((n) >> POW(c) & MASK(c))) //运算优先级:先右移,再位与
//过程:以2^c位为单位分组,相邻的组两两捉对累加,累加值用原2^(c + 1)位就地记录
//输出:n的二进制展开中,以2^(c + 1)位为单位分组,各组数值已经分别等于原先这2^(c + 1)位中1的数目
int countOnes2 ( unsigned int n ) { //统计整数n的二进制展开中数位1的总数
n = ROUND ( n, 0 ); //以02位为单位分组,各组内前01位与后01位累加,得到原先这02位中1的数目
n = ROUND ( n, 1 ); //以04位为单位分组,各组内前02位与后02位累加,得到原先这04位中1的数目
n = ROUND ( n, 2 ); //以08位为单位分组,各组内前04位与后04位累加,得到原先这08位中1的数目
n = ROUND ( n, 3 ); //以16位为单位分组,各组内前08位与后08位累加,得到原先这16位中1的数目
n = ROUND ( n, 4 ); //以32位为单位分组,各组内前16位与后16位累加,得到原先这32位中1的数目
return n; //返回统计结果
} //32位字长时,O(log_2(32)) = O(5) = O(1)