【C++】-- STL之位图(二)

简介: 【C++】-- STL之位图

三、位图实现

1.位图定义

位图只需要定义一个成员_bits即可,表明传入的数据个数:

1. #pragma once
2. #include<assert.h>
3. namespace delia
4. {
5.  template<size_t N>//数据总数
6.  class BitSet
7.  {
8.  private:
9.    vector<int> _bits;
10.   };
11. }

2.构造

1个字节可以表示32个数在不在,因此只需要申请N/32+1个空间,向上取整

1.  public:
2.    BitSet()
3.    {
4.      _bits.resize(N/32+1,0)//向上取整,否则不够存,默认每一位标记为0
5.    }

3.标记

只把该位置1,其他位都不变:

①计算x在位图中的第几个整数的第几个位置

②要把该位置1,就必须让该位和1按位或,且其他位都不能被改变

1.    //标记
2.    void Set(size_t x)
3.    {
4.      assert(x < N);
5. 
6.      //计算x映射的位在第i个整数
7.      //计算x映射的位在这个整数的第j位
8. 
9.      size_t i = x / 32;
10.       size_t j = x % 32;
11. 
12.       //_bits[i]的第j位标记为1,并且不影响其他位
13.       _bits[i] |= (1 << j);
14.     }

4.删除

只把该位置0,其他位都不变:

①计算x在位图中的第几个整数的第几个位置

②要把该位置0,就必须让该位和0按位与,且其他位都不能被改变

③把1左移j位再按位取反,就可以将该位置为0。

1.    //删除
2.    void Reset(size_t x)
3.    {
4.      assert(x < N);
5. 
6.      //计算x映射的位在第i个整数
7.      //计算x映射的位在这个整数的第j位
8. 
9.      size_t i = x / 32;
10.       size_t j = x % 32;
11. 
12.       //_bits[i]的第j位标记为0,并且不影响其他位,
13.       _bits[i] &= (~(1 << j));      
14.     }

5.检验在不在

①计算x在位图中的第几个整数的第几个位置

②返回该位和1左移j位置后相与的结果

1.    //检验在不在
2.    void Test(size_t x)
3.    {
4.      assert(x < N);
5. 
6.      //计算x映射的位在第i个整数
7.      //计算x映射的位在这个整数的第j位
8. 
9.      size_t i = x / 32;
10.       size_t j = x % 32;
11. 
12.       //如果第j位为1,结果是非0,非0为真
13.       //如果第j位为0,结果是0,0为假
14. 
15.       return _bits[i] & (1 << j);
16.     }

6.完整代码段

1. #pragma once
2. #include<assert.h>
3. #include<vector>
4. using namespace std;
5. 
6. namespace delia
7. {
8.  template<size_t N>
9.  class BitSet
10.   {
11.   public:
12.     BitSet()
13.     {
14.       _bits.resize(N/32+1,0)//向上取整,否则不够存,默认每一位标记为0
15.     }
16. 
17.     //标记
18.     void Set(size_t x)
19.     {
20.       assert(x < N);
21. 
22.       //计算x映射的位在第i个整数
23.       //计算x映射的位在这个整数的第j位
24. 
25.       size_t i = x / 32;
26.       size_t j = x % 32;
27. 
28.       //_bits[i]的第j位标记为1,并且不影响其他位
29.       _bits[i] |= (1 << j);
30.     }
31. 
32.     //删除
33.     void Reset(size_t x)
34.     {
35.       assert(x < N);
36. 
37.       //计算x映射的位在第i个整数
38.       //计算x映射的位在这个整数的第j位
39. 
40.       size_t i = x / 32;
41.       size_t j = x % 32;
42. 
43.       //_bits[i]的第j位标记为0,并且不影响其他位,
44.       _bits[i] &= (~(1 << j));      
45.     }
46. 
47.     //检验在不在
48.     void Test(size_t x)
49.     {
50.       assert(x < N);
51. 
52.       //计算x映射的位在第i个整数
53.       //计算x映射的位在这个整数的第j位
54. 
55.       size_t i = x / 32;
56.       size_t j = x % 32;
57. 
58.       //如果第j位为1,结果是非0,非0为真
59.       //如果第j位为0,结果是0,0为假
60. 
61.       return _bits[i] & (1 << j);
62.     }
63.   private:
64.     vector<int> _bits;
65.   };
66. 
67.   void test_BitSet()
68.   {
69.     BitSet<4294967295u>* bs=new BitSet<4294967295u>;//40亿个数据向上取整,即开辟2^32个bit位
70.   }
71. }

四、位图应用

1.给定两个文件,这两个文件分别都有100亿个整数,现在只有1G内存,如何找两个文件交集?

方案(1):依次读取第一个文件中的所有整数并标记映射到一个位图,再读取第二个文件中的所有整数,判断在不在位图,在就是交集中的书,不在就不是

方案(2):依次读取第一个文件的所有证书标记映射为位图1,一次读取第二个文件的所有证书标记映射为位图2,再对两个位图进行相与,结果为1的位就是交集。

无论方案(1)还是方案(2),由于整数最多只有2^32=4294967295个,42亿多个,文件有100亿个数据,肯定有重复的,因此只需要开辟2^32个bit位就能覆盖到这100亿个数据。

2.给定100亿个整数,设计算法找到只出现一次的整数

