假设x是一个集合,下面的代码遍历集合x的子集:
int b = 0;
do {
// process subset b
} while (b=(b-x)&x);
我看到了这篇关于位操作的文章,以及它是如何用来表示集合的。
表达式b=(b-x)&x是什么意思? 它是怎么工作的? 在do while循环中,我熟悉==,但不熟悉=。 那是怎么运作的? 当(b-x)&x的值变为零时,循环是否终止?
代码的用法如下:
#include <iostream>
using namespace std;
void subsets(int x, int b){
do{
cout << b<<"\n";
}while(b = (b-x)&x);
}
int main()
{
int x = (1<<1)|(1<<3)|(1<<4)|(1<<8);
int b = 0;
subsets(x, b);
return 0;
}
上面代码给出的输出是:
0
2
8
10
16
18
24
26
256
258
264
266
272
274
280
282
这段代码摘自《竞争性编程指南:通过竞赛学习和改进算法》一书
容易零件优先:
当(b-x)&x的值变为零时,循环是否终止? 在do while循环中,我熟悉==,但不熟悉=。 那是怎么运作的?
是的。
do
/while
循环如下:
do{
cout << b<<"\n";
}while(b = (b-x)&x);
执行以下步骤:
cout<<<; b<<“\n”;
.b=(b-x)&x
并记住结果。=
是分配。 它将变量设置为值,如i=0;
。 但是。。。 嗯? 作业结果如何? 在C语言中,赋值的结果就是被赋值的值。 这允许您编写a=b=c=0;
,将三个变量a
,b
和c
设置为0。 这相当于a=(b=(c=0));
,即它将c
设置为0,然后将b
设置为该结果,然后将a
设置为该结果。 (在C++中,可以编写一个不遵循此规则的类,但我们这里只处理int
s,而不是类)
有些人喜欢用这个伎俩让他们的代码变得更短。 你可以这样写:
do{
cout << b<<"\n";
b = (b-x)&x;
}while(b);
表达式b=(b-x)&x是什么意思?
=
是分配。 -
是减法。 &
是“按位与”。
这将从b
中减去x
。 然后,它用x
对答案进行逐位加和。 然后,它将b
设置为该问题的答案。
什么是按位与? 按位AND是这样一种操作,在这种操作中,你记下二进制数字,对齐它们,然后创建一个新的数字,如果两个输入中的位都是1,则每个位都是1,否则为0。 示例:
01011010 = 90
& 11101000 = 232
-----------------
01001000 = 72
so 90(&P; 232等于72。
它是怎么工作的?
这个程序基本上是把数字当作二进制来处理的。 x
中的每个位为1表示某物“在集合中”,或为0表示该物不在集合中。
b
然后遍历这些位的所有可能组合。 B=(b-x)&; X;
有点“巫毒魔咒”的意思,按顺序将组合改为下一个,例如:
- 000000000 <- b the first time
011001001 <- x
-----------------
100110111 <- b-x
& 011001001 <- x
-----------------
000000001 <- (b-x)&x (b the second time)
- 011001001 <- x
-----------------
100111000 <- b-x
& 011001001 <- x
-----------------
000001000 <- (b-x)&x (b the third time)
- 011001001 <- x
-----------------
100111111 <- b-x
& 011001001 <- x
-----------------
000001001 <- (b-x)&x (b the fourth time)
...etc...
你可以肯定,发明这个把戏的人是非常聪明的。
“所有内置赋值运算符返回*this
”[cppreference]
这意味着b=a
是返回对b
的引用的表达式(对于原始类型,例如int B;int a;
)。
在您的示例中,B=(b-x)&x
在将(b-x)&x
分配给B
之后返回对B
的引用。
在条件检查中(例如,在while
循环中),此值隐式转换为bool
,其中0
=>; false
和其他任何东西=>; true
。 循环
do {
// process subset b
} while (b=(b-x)&x);
只要(b-x)&x!=0
就会重复