【问题标题】:Return an array by looking up bits?通过查找位返回一个数组?
【发布时间】:2009-02-12 05:11:00
【问题描述】:

我有以下用例, 整数数组

vector<int>  containing elements 123 345 678  890 555 ...
                           pos    0   1   2    3   4

基于我收到的位表示,例如

101  then return 123 678 (Elements of the array with its position bits set)
0011  then return 678 890
00001  then return 555

你能推荐任何我可以用来解决这个问题的库吗?

编辑:向量本身是动态的,位大小可以根据想要返回相应数组元素的 1 位而变化。

【问题讨论】:

  • 总是返回两个值吗?价值观总是一样的吗?还是它们是由向量中的特定索引决定的?我认为您将不得不详细说明
  • 不可以是任意数量的值,向量大小是动态的
  • 从未提及。我想我现在很清楚它的作用。虽然很难弄清楚:)
  • 对不起,如果我的问题不清楚。
  • 我花了一段时间才明白这个问题是关于什么的。

标签: c++ c stl boost


【解决方案1】:

您最终希望将位集映射到它们的位索引。这很容易使用众所周知的小技巧:

bit_mask_iterator= bits;

while (bit_mask_iterator)
{
    long single_bit_set= bit_mask_iterator & -bit_mask_iterator;
    long bit_index= count_bits_set(single_bit_set - 1); // this is the index you want
    bit_mask_iterator&= bit_mask_iterator - 1;
}

count_bits_set 可以使用编译器内部或手动实现(请参阅http://www-graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel)。如果您愿意,也可以使用查找 single_bit_set 的 log2。

【讨论】:

    【解决方案2】:
    int bitMask = 11;  // 1011 (reverse the bitmask when it comes in)
    int count = 0;
    vector<int> myVector (4);
    vector<int> returnVector;
    
    myVector[0] = 123;
    myVector[1] = 356;
    myVector[2] = 678;
    myVector[3] = 890;
    
    while (bitMask)
    {
        if (bitMask & 0x01)
        {
            returnVector.push_back (myVector[count]);
        }
        count++;
        bitMask >>= 1;
    }
    

    【讨论】:

      【解决方案3】:

      我假设一个位掩码存储在一个容器中(以支持系统上超过sizeof(uintmax_t) 位的位掩码)。在这种情况下,解决方案的本质是:

      std::remove_copy_if(v.begin(), v.end(), std::back_inserter(out),
                          !*boost::lambda::var(pred)++);
      

      其中v - 输入向量; out - 存储结果的向量; pred - 位掩码上的迭代器。

      如果您想避开boost::lambda,那么很容易模拟:

      template <class InputIterator, class OutputIterator, class PredicateIterator>
      void copy_if(InputIterator first, InputIterator last, OutputIterator result,
                   PredicateIterator pred) {
        for ( ; first != last; ++first)
          if (*pred++)
            *result++ = *first;
      }
      

      可以按如下方式使用(使用与上例相同的符号):

      copy_if(v.begin(), v.end(), std::back_inserter(out), pred);
      

      或同样使用谓词:

      template <class Iterator>
      class Pred {
        Iterator it;
      public:
        Pred(Iterator it_) : it(it_) {}
        template <class T>
        bool operator ()(T /* ignore argument */) { return !*it++; }
      };
      template <class Iterator>
      Pred<Iterator> iterator2predicate(Iterator it) {
        return Pred<Iterator>(it);
      }
      

      可以这样使用:

      std::remove_copy_if(v.begin(), v.end(), std::back_inserter(out),
                          iterator2predicate(pred));
      

      示例(使用boost::lambda,但很容易被上面两个其他选项替换):

      /** g++ -Wall -Ipath/to/boost -o filter_array filter_array.cpp */
      #include <algorithm>
      #include <iostream>
      #include <iterator>     // back_inserter()
      #include <vector>    
      #include <boost/lambda/lambda.hpp>
      
      #define LEN(array) (sizeof(array) / sizeof(*(array)))    
      #define P(v) { std::for_each(v.begin(), v.end(),            \
                         std::cout << boost::lambda::_1 << " ");  \
                     std::cout << std::endl; }
      
      int main() {
        int a[] = {123, 345, 678, 890, 555,};
        const size_t n = LEN(a);
        bool bits[][n] = { 
          1, 0, 1, 0, 0,
          0, 0, 1, 1, 0,
          0, 0, 0, 0, 1,
        };
        typedef std::vector<int> Array;
        Array v(a, a + n);
        P(v);      
        for (size_t i = 0; i < LEN(bits); ++i) {
          Array out;
          std::vector<bool> b(bits[i], bits[i] + LEN(bits[i]));
          std::vector<bool>::const_iterator pred = b.begin();
          P(b);
          std::remove_copy_if(v.begin(), v.end(), std::back_inserter(out),
                              !*boost::lambda::var(pred)++);
          P(out);
        }
      }
      

      输出:

      123 345 678 890 555 
      1 0 1 0 0 
      123 678 
      0 0 1 1 0 
      678 890 
      0 0 0 0 1 
      555 
      

      【讨论】:

        【解决方案4】:

        这是一个快速而肮脏的解决方案

            vector<int> filtered;
        
            char *bits = "0011";
        
            for(int i = 0;i < sizeof(bits) ; i++)
              if(bit[i] == '1')
                filtered.push_back(myvector[i]);
        
            return  filtered
        

        【讨论】:

        • 嗯...向量没有 push_back...这就是为什么我建议将列表作为输出...
        • @diegosevilla: vector&lt;&gt; 对象确实有 .push_back() 方法。
        【解决方案5】:

        好的,您可以使用过滤迭代器稍微优雅一点。正如我在您的问题中看到的那样,数组上的索引以与数字相反的顺序开始(数字的位置“0”的索引对应于数组中的位置“3”)。因此,您必须反向查看数组以选择正确的元素。另外,由于返回值可能包含 0、1、2、3 或 4 个元素,我建议您返回一个列表。这是一个提示:

        struct filter
        {
            filter (int n) :number (n)
            {
            }
        
            bool operator()(int other_number)
            {
                    bool result = number & 1;
                    number>>=1;
                    return result;
            }
        
            int number;
        
        }; 
        
        
        int main(void)
        {
        using namespace std;
        
            vector<int> my_v (4);
            my_v[0] = 123;
            my_v[1] = 356;
            my_v[2] = 678;
            my_v[3] = 890;
        
            int bin_num = 10; // 1010
        
            list<int> out_list;
        
            std::copy(boost::make_filter_iterator (filter (bin_num),
                                                   my_v.rbegin(),
                                                   my_v.rend()),
                      boost::make_filter_iterator(filter (bin_num),
                                                  my_v.rend(), my_v.rend()),
                      std::front_inserter (out_list));
            // out_list will have 123 678
        
        }
        

        希望这会有所帮助,

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-11-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-03-01
          • 2022-12-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多