方案:位图是一个bit位标记一个值,现在用两个bit位标记一个值,位图能标记32个值在不在,那么现在只能标记16个值在不在:

00    出现0次

01    出现1次

10    出现2次及以上

11    不考虑

最后找出01标记的整数

1. #define  _CRT_SECURE_NO_WARNINGS  1
2. #pragma once
3. #include<assert.h>
4. #include<iostream>
5. #include<vector>
6. #include<bitset>
7. using namespace std;
8. 
9. int main()
10. {
11.   vector<int> v = { 3,67,259,1,7890,4,36,23 };
12. 
13.   bitset<4294967295u>* bs1 = new bitset<4294967295u>;
14.   bitset<4294967295u>* bs2 = new bitset<4294967295u>;
15. 
16.   for (auto e : v)
17.   {
18.     if (!bs1->test(e) && !bs2->test(e))//00->01,第一次出现
19.     {
20.       bs2->set(e);
21.     }
22.     else if (!bs1->test(e) && bs2->test(e))//01->10,第二次出现
23.     {
24.       bs1->set(e);
25.       bs2->reset(e);
26.     }
27.     else if (bs1->test(e) && !bs2->test(e))//10->11,第三次出现
28.     {
29.       //不用处理
30.     }
31.     else//第四次出现
32.     {
33.       //不用处理
34.       assert(false);
35.     }
36.   }
37. 
38.   for (size_t i = 0; i < 4294967295; i++)
39.   {
40.     if (!bs1->test(i) && bs2->test(i))//找01
41.     {
42.       cout << i << endl;
43.     }
44.   }
45.   return 0;
46. }

3.  1个文件有100亿个整数,1G内存,设计算法找到出现次数不超过2次的所有整数

现在用两个bit位标记一个值,

00    出现0次

01    出现1次

10    出现2次

11    出现3次

最后找出01和10标记的,即出现1次和出现2次的整数

1. #define  _CRT_SECURE_NO_WARNINGS  1
2. #pragma once
3. #include<assert.h>
4. #include<iostream>
5. #include<vector>
6. #include<bitset>
7. using namespace std;
8. 
9. int main()
10. {
11.   vector<int> v = { 3,67,259,1,7890,4,36,23 };
12. 
13.   bitset<4294967295u>* bs1 = new bitset<4294967295u>;
14.   bitset<4294967295u>* bs2 = new bitset<4294967295u>;
15. 
16.   for (auto e : v)
17.   {
18.     if (!bs1->test(e) && !bs2->test(e))//00->01,第一次出现
19.     {
20.       bs2->set(e);
21.     }
22.     else if (!bs1->test(e) && bs2->test(e))//01->10,第二次出现
23.     {
24.       bs1->set(e);
25.       bs2->reset(e);
26.     }
27.     else if (bs1->test(e) && !bs2->test(e))//10->11,第三次出现
28.     {
29.       bs1->set(e);
30.     }
31.     else//第四次出现
32.     {
33.       //不用处理
34.       assert(false);
35.     }
36.   }
37. 
38.   //找01或10
39.   for (size_t i = 0; i < 4294967295; i++)
40.   {
41.     if ((!bs1->test(i) && bs2->test(i))
42.       || (bs1->test(i) && !bs2->test(i))
43.     {
44.       cout << i << endl;
45.     }
46.   }
47. 
48.   return 0;
49. }
相关文章
|
12天前
|
存储 自然语言处理 安全
C++ STL标准库 《string原理与实战分析》
C++ STL标准库 《string原理与实战分析》
17 0
|
9天前
|
安全 算法 C语言
【C++进阶】深入STL之string:掌握高效字符串处理的关键
【C++进阶】深入STL之string:掌握高效字符串处理的关键
14 1
【C++进阶】深入STL之string:掌握高效字符串处理的关键
|
1天前
|
C++ 容器
C++ STL:各类容器的特点和优缺点比较
C++ STL:各类容器的特点、优势、劣势比较
|
3天前
|
存储 算法 C++
C++一分钟之-标准模板库(STL)简介
【6月更文挑战第21天】C++ STL是高效通用的算法和数据结构集,简化编程任务。核心包括容器(如vector、list)、迭代器、算法(如sort、find)和适配器。常见问题涉及内存泄漏、迭代器失效、效率和算法误用。通过示例展示了如何排序、遍历和查找元素。掌握STL能提升效率,学习过程需注意常见陷阱。
20 4
|
7天前
|
算法 前端开发 Linux
【常用技巧】C++ STL容器操作:6种常用场景算法
STL在Linux C++中使用的非常普遍,掌握并合适的使用各种容器至关重要!
33 10
|
1天前
|
存储 安全 算法
C++的内置数组和STL array、STL vector
C++的内置数组和STL array、STL vector
|
5天前
|
存储 编译器 C++
|
9天前
|
存储 算法 程序员
【C++进阶】深入STL之 栈与队列:数据结构探索之旅
【C++进阶】深入STL之 栈与队列:数据结构探索之旅
18 4
|
9天前
|
存储 算法 程序员
【C++进阶】深入STL之vector:构建高效C++程序的基石
【C++进阶】深入STL之vector:构建高效C++程序的基石
16 1
|
9天前
|
编译器 C++
【C++进阶】深入STL之string:模拟实现走进C++字符串的世界
【C++进阶】深入STL之string:模拟实现走进C++字符串的世界
13 1