标准非STL容器 : bitset
什么是“标准非STL容器”?标准非STL容器是指“可以认为它们是容器,但是他们并不满足STL容器的所有要求”。前文提到的容器适配器stack、queue及priority_queue都是标准非STL容器的一部分。此外,valarray也是标准非STL容器。
bitset:一种高效位集合操作容器。
2. API
bitset提供的api:
(constructor) Construct bitset (public member function)
operator[] Access bit (public member function)
set Set bits (public member function)
reset Reset bits (public member function )
flip Flip bits (public member function)
to_ulong Convert to unsigned long integer (public member function)
to_string Convert to string (public member function)
count Count bits set (public member function)
size Return size (public member function)
test Return bit value (public member function )
any Test if any bit is set (public member function)
none Test if no bit is set (public member function)
3. 源码剖析
SGI bitset部分实现源码
- template<size_t _Nb>
- class bitset : private _Base_bitset<__BITSET_WORDS(_Nb)>
- {
- private:
- typedef _Base_bitset<__BITSET_WORDS(_Nb)> _Base;
- typedef unsigned long _WordT;
- private:
- void _M_do_sanitize() {
- _Sanitize<_Nb%__BITS_PER_WORD>::_M_do_sanitize(this->_M_hiword());
- }
- .....
- }
- #define __BITS_PER_WORD (CHAR_BIT*sizeof(unsigned long))
- #define __BITSET_WORDS(__n) \
- ((__n) < 1 ? 1 : ((__n) + __BITS_PER_WORD - 1)/__BITS_PER_WORD)
- template<size_t _Nw>
- struct _Base_bitset {
- typedef unsigned long _WordT;
- _WordT _M_w[_Nw]; // 0 is the least significant word.
- _Base_bitset( void ) { _M_do_reset(); }
- _Base_bitset(unsigned long __val) {
- _M_do_reset();
- _M_w[0] = __val;
- }
- static size_t _S_whichword( size_t __pos )
- { return __pos / __BITS_PER_WORD; }
- static size_t _S_whichbyte( size_t __pos )
- { return (__pos % __BITS_PER_WORD) / CHAR_BIT; }
- static size_t _S_whichbit( size_t __pos )
- { return __pos % __BITS_PER_WORD; }
- static _WordT _S_maskbit( size_t __pos )
- { return (static_cast<_WordT>(1)) << _S_whichbit(__pos); }
- _WordT& _M_getword(size_t __pos) { return _M_w[_S_whichword(__pos)]; }
- _WordT _M_getword(size_t __pos) const { return _M_w[_S_whichword(__pos)]; }
- _WordT& _M_hiword() { return _M_w[_Nw - 1]; }
- _WordT _M_hiword() const { return _M_w[_Nw - 1]; }
- void _M_do_and(const _Base_bitset<_Nw>& __x) {
- for ( size_t __i = 0; __i < _Nw; __i++ ) {
- _M_w[__i] &= __x._M_w[__i];
- }
- }
- void _M_do_or(const _Base_bitset<_Nw>& __x) {
- for ( size_t __i = 0; __i < _Nw; __i++ ) {
- _M_w[__i] |= __x._M_w[__i];
- }
- }
- void _M_do_xor(const _Base_bitset<_Nw>& __x) {
- for ( size_t __i = 0; __i < _Nw; __i++ ) {
- _M_w[__i] ^= __x._M_w[__i];
- }
- }
节选上述代码,可以得到:
1. bitset继承_Base_bitset,具体操作封装在_Base_bitset中
2. bitset 的size作为模板参数(非类型模板参数的一个要求是,编译器能在编译期就能把参数确定下来),因此,bitset大小在编译期固定,不支持插入和删除元素
3. 各种位操作,性能高
4._Base_bitset使unsigned long作为底层存储,不支持指针、引用、迭代器
5. 使用 _WordT _M_w[_Nw];分配内存,因此在栈中定义bitset需要注意大小(和STL标准容器堆内存分配区别开)。
eg,下面的代码将栈溢出(测试机器栈内存10M)
- void fun()
- {
- const int n = 800000000;
- bitset<n> a;
- cout << a.size() << endl;
- }
- int main(int argc, char** argv)
- {
- fun();
- return 0;
- }
大内存分配可以分配在堆中,如下:
- const int n = 800000000;
- bitset<n> *a = new(std::nothrow) bitset<n>;
- if(a)
- {
- cout << a->size() << endl;
- delete a;
- a = NULL;
- }
4. vector<bool>及deque<bool>
bitset高效,但是size必须在编译器确定,不支持插入和删除。因此,一个可能的替代品是vector<bool>和deque<bool>
两者的区别:
vector<bool>不是一个STL容器,并且不容纳bool(like bitse底层t机制)
deque<bool>是一个STL容器,它保存真正的bool值
分别运行
- deque<bool> a;
- a[0] = 0;
- bool* b = &a[0];
- cout << *b << endl;
和
- vector<bool> a;
- a[0] = 0;
- bool* b = &a[0];
- cout << *b << endl;
将会发现:
使用deque<bool>正确,而是用vector<bool>会报错:“cannot convert `std::_Bit_reference*' to `bool*' in initialization“
但是,deque简直是在践踏内存。
使用deque<bool>
- int main(int argc, char** argv)
- {
- deque<bool> a(10000000000);
- sleep(100);
- return 0;
- }
内存使用:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
23612 work 25 0 9990m 9.8g 720 S 0.0 65.0 0:39.35 test
使用vector<bool>
- int main(int argc, char** argv)
- {
- vector<bool> a(10000000000);
- sleep(100);
- return 0;
- }
内存使用:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
23909 work 25 0 1198m 1.2g 716 S 0.0 7.8 0:01.31 test
使用bitset
- int main(int argc, char** argv)
- {
- const unsigned long int n = 10000000000;
- bitset<n> *a = new(std::nothrow) bitset<n>;
- sleep(100);
- return 0;
- }
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
24439 work 25 0 1198m 1.2g 712 S 30.7 7.8 0:00.92 test
10亿个bool,vector<bool>和bitset使用内存1198M,deque<bool>则是9990M
5. 总结
在需要对位集合进行操作的时候,如何操作集合大小比较固定,优先选择高效的bitset;
如果需要动态增删元素,或者编译期间无法确定集合大小,则可以考虑vector<bool>,deque<bool>内存开销太大,基本上不考虑。
参考:
http://www.sgi.com/tech/stl/download.html
http://www.cplusplus.com/reference/stl/vector/
http://www.cplusplus.com/reference/stl/bitset/
扩展阅读:
Vector specialization: vector<bool>
The vector class template has a special template specialization for the bool type.
This specialization is provided to optimize for space allocation: In this template specialization, each element occupies only one bit (which is eight times less than the smallest type in C++:char).
The references to elements of a bool vector returned by the vector members are not references tobool objects, but a special member type which is a reference to a single bit, defined inside thevector<bool> class specialization as:
- class vector<bool>::reference {
- friend class vector;
- reference(); // no public constructor
- public:
- ~reference();
- operator bool () const; // convert to bool
- reference& operator= ( const bool x ); // assign from bool
- reference& operator= ( const reference& x ); // assign from bit
- void flip(); // flip bit value.
- }
转载于:https://www.cnblogs.com/freeopen/p/5483005.html
标准非STL容器 : bitset相关推荐
- STL 标准模板库—容器部分【C++】
STL标准模板库 包含内容: 容器类:vector.list.deque.set.map等 迭代器:"泛型指针",每个容器都有自己的迭代器,[vector和deque的迭代器是随机 ...
- C++ 笔记(19)— 标准模板库(STL容器、STL迭代器、STL算法、STL容器特点、STL字符串类)
C++ 标准库可以分为两部分: 标准函数库: 这个库是由通用的.独立的.不属于任何类的函数组成的.函数库继承自 C 语言. 面向对象类库: 这个库是类及其相关函数的集合. C++ 标准库包含了所有的 ...
- C++ 标准模板库 STL 容器适配器
C++ 标准模板库 STL 容器适配器 容器 数据结构 时间复杂度 顺序性 重复性 stack deque / list 顶部插入.顶部删除 O(1) 无序 可重复 queue deque / lis ...
- C++语言基础 —— STL —— 容器与迭代器
[概述] STL 是指 C++ 标准模板库,是 C++ 语言标准中的重要组成部分,其以模板类和模版函数的形式提供了各种数据结构与算法的精巧实现,如果能充分使用 STL,可以在代码空间.执行时间.编码效 ...
- STL容器底层数据结构的实现
C++ STL 的实现: 1.vector 底层数据结构为数组 ,支持快速随机访问 2.list 底层数据结构为双向链表,支持快速增删 3.deque 底层 ...
- STL 容器和迭代器连载8_访问顺序容器的元素
2019独角兽企业重金招聘Python工程师标准>>> /*- ========================================================== ...
- [技术] OIer的C++标准库 : STL入门
注: 本文主要摘取STL在OI中的常用技巧应用, 所以可能会重点说明容器部分和算法部分, 且不会讨论所有支持的函数/操作并主要讨论 C++11 前支持的特性. 如果需要详细完整的介绍请自行查阅标准文档 ...
- c++ STL 容器
STL源码分析 (一)vector容器 vector的数据安排以及操作方式,与array非常相似.两者的唯一区别在于空间的运用的灵活性.array是静态空间,一旦配置了就不能改变.vector是动态空 ...
- C++ STL容器元素正确删除
一.容器与迭代器 1.1 STL容器 容器是用来管理一大群元素的,为了适应不同需要,STL提供了不同的容器. 在C++中,容器被定义为:在数据存储上,有一种对象类型,它可以持有其他对象或指向其他对象的 ...
最新文章
- 产品经理如何开始数据分析之路?(基础知识)
- android 属性动画伸缩,Android的属性动画(二)加载框圆点旋转收缩放大缩小效果的实现...
- CV Code | 计算机视觉开源周报 20190701期
- Ext.Ajax.request
- 普通人怎么样才能存到钱?
- Bailian4074 积水量【序列处理】
- 51nod 更难的矩阵取数问题 + 滚动数组优化
- RHEL4-VNC服务(二)vnc服务器的配置
- linux操作系统环境搭建实验报告,操作系统实验报告 Linux基本环境
- 串口工具 和 终端工具的区别 -个人猜测
- mysql +cobar_转:阿里开源Mysql分布式中间件:Cobar
- spring报错→UnexpectedRollbackException: Transaction silently rolled back becaus
- C#迷宫Winform小游戏,生成可连通的迷宫地图
- AngularJS笔记
- python百度爬虫_Python爬虫 - 简单抓取百度指数
- 微信公众平台开发技术文档
- npm i 和 npm i -S有什么区别吗?
- 微信兔子,比较下来算是比较好用的工具
- R语言 | 将CSV文件中原本为空白值的chr数据赋值为NA
- 二进制文件转文本工具
热门文章
- android 组件 线程,Android UI线程和非UI线程
- java编程题有难度的_算法与编程面试题 不喜勿喷 难度指数:*****...
- 【基础大全】一文带你打好网工路由基础......
- 云原生时代下,容器安全的“四个挑战”和“两个关键”
- 林昊获中国计算机学会杰出工程师奖,阿里中间件再获高度肯定,“三位一体”推动技术普惠
- Kubernetes 核心概念
- hive 指定字段插入数据_Hive 表之间数据处理,Int 类型字段部分字段出现 NULL情况...
- python 遍历内嵌tuple,python特性语法之遍历、公共方法、引用
- php查询跳转结果页面,登录判断跳转页面
- mysql5.6英文版安装步骤_mysql5.6版本安装步骤详解