【问题标题】:STL Compliant iterator for two arrays两个数组的 STL 兼容迭代器
【发布时间】:2013-04-15 14:51:25
【问题描述】:

我想按以下方式对两个大小相同的数组 a 和 b 进行排序:数组 b 的排序方式与数组 a 的排序方式相同。示例输入:

a = {3, 1, 5}
b = {2, 6, 4}

举例

a = {1, 3, 5}
b = {6, 2, 4}

使得 b 的值与其重新排序无关,而是遵循数组 a 的重新排序。

我想使用 stl::sort 来执行此操作,并且我需要尽可能高效地执行此操作。因此,我不想将所有元素复制到结构中或使用索引对数组进行排序,然后我可以使用该索引对数组 a 和 b 进行排序。我认为开销最小的应该是 RandomAccessIterator (因为排序需要随机访问)。现在我的问题是,我真的不太擅长 C++。如果有人可以在菜鸟可以理解的水平上给我提示,我会很高兴。我找到了一些解决方案:

Sorting two corresponding arrays,但是两个提议的解决方案似乎都不够性能,

http://www.stanford.edu/~dgleich/notebook/2006/03/sorting_two_arrays_simultaneou.html 它使用了我认为违反 stl 的 boost 内容(老实说,我不了解那里使用的所有模板内容,我有一个 double 和一个 int 数组以及两者的大小 n,所以我不要认为我需要模板),最后是这个

http://www.c-plusplus.de/forum/313698-full 解决方案我被困在我不知道如何实现 operator-> 和 operator* 因为我不知道我是否只能返回一个值(来自数组 a 的值),即,如果此值仅用于比较或分配值。该线程中的解决方案还比较了比较运算符的指针值,我不确定这是否正确(不应该是指针后面的值吗?)。

这是我到目前为止所拥有的,如果你看到可怕的菜鸟错误,请告诉我我哪里出错了:)

#include "DoubleArrayRAccIterator.h"


DoubleArrayRAccIterator::~DoubleArrayRAccIterator() {
    // TODO Auto-generated destructor stub
}
struct doubleValue{
    double* a_val;
    int* b_val;
};

double::DoubleArrayRAccIterator::DoubleArrayRAccIterator(double& a_arr,int& b_arr, int size) {
    a_begin = &a_arr;
    b_begin = &b_arr;
    a = &a_arr;
    b = & b_arr;
    n = size;
}

DoubleArrayRAccIterator::DoubleArrayRAccIterator() {
    a = 0;
    b = 0;
    n = 0;
}

DoubleArrayRAccIterator::DoubleArrayRAccIterator(const DoubleArrayRAccIterator& it) {
    a = it.a;
    b = it.b;
    n = it.n;
}

DoubleArrayRAccIterator& DoubleArrayRAccIterator::operator=(const DoubleArrayRAccIterator& it) {
    a = it.a;
    b = it.b;
    n = it.n;
    return *this;
}

DoubleArrayRAccIterator& DoubleArrayRAccIterator::operator++() {
    ++a;
    ++b;
    return *this;
}


DoubleArrayRAccIterator& DoubleArrayRAccIterator::operator--() {
    --a;
    --b;
    return *this;
}

DoubleArrayRAccIterator DoubleArrayRAccIterator::operator++(int) {
    DoubleArrayRAccIterator it(*this);
    ++a;
    ++b;
    return it;
}


DoubleArrayRAccIterator DoubleArrayRAccIterator::operator--(int) {
    --a;
    --b;
    return *this;
}

DoubleArrayRAccIterator& DoubleArrayRAccIterator::operator+=(diff_type x) {
    a += x;
    b += x;
    return *this;
}


DoubleArrayRAccIterator& DoubleArrayRAccIterator::operator-=(diff_type x) {
    a += x;
    b += x;
    return *this;
}

DoubleArrayRAccIterator DoubleArrayRAccIterator::operator+(diff_type x) const {
    a += x;
    b += x;
    return *this;
}


typename DoubleArrayRAccIterator DoubleArrayRAccIterator::operator-(diff_type x) const {
    a -= x;
    b -= x;
    return *this;
}


