【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. }
相关文章
|
8天前
|
存储 搜索推荐 Serverless
【C++航海王:追寻罗杰的编程之路】哈希的应用——位图 | 布隆过滤器
【C++航海王:追寻罗杰的编程之路】哈希的应用——位图 | 布隆过滤器
18 1
|
4天前
|
安全 编译器 容器
C++STL容器和智能指针
C++STL容器和智能指针
|
6天前
|
算法 安全 Linux
|
1月前
|
存储 算法 数据挖掘
【C++】位图
【C++】位图
24 1
|
1月前
|
设计模式 算法 Java
【c++】STL之stack和queue详解
【c++】STL之stack和queue详解
28 1
|
2月前
|
编译器 C语言 C++
C++ STL中list迭代器的实现
C++ STL中list迭代器的实现
C++ STL中list迭代器的实现
|
1月前
|
存储 算法 C++
【C++高阶】探索STL的瑰宝 map与set:高效数据结构的奥秘与技巧
【C++高阶】探索STL的瑰宝 map与set:高效数据结构的奥秘与技巧
39 0
|
1月前
|
存储 算法 数据处理
【C++】STL简介
**STL是C++标准库的关键部分,源于Alexander Stepanov的泛型编程研究。它提供了数据结构(如vector、list)和算法,是高效、通用的软件框架。STL始于惠普,后由SGI发展,现已成为C++1998标准的一部分并不断进化。它包括容器、迭代器、算法、仿函数、配接器和分配器六大组件,带来高效性、通用性和可扩展性,但也存在性能开销和学习难度。学习STL涉及理解底层数据结构、用法、实现和实践。推荐[cplusplus.com](https://cplusplus.com)作为学习资源。**
|
1月前
|
存储 算法 程序员
C++基础知识(八:STL标准库(Vectors和list))
C++ STL (Standard Template Library标准模板库) 是通用类模板和算法的集合,它提供给程序员一些标准的数据结构的实现如 queues(队列), lists(链表), 和 stacks(栈)等. STL容器的提供是为了让开发者可以更高效率的去开发,同时我们应该也需要知道他们的底层实现,这样在出现错误的时候我们才知道一些原因,才可以更好的去解决问题。
|
1月前
|
算法 前端开发 C++
C++基础知识(八:STL标准库 deque )
deque在C++的STL(Standard Template Library)中是一个非常强大的容器,它的全称是“Double-Ended Queue”,即双端队列。deque结合了数组和链表的优点,提供了在两端进行高效插入和删除操作的能力,同时保持了随机访问的特性。