通过查找位返回一个数组?

时间:2009-02-12 05:11:01

标签: c++ c stl boost

我有以下用例, 整数数组

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位而变化。

5 个答案:

答案 0 :(得分:4)

您最终希望将设置的位映射到其位索引。使用众所周知的比特笨拙的黑客很容易:

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。

答案 1 :(得分:1)

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;
}

答案 2 :(得分:1)

我假设位掩码存储在容器中(以支持系统上位数超过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 

答案 3 :(得分:0)

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

    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

答案 4 :(得分:0)

好的,你可以使用过滤迭代器来做到这一点。正如我在你的问题上看到的那样,数组上的索引以与数字相反的顺序开始(数字的位置索引“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

}

希望这有帮助,