DoubleArrayRAccIterator DoubleArrayRAccIterator::operator+(const DoubleArrayRAccIterator& it) const {
    a += it.a;
    b += it.b;
    return *this;
}


DoubleArrayRAccIterator DoubleArrayRAccIterator::operator-(const DoubleArrayRAccIterator& it) const {
    a -= it.a;
    b -= it.b;
    return *this;
}


DoubleArrayRAccIterator::reference DoubleArrayRAccIterator::operator*() const {
    // this MUST be wrong, only return value of array a?
    doubleValue result;
    result.a_val=a;
    result.b_val=b;
    return *result;
}

DoubleArrayRAccIterator::pointer DoubleArrayRAccIterator::operator->() const {
    // this MUST be wrong, only return value of array a?
    doubleValue result;
    result.a_val=a;
    result.b_val=b;
    return &result;
}


DoubleArrayRAccIterator::reference DoubleArrayRAccIterator::operator[](diff_type x) const {
    // this MUST be wrong, only return value of array a?
    doubleValue result;
    result.a_val=a_begin+x;
    result.b_val=b_begin+x;
    return *result;
}


bool DoubleArrayRAccIterator::operator==(const DoubleArrayRAccIterator& it) const {
    return a == it.a;
    //compare indices or values here?
}


bool DoubleArrayRAccIterator::operator!=(const DoubleArrayRAccIterator& it) const {
    return a != it.a;
    //compare indices or values here?
}


bool DoubleArrayRAccIterator::operator<(const DoubleArrayRAccIterator& it) const {
    //compare indices or values here?
}


bool DoubleArrayRAccIterator::operator>(const DoubleArrayRAccIterator& it) const {
    //compare indices or values here?
}


bool DoubleArrayRAccIterator::operator<=(const DoubleArrayRAccIterator& it) const {
    //compare indices or values here?
}


bool DoubleArrayRAccIterator::operator>=(const DoubleArrayRAccIterator& it) const {
    //compare indices or values here?
}


DoubleArrayRAccIterator begin() {
    return DoubleArrayRAccIterator(a_begin, b_begin, n);
}


DoubleArrayRAccIterator end() {
    return DoubleArrayRAccIterator(a_begin + n, b_begin + n, n);
}

如果有人还没有停止阅读并且仍然有耐心,我对我刚刚从这里 http://www.c-plusplus.de/forum/313698-full 复制的“diff_type”、“reference”和“pointer”类型感到困惑,它们应该是什么?

【问题讨论】:

  • 普通指针随机访问迭代器。你可能只是使用它们。
  • 您好,Arne,感谢您的回复。我想将迭代器传递给排序函数,为了对两个数组进行排序,我需要同时遍历两个数组。
  • 我明白了,我在第一次阅读您的问题时并不太清楚 - 请忘记我的评论;)
  • 你可能想看看 boost.operators,尤其是他们提供的迭代器助手——他们会为你定义大部分的操作符,typedef 等等。 wrt 取消引用运算符:是的,您应该(并且可以)只返回一个指向两个元素之一的指针。您可以模板化您的迭代器类,让运算符返回指向第一个或第二个元素的指针。
  • 我很难理解这句话 - “数组 b 的排序方式与数组 b 的排序方式相同”。你能澄清一下你的意思吗?

标签: c++ stl iterator


【解决方案1】:

如果我理解正确的话,你有这种情况:

[a1][a2][a3]....[an]
[b1][b2][b3]....[bn]

你想按数组a排序,这两个数组的方式一样,所以结果是:

[ax1][ax2][ax3]....[axn]
[bx1][bx2][bx3]....[bxn]

其中xi 两个数组的索引相同。

考虑这个例子:

class SIter {
public:


   SIter(int* aIter, double* bIter) : aIter(aIter), bIter(bIter) {}

