免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4778 | 回复: 12
打印 上一主题 下一主题

贴一个BitSet类,请大家拍砖^_^ [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-04-14 19:45 |只看该作者 |倒序浏览
需要一个类,能实现一些简单的位操作,标准库的bitset类提供了很好的功能,但它的大小由其模板参数决定。这使我们不能在运行时确定大小,于是自己动手写了个,实现了一些简单的操作(操作基本完备),请大家拍砖^_^

大家有什么好的建议或者想法,欢迎探讨。另外,这个类只简单地测试了下下,如果发现什么Bug或者不完备的地方,还望指出,谢谢

谢谢网友 awake 的建议!


  1. // BitSet.h

  2. #ifndef BITSET_H
  3. #define BITSET_H

  4. #include <iostream>
  5. #include <stdexcept>
  6. #include <limits>

  7. // Class BitSet:
  8. //   Class BitSet is a sequence of bits, and some operations are defined on it.
  9. // Notes:
  10. // (1) When an operation will be done on the bit at position 'pos',
  11. //       you have to be sure that 'pos' satisfies the inequation pos < size(),
  12. //       where size() returns the number of bits in this BitSet object.
  13. //     If pos >= size(), an exception with type out_of_range will be thrown.
  14. //     Note that the position 'pos' starts at zero.
  15. // (2) In these operators: &=, |=, ^=, &, | and ^,
  16. //       if the two BitSet objects have unequal values returned by size() ,
  17. //       then an exception with type lenth_error will be thrown.
  18. // (3) When the memory allocation fails, an exception with type bad_alloc will be thrown.
  19. class BitSet
  20. {
  21. public:
  22.     typedef unsigned long block_type;
  23.     typedef unsigned long size_type;
  24.    
  25. private:
  26.     enum {BLOCK_BYTES = sizeof(block_type)};
  27.     enum {BLOCK_BITS = std::numeric_limits<block_type>::digits};
  28.    
  29. public:
  30.     //--- copy control functions -------------------------
  31.     BitSet(size_type bitNum);
  32.     BitSet(const BitSet& bits);
  33.     BitSet& operator= (const BitSet&);
  34.     ~BitSet();
  35.    
  36.     //--- bit opearations --------------------------------
  37.     // left-shift operator
  38.     BitSet& operator<<= (size_type num);   
  39.     // right-shift operator
  40.     BitSet& operator>>= (size_type num);
  41.    
  42.     // set the bit at position pos when tagSet is true(default); otherwise, clear the bit
  43.     BitSet& set(size_type pos, bool tagSet = true);
  44.     // clear all the bits when tagClear is true(default); otherwise, set all the bits
  45.     BitSet& clear(bool tagClear = true);
  46.    
  47.     // flip all the bits
  48.     BitSet& flip();
  49.     BitSet operator~ ();
  50.     // flip the bit at position pos
  51.     BitSet& flip(size_type pos);
  52.    
  53.     // test the bit at position pos
  54.     bool test(size_type pos) const;   

  55.     //--- operation between two BitSet objects-----------------
  56.     BitSet& operator&= (const BitSet& bit);     // bitwise AND
  57.     BitSet& operator|= (const BitSet& bit);     // bitwise inclusive OR
  58.     BitSet& operator^= (const BitSet& bit);     // bitwise exclusive OR
  59.     bool operator== (const BitSet&) const;      // equal: bitwise equal
  60.    
  61.     // get the number of bits in this BitSet object
  62.     size_type size() const;
  63.    
  64. private:
  65.     void leftShift(size_type num);    // left shift
  66.     void rightShift(size_type num);   // right shift   

  67. private:
  68.     size_type m_bitNum;    // the number of bits in this BitSet object
  69.     size_type m_size;      // the number of elements with type BitSet::block_type used to store the bits
  70.     block_type *m_pBits;   // a pointer to an array with element type BitSet::block_type,
  71.                            // used to store the bits information
  72.     block_type m_mask;     // used to filter the redundant bits
  73.                            // in the array element with the highest address
  74. };

  75. // declarations of nonmember functions
  76. BitSet operator<< (const BitSet&, BitSet::size_type);   // left-shift operator
  77. BitSet operator>> (const BitSet&, BitSet::size_type);   // right-shift operator
  78. BitSet operator& (const BitSet&, const BitSet&);        // bitwise AND
  79. BitSet operator| (const BitSet&, const BitSet&);        // bitwise inclusive OR
  80. BitSet operator^ (const BitSet&, const BitSet&);        // bitwise exclusive OR
  81. bool operator!= (const BitSet&, const BitSet&);         // not equal

  82. //--- inline member functions ----------------------------------
  83. //--- copy control functions --------------------
  84. inline BitSet::BitSet(size_type bitNum)
  85. {
  86.     m_bitNum = bitNum;
  87.     size_type freeBits = (BLOCK_BITS - m_bitNum % BLOCK_BITS) % BLOCK_BITS;
  88.     m_size = m_bitNum / BLOCK_BITS + (freeBits == 0 ? 0 : 1);
  89.     m_pBits = new block_type[m_size];
  90.     if (m_pBits == NULL)
  91.         throw std::bad_alloc();
  92.     clear();  // clear all bits
  93.     // calculate the mask value
  94.     m_mask = ~block_type(0);
  95.     m_mask >>= freeBits;
  96. }

  97. inline BitSet::BitSet(const BitSet& bit)
  98. {
  99.     m_size = bit.m_size;
  100.     m_pBits = new block_type[m_size];
  101.     if (m_pBits == NULL)
  102.         throw std::bad_alloc();
  103.     memcpy(m_pBits, bit.m_pBits, m_size * BLOCK_BYTES);
  104.     m_bitNum = bit.m_bitNum;
  105.     m_mask = bit.m_mask;
  106. }

  107. inline BitSet& BitSet::operator= (const BitSet& bit)
  108. {
  109.     if (this == &bit)    // self assignment
  110.         return (*this);
  111.     if (m_size != bit.m_size) {
  112.         delete [] m_pBits;
  113.         m_size = bit.m_size;
  114.         m_pBits = new block_type[m_size];
  115.         if (m_pBits == NULL)
  116.             throw std::bad_alloc();
  117.     }
  118.     memcpy(m_pBits, bit.m_pBits, m_size * BLOCK_BYTES);
  119.     m_bitNum = bit.m_bitNum;
  120.     m_mask = bit.m_mask;
  121.     return (*this);
  122. }

  123. inline BitSet::~BitSet()
  124. {
  125.     delete [] m_pBits;
  126. }

  127. //--- bit opearations -----------------------------
  128. // left shift operator
  129. inline BitSet& BitSet::operator<<= (size_type num)
  130. {
  131.     leftShift(num);
  132.     return (*this);
  133. }

  134. // right shift operator
  135. inline BitSet& BitSet::operator>>= (size_type num)
  136. {
  137.     rightShift(num);
  138.     return (*this);
  139. }

  140. // clear all the bits when tagClear is true(default); otherwise, set all the bits
  141. inline BitSet& BitSet::clear(bool tagClear)
  142. {
  143.     if (tagClear)
  144.         memset(m_pBits, 0, m_size * BLOCK_BYTES);
  145.     else {
  146.         memset(m_pBits, (int)std::numeric_limits<unsigned char>::max(), m_size * BLOCK_BYTES);
  147.         m_pBits[m_size-1] &= m_mask;  // filter the redundant bits
  148.     }
  149.     return (*this);
  150. }

  151. // flip all the bits
  152. inline BitSet& BitSet::flip()
  153. {
  154.     for (size_type i = 0; i < m_size; ++i)
  155.         m_pBits[i] = ~m_pBits[i];
  156.     m_pBits[m_size-1] &= m_mask;  // filter the redundant bits
  157.     return (*this);
  158. }

  159. // flip all the bits
  160. inline BitSet BitSet::operator~ ()
  161. {
  162.     return BitSet(*this).flip();
  163. }  

  164. //--- operation between two BitSet objects-----------------
  165. // bitwise AND
  166. inline BitSet& BitSet::operator&= (const BitSet& bit)
  167. {
  168.     if (m_bitNum != bit.m_bitNum)
  169.         throw std::length_error("Error: two BitSet objects have not equal lengths");
  170.     for (size_type i = 0; i < m_size; ++i)
  171.         m_pBits[i] &= bit.m_pBits[i];
  172.     return (*this);
  173. }

  174. // bitwise inclusive OR
  175. inline BitSet& BitSet::operator|= (const BitSet& bit)
  176. {
  177.     if (m_bitNum != bit.m_bitNum)
  178.         throw std::length_error("Error: two BitSet objects have not equal lengths");
  179.     for (size_type i = 0; i < m_size; ++i)
  180.         m_pBits[i] |= bit.m_pBits[i];
  181.     return (*this);
  182. }

  183. // bitwise exclusive OR
  184. inline BitSet& BitSet::operator^= (const BitSet& bit)
  185. {
  186.     if (m_bitNum != bit.m_bitNum)
  187.         throw std::length_error("Error: two BitSet objects have not equal lengths");
  188.     for (size_type i = 0; i < m_size; ++i)
  189.         m_pBits[i] ^= bit.m_pBits[i];
  190.     return (*this);
  191. }

  192. // equal: bitwise equal
  193. inline bool BitSet::operator== (const BitSet &bit) const
  194. {
  195.     if (m_bitNum != bit.m_bitNum)
  196.         return false;
  197.     for (size_type i = 0; i < m_size; ++i)
  198.         if (m_pBits[i] != bit.m_pBits[i])
  199.             return false;
  200.     return true;
  201. }

  202. // get the number of bits in this BitSet object
  203. inline BitSet::size_type BitSet::size() const
  204. {
  205.     return m_bitNum;
  206. }

  207. //--- nonmember functions -----------------------------------
  208. // left shift operator
  209. inline BitSet operator<< (const BitSet &bit, BitSet::size_type num)
  210. {
  211.     return BitSet(bit) <<= num;
  212. }

  213. // right shift operator
  214. inline BitSet operator>> (const BitSet &bit, BitSet::size_type num)
  215. {
  216.     return BitSet(bit) >>= num;
  217. }

  218. // bitwise AND
  219. inline BitSet operator& (const BitSet &lhs, const BitSet &rhs)
  220. {
  221.     return BitSet(lhs) &= rhs;
  222. }

  223. // bitwise inclusive OR
  224. inline BitSet operator| (const BitSet &lhs, const BitSet &rhs)
  225. {
  226.     return BitSet(lhs) |= rhs;
  227. }

  228. // bitwise exclusive OR
  229. inline BitSet operator^ (const BitSet &lhs, const BitSet &rhs)
  230. {
  231.     return BitSet(lhs) ^= rhs;
  232. }

  233. // not equal
  234. inline bool operator!= (const BitSet &lhs, const BitSet &rhs)
  235. {
  236.     return !(lhs == rhs);
  237. }

  238. // endif: BITSET_H
  239. #endif
复制代码


  1. // BitSet.cpp

  2. #include <iostream>
  3. #include <iomanip>
  4. #include <stdexcept>
  5. #include "BitSet.h"

  6. //--- bit operation ----------------------------------------
  7. void BitSet::leftShift(size_type num)
  8. {
  9.     // function: left-shift num bits
  10.     if (num >= m_bitNum) {
  11.         // when the number of bits asked to shift is more than
  12.         // that possessed by the object, just clear all the bits.
  13.         clear();
  14.         return ;
  15.     }

  16.     // compute the corresponding number of
  17.     // elements(ULONG) and the remaining bits
  18.     size_type eleNum = num / BLOCK_BITS;
  19.     size_type bitNum = num % BLOCK_BITS;
  20.    
  21.     // first left-shift eleNum elements
  22.     if (eleNum != 0) {
  23.         block_type* pTmp = new block_type[m_size];
  24.         if (pTmp == NULL)
  25.             throw std::bad_alloc();
  26.         memcpy(pTmp, m_pBits, (m_size - eleNum) * BLOCK_BYTES);
  27.         memcpy(m_pBits + eleNum, pTmp, (m_size - eleNum) * BLOCK_BYTES);
  28.         memset(m_pBits, 0, eleNum * BLOCK_BYTES);
  29.         delete [] pTmp;
  30.     }

  31.     // next, left-shift bitNum bits (1 <= bitNum <= ULONG_BITS - 1)
  32.     if (bitNum != 0) {
  33.         block_type *pTmp  = m_pBits + m_size - 1;
  34.         for ( ; pTmp > m_pBits; --pTmp) {
  35.             *pTmp = (*pTmp << bitNum) | (*(pTmp - 1) >> (BLOCK_BITS - bitNum));
  36.         }
  37.         *pTmp <<= bitNum;
  38.     }
  39.     m_pBits[m_size-1] &= m_mask;      // filter the redundant bits
  40. }

  41. void BitSet::rightShift(size_type num)
  42. {
  43.     // function: right-shift num bits
  44.     if (num >= m_bitNum) {
  45.         // when the number of bits asked to shift is more than
  46.         // that possessed by the object, just clear all the bits.
  47.         clear();
  48.         return ;
  49.     }

  50.     // compute the corresponding number of elements(ULONG) and remaining bits
  51.     size_type eleNum = num / BLOCK_BITS;
  52.     size_type bitNum = num % BLOCK_BITS;
  53.    
  54.     // first right-shift eleNum elements
  55.     if (eleNum != 0) {
  56.         block_type* pTmp = new block_type[m_size];
  57.         if (pTmp == NULL)
  58.             throw std::bad_alloc();
  59.         memcpy(pTmp, m_pBits + eleNum, (m_size - eleNum) * BLOCK_BYTES);
  60.         memcpy(m_pBits, pTmp, (m_size - eleNum) * BLOCK_BYTES);
  61.         memset(m_pBits + m_size - eleNum, 0, eleNum * BLOCK_BYTES);
  62.         delete [] pTmp;
  63.     }

  64.     // next, right-shift bitNum bits (1 <= bitNum <= ULONG_BITS - 1)
  65.     if (bitNum != 0) {
  66.         block_type *pTmp  = m_pBits;
  67.         for ( ; pTmp < m_pBits + m_size - 1; ++pTmp) {
  68.             *pTmp = (*pTmp >> bitNum) | (*(pTmp + 1) << (BLOCK_BITS - bitNum));
  69.         }
  70.         *pTmp >>= bitNum;
  71.     }
  72. }

  73. BitSet& BitSet::set(size_type pos, bool tagSet)
  74. {
  75.     // function: set the bit at position pos (beginning from 0) when tagSet is true;
  76.     //           otherwise, clear the bit.
  77.     if (pos >= m_bitNum)
  78.         throw std::out_of_range("Error: out of range in fuction set");
  79.    
  80.     // compute the corresponding index of elements(ULONG) and remaining bits
  81.     size_type eleIndex = pos / BLOCK_BITS;
  82.     size_type bitIndex = pos % BLOCK_BITS;
  83.    
  84.     block_type mask = 1;
  85.     mask <<= bitIndex;
  86.     if (!tagSet)
  87.         mask = ~mask;
  88.     m_pBits[eleIndex] = tagSet ? (m_pBits[eleIndex] | mask) : (m_pBits[eleIndex] & mask);
  89.     return (*this);
  90. }

  91. BitSet& BitSet::flip(size_type pos)
  92. {
  93.     // function: flip the bit at position pos
  94.     if (pos >= m_bitNum)
  95.         throw std::out_of_range("Error: out of range in fuction set");
  96.    
  97.     // compute the corresponding index of elements(ULONG) and remaining bits
  98.     size_type eleIndex = pos / BLOCK_BITS;
  99.     size_type bitIndex = pos % BLOCK_BITS;
  100.    
  101.     block_type mask = 1;
  102.     mask <<= bitIndex;
  103.     m_pBits[eleIndex] = (m_pBits[eleIndex] & mask) ? (m_pBits[eleIndex] & ~mask) : (m_pBits[eleIndex] | mask);
  104.     return (*this);
  105. }

  106. bool BitSet::test(size_type pos) const
  107. {
  108.     // function: test the bit at position pos.
  109.     // return:   If the bit is set, then return true; otherwise return false.
  110.     if (pos >= m_bitNum)
  111.         throw std::out_of_range("Error: out of range in fuction set");
  112.    
  113.     // compute the corresponding index of elements(ULONG) and remaining bits
  114.     size_type eleIndex = pos / BLOCK_BITS;
  115.     size_type bitIndex = pos % BLOCK_BITS;
  116.    
  117.     block_type mask = 1;
  118.     mask <<= bitIndex;
  119.     return m_pBits[eleIndex] & mask;
  120. }
复制代码

[ 本帖最后由 tyc611 于 2007-4-21 14:20 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2007-04-14 19:55 |只看该作者
贴一个用该类实现的算法:实现子集和数问题的判定性问题^_^


  1. #include <iostream>
  2. #include "BitSet.h"

  3. bool SubsetSum(ULONG *nums, int num, ULONG sum);

  4. int main()
  5. {
  6.     ULONG nums[6] = {5, 10, 12, 13, 15, 18};
  7.     std::cout << std::boolalpha << SubsetSum(nums, 6, 30) << std::endl;
  8.    
  9.     return 0;
  10. }

  11. bool SubsetSum(ULONG *nums, int num, ULONG sum)
  12. {
  13.     BitSet bit(sum + 1);
  14.     bit.set(0);
  15.     for (int i = 0; i < num; ++i) {
  16.         bit |= (bit << nums[i]);
  17.         if (bit.test(sum))
  18.             return true;
  19.     }
  20.     return false;
  21. }
复制代码

论坛徽章:
0
3 [报告]
发表于 2007-04-14 19:57 |只看该作者
不错。我就不多加评论了。

论坛徽章:
0
4 [报告]
发表于 2007-04-14 19:59 |只看该作者
原帖由 langue 于 2007-4-14 19:57 发表
不错。我就不多加评论了。

谢谢版主^_^

希望大家多多讨论^_^

论坛徽章:
0
5 [报告]
发表于 2007-04-14 20:27 |只看该作者
顶~

论坛徽章:
0
6 [报告]
发表于 2007-04-15 12:37 |只看该作者
hehe, 楼主在哪个项目用了bitset了?p2p2? bittorrent?

论坛徽章:
0
7 [报告]
发表于 2007-04-15 14:40 |只看该作者
不错不错,支持一把。

论坛徽章:
0
8 [报告]
发表于 2007-04-20 21:08 |只看该作者
支持楼主!


不过相同功能的Bitset类已经由Boost写出来了。
使用方法见:
http://www.boost.org/libs/dynamic_bitset/dynamic_bitset.html

论坛徽章:
0
9 [报告]
发表于 2007-04-20 22:28 |只看该作者
原帖由 doctorjxd 于 2007-4-20 21:08 发表
支持楼主!


不过相同功能的Bitset类已经由Boost写出来了。
使用方法见:
http://www.boost.org/libs/dynamic_bitset/dynamic_bitset.html

不知道有这东西呢,又做了无用功,权当练手
已经下了库回来,研究下它怎么移位的

论坛徽章:
0
10 [报告]
发表于 2007-04-21 01:12 |只看该作者
我来提几个建议吧,大家一起讨论:
考虑使用unsigned char代替unsigned long。
去掉所有的inline关键字。
把所有的typedef和常数放在class之内。
不要检查内存分配失败。
friend函数不必成为friend。
operator<<()是否应该为const?
考虑使用numeric_limits<unsigned long>::digits。
考虑提供命名操作,如and。
考虑提供swap操作。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP