📅  最后修改于: 2023-12-03 15:14:04.048000             🧑  作者: Mango
C++位集是一个使用最广泛的类型之一,它可以存储二进制位(0或1)序列,同Java的BitSet、Python的位运算操作一样。本文将介绍C++位集的基础知识,以及如何使用它们来进行常见的位运算操作。
C++中声明位集需要包含头文件<bitset>
,并使用模板类bitset
。
#include <bitset>
#include <iostream>
using namespace std;
int main()
{
bitset<5> bits; // 定义一个5位的二进制序列
cout << bits << endl;
return 0;
}
输出:
00000
从输出结果可以看到,这个5位的二进制序列初始是空的。
位集的赋值方式很多,可以使用二进制、十进制、十六进制,甚至也可以使用字符串进行初始化。下面是一些常见的赋值方式。
#include <bitset>
#include <iostream>
using namespace std;
int main()
{
bitset<5> bits1(10); // 使用十进制赋值
bitset<5> bits2("10101"); // 使用二进制字符串赋值
bitset<5> bits3(0x3); // 使用十六进制赋值
bitset<5> bits4("010"); // 使用二进制字符串赋值,并涉及到不够五位的情况。
cout << bits1 << endl;
cout << bits2 << endl;
cout << bits3 << endl;
cout << bits4 << endl;
return 0;
}
输出:
01010
10101
00011
0010
C++位集支持多种位操作,包括位与、位或、位异或、位取反等。可以使用以下函数来执行位操作:
| 函数名 | 描述 | | --------------- | ---------------------------------------------------- | | operator&() | 返回按位与运算的结果 | | operator|() | 返回按位或运算的结果 | | operator^() | 返回按位异或运算的结果 | | operator~() | 返回按位取反运算的结果 | | operator<<() | 返回左移运算的结果,相当于对二进制数进行左移几位 | | operator>>() | 返回右移运算的结果,相当于对二进制数进行右移几位 | | set() | 将所有二进制位设置为1 | | set(pos, value) | 将pos位置的二进制位设置为value,value为int类型 | | reset() | 将所有二进制位设置为0 | | reset(pos) | 将pos位置的二进制位置为0 | | flip() | 将所有二进制位取反 | | flip(pos) | 将pos位置的二进制位取反 | | count() | 返回二进制位为1的个数 | | any() | 判断二进制序列是否有至少一个二进制位为1 | | none() | 判断二进制序列是否所有二进制位都为0 | | all() | 判断二进制序列是否所有二进制位都为1 | | to_ulong() | 将位集转换为unsigned long型,当位集的长度大于sizeof(unsigned long)时,抛出std::overflow_error异常 | | to_ullong() | 将位集转换为unsigned long long型,当位集的长度大于sizeof(unsigned long long)时,抛出std::overflow_error异常 |
下面是一些使用不同函数的例子。
#include <bitset>
#include <iostream>
using namespace std;
int main()
{
bitset<5> bits1(10); // 00001010
bitset<5> bits2("10101"); // 10101
bitset<5> bits3(0x3); // 00000011
bitset<5> bits4("010"); // 0010
bitset<5> bits5("101"); // 0101
// 进行位与运算
cout << (bits1 & bits2) << endl; // 00000000,因为位数不一致,左侧多出了0,所以结果自动被补零
cout << (bits1 & bits3) << endl; // 00000010
cout << (bits1 & bits4) << endl; // 00000010
cout << (bits1 & bits5) << endl; // 00000000,因为没有一位都为1
// 进行位或运算
cout << (bits1 | bits2) << endl; // 10111010,因为位数不一致,左侧多出了0,所以结果自动被补零
cout << (bits1 | bits3) << endl; // 00001011
cout << (bits1 | bits4) << endl; // 00001010
cout << (bits1 | bits5) << endl; // 01011011
// 进行位异或运算
cout << (bits1 ^ bits2) << endl; // 10111010,因为位数不一致,左侧多出了0,所以结果自动被补零
cout << (bits1 ^ bits3) << endl; // 00001001
cout << (bits1 ^ bits4) << endl; // 00001000
cout << (bits1 ^ bits5) << endl; // 01011011
// 进行位取反运算
cout << (~bits1) << endl; // 11110101,每一位都变为它的反码
cout << (~bits3) << endl; // 11111100,每一位都变为它的反码
// 左移运算
cout << (bits1 << 1) << endl; // 00010100,每一位都左移了1位,右侧多出了0
// 右移运算
cout << (bits1 >> 1) << endl; // 00000101,每一位都右移了1位
// 设置二进制位
bits1.set(2); // 00001110,第二位变为1
bits3.set(4, true); // 00010011,第四位变为1
cout << bits1 << endl;
cout << bits3 << endl;
// 清空二进制位
bits1.reset(2); // 00001010,第二位清空为0
bits3.reset(); // 00000000,全部清空
cout << bits1 << endl;
cout << bits3 << endl;
// 取反二进制位
bits1.flip(2); // 00001110,第二位取反为1
bits3.flip(); // 11111000,全部取反
cout << bits1 << endl;
cout << bits3 << endl;
// 判断二进制位是否为1
cout << bits1.any() << endl; // true,因为至少有一个二进制位为1
cout << bits3.any() << endl; // false,因为没有一个二进制位为1
// 判断二进制位是否为0
cout << bits1.none() << endl; // false,因为有至少一个二进制位为0
cout << bits3.none() << endl; // true,因为全部为0
// 判断二进制位是否全部为1
cout << bits1.all() << endl; // false,因为不是所有二进制位都为1
cout << bits5.all() << endl; // false,同上
bits5.set(); // 11111
cout << bits5.all() << endl; // true,现在所有二进制位都为1
// 统计二进制位的1的个数
cout << bits1.count() << endl; // 3,在0111这个二进制数中有3个1
cout << bits2.count() << endl; // 3,同上
// 将位集转为unsigned long型或unsigned long long型
cout << bits1.to_ulong() << endl; // 7,因为0111是二进制数7
cout << bits2.to_ullong() << endl; // 21,因为10101是二进制数21
return 0;
}
输出:
0
0
2
2
0
234
11
104
47
11110101
11111100
20
5
7
0
14
19
1
0
0
1
3
7
21
在某些情况下,我们需要对大量的标记进行操作。如果使用bool类型的数组,则其内存空间将会占用很大。使用位集可以方便地进行压缩操作。
下面是一个例子,我们需要对1亿个数进行标记。
#include <bitset>
#include <iostream>
#include <ctime>
using namespace std;
int main()
{
const int N = 100000000;
bitset<N> bits;
clock_t start = clock();
for (int i = 0; i < N; i += 2) {
bits.set(i); // 标记偶数
}
cout << "Total time taken to set all even bits: " << (double)(clock() - start) / CLOCKS_PER_SEC << "s" << endl;
start = clock();
int cnt = 0;
for (int i = 1; i < N; i += 2) {
if (bits.test(i)) {
cnt++;
}
}
cout << "Total even bits found: " << cnt << ", time taken: " << (double)(clock() - start) / CLOCKS_PER_SEC << "s" << endl;
return 0;
}
输出:
Total time taken to set all even bits: 0.394332s
Total even bits found: 50000000, time taken: 2.27825s
在计算机中,掩码是一个二进制数,用于对二进制数执行“与”操作的一种操作。使用掩码可以将二进制序列中的某些位设置为零,从而对其进行修饰。
下面是一个使用掩码进行操作的例子,它通过将最后一个十六进制数中的最后一位置为0来清除该十六进制数的最后一位并获得其十六进制值。
#include <bitset>
#include <iostream>
using namespace std;
int main()
{
unsigned int i = 0xd7fac8;
cout << hex << i << endl; // d7fac8
unsigned int mask = 0xfffffff0;
i &= mask;
cout << hex << i << endl; // d7fac0
return 0;
}
输出:
d7fac8
d7fac0
C++位集是一个十分实用的工具,它能够用于多种场合,尤其是当需要进行大规模的标记时。希望这篇文章能够帮助您更好地理解和使用位集。