  // we move to next position is just moving both:
  SIter& operator ++() {
     ++aIter; ++bIter;
     return *this;
  }
  SIter operator ++(int) {
     SIter rv = *this;
     ++aIter; ++bIter;
     return rv;
  }
  SIter& operator --() {
     --aIter; --bIter;
     return *this;
  }
  SIter operator --(int) {
     SIter rv = *this;
     --aIter; --bIter;
     return rv;
  }
  SIter operator + (std::ptrdiff_t cc) const
  {
      SIter rv = *this;
      rv.aIter += cc;
      rv.bIter += cc;
      return rv;
  }
  SIter operator - (std::ptrdiff_t cc) const
  {
      SIter rv = *this;
      rv.aIter -= cc;
      rv.bIter -= cc;
      return rv;
  }
  std::ptrdiff_t operator - (SIter other) const
  {
      return aIter - other.aIter;
  }
   struct value_type {
      int a; double b;
      bool operator < (const value_type& other) const {
          return a < other.a; // this is the place where way of sorting is defined!!!!
      }
   };
  struct reference {
     int* a;
     double* b;
     reference& operator = (const value_type& o) 
     {
       *a = o.a;
       *b = o.b;
       return *this;
     }
     operator value_type() const {
         value_type rv = { *a, *b };
         return rv;
     }
     reference& operator = (const reference& other)
     {
        *a = *other.a;
        *b = *other.b;
        return *this;
     }
     bool operator < (const reference& other) const {
        return *a < *other.a; 
     }
     bool operator < (const value_type& other) const {
        return *a < other.a; 
     }
  };

  reference operator * () {
     reference rv = { aIter, bIter };
     return rv;
  }
  bool operator == (const SIter& other) const
  {
      return aIter == other.aIter; // don't need to compare bIter - shall be in sync
  }
  bool operator != (const SIter& other) const
  {
      return aIter != other.aIter; // don't need to compare bIter - shall be in sync
  }
  bool operator < (const SIter& other) const
  {
      return aIter < other.aIter; // don't need to compare bIter - shall be in sync
  }
  // I bet you don't need pointer operator -> ()
   typedef std::random_access_iterator_tag iterator_category;
   typedef std::ptrdiff_t difference_type;
   typedef reference pointer;


private:
  int* aIter; 
  double* bIter;
};

然后像这样使用:

int main() {
   int a[100] = {};
   double b[100] = {};

   SIter beginIter(a, b);
   SIter endIter(a + 100, b + 100);

   std::sort(beginIter, endIter);

}

我没有尝试这个,可能它有一些缺点,但你应该朝这个方向走。您的迭代器应包含两个指向您的数组的指针(以更一般的方式 - 指向您的容器的迭代器),并且您的引用类型应具有 operator =operator &lt;,它们将能够分配两个数组的元素并仅比较元素一个数组。

[更新]

好消息:我做了一个工作示例:ideone

【讨论】:

  • 对于比 int 和 double 类型更通用的数组,性能改进是定义 swap(const reference &, const reference &) 并在两个成员上使用 swap,从而避免复制昂贵的物品。
【解决方案2】:

我对您的问题有点困惑,但是由于您链接到this 问题,我假设您正在尝试解决与该问题相同的问题,即您想要对数组a 进行排序并且您想要索引b 的数组以与 a 相同的方式重新排列。

这听起来像是XY Problem。如果可能的话,重新设计你的代码,这样你就没有parallel arrays。相反,将a 的每个元素与其对应的b 元素放在一个类或std::pair 中,将那些 放入一个集合(如数组或向量)中,然后对其进行排序(可能重载比较运算符(如果需要)。

【讨论】:

  • 感谢您的回答!我同意这将是最干净的解决方案,不幸的是,这对我的问题来说是不可行的,因为这意味着更改大量代码,因为这些数组在多个位置使用。数十年的遗留代码;)
  • 我不知道我是否可以通过“联合”将数组的相应元素解释为一对以避免更改数据,这也可以解决我的问题,但我的 C++ 还不够好估计。我的猜测是这是不可能的,因为两个对应的元素不在相邻的内存位置。排序已经是系统中的热点,所以我想避免做任何额外的操作。
猜你喜欢
  • 2021-02-14
  • 2013-07-01
  • 2021-03-28
  • 2013-04-16
  • 1970-01-01
  • 2011-12-25
  • 1970-01-01
  • 2011-07-24
  • 1970-01-01
相关资源
最近更新 更多