【问题标题】:Best way to iterate a subset of a 2dimensional grid迭代二维网格子集的最佳方法
【发布时间】:2012-11-29 01:14:11
【问题描述】:

我有一个二维矩形网格,我需要对这个网格中的节点子集应用不同的函数。子集由矩形边界给出,例如行和列分隔符。由于我不想一遍又一遍地用 2 个 for 循环对迭代进行编码,我正在考虑两种方法来解决这个问题:

首先创建一个自定义迭代器提供程序,该提供程序使用矩形限制进行初始化,然后在迭代时保留它们。虽然这是可行的,但要使这个迭代器兼容似乎还需要做很多工作。使用标准 stl 算法。

第二种方法是将函数指针传递给遍历for循环并在内部循环中执行的函数。这也是可行的,但可能会产生非常难看的语法,因为我必须传递成员函数。

通常哪种方式更可取?对于这样的用例,是否有任何干净的示例,以防止我重新发明轮子?

注意:由于代码频繁执行,因此该操作对性能非常关键

【问题讨论】:

  • 如果您能够描述如何选择子集,它们是否以某种方式相交或完全不同等,将会很有帮助。

标签: c++ algorithm iterator iteration


【解决方案1】:

为什么不直接将二维子集数组复制到一个临时数组,然后将指向数组开头的指针传递给不同的函数呢?

如果将同一个子集多次传递给不同的函数,它应该会减少缓存未命中,从而减少子集迭代所花费的时间。

【讨论】:

  • 一个词:性能。网格相当大 > 500.000 个节点,每个节点大约 50 字节。所以整个网格已经可以达到 20 MB 以上。此外,我需要访问几个 1000 个节点的子集大约 100 次,并且这些子集通常不相似。由于这部分程序已经是一个主要瓶颈(测量而不是猜测)我买不起副本。
【解决方案2】:

从设计的角度来看,我会说迭代器方法更好,因为它在循环体上的复杂性较低(并且可能会比迭代中的复杂性更高)。

但我希望使用仿函数方法获得更好的性能。特别是如果您将使用 STL 样式(带有预期 operator() 的模板参数)。

【讨论】:

    【解决方案3】:

    这里值得的是我最终实现的算法。代码不完整,但可能对其他人有用:

    //forward declarations
    template <typename T> class Grid;
    template <typename T> class rectIterator;
    
    //friend forward declarations
    template<class T>
    bool operator!=(rectIterator<T> const& left, rectIterator<T> const& right);
    
    
    template<class T>
    class rectIterator: public std::iterator<std::forward_iterator_tag, GridTile<T> >{
    
    public:
      typedef GridTile<T> const& const_reference;
      typedef GridTile<T>& reference;
      typedef GridTile<T> const* const_pointer;
      typedef GridTile<T>* pointer;
    
    private:
      Grid<T>* mpGrid;
      int mRow;
      int mCol;
      int mMinRow;
      int mMinCol;
      int mMaxRow;
      int mMaxCol;
    
    
    public:
      rectIterator(Grid<T>& grid,Rectangle const& rect):
        mpGrid(&grid){
        mpGrid->getRowCol(mpGrid->getTileId(rect.bottomLeft()),mMinRow,mMinCol);
        mpGrid->getRowCol(mpGrid->getTileId(rect.topRight()),mMaxRow,mMaxCol);
        mRow = mMinRow;
        mCol = mMinCol;
      }
    
      rectIterator():
        mpGrid(0){
        mMinRow= -1;
        mMinCol=-1;
        mMaxRow =-1;
        mMaxCol =-1;
        mCol = 0;
        mRow = 0;
      }
    
      rectIterator<T>& operator++(){
        if(mCol<=mMaxCol){
          ++mCol;
        }else if(mRow<=mMaxRow){
          ++mRow;
          mCol = mMinCol;
        }else{
          mCol = mpGrid->getCols();
          mRow = mpGrid->getRows();
          mpGrid=0;
        }
        return *this;
      }
    
      reference operator*() const throw(std::out_of_range, std::runtime_error){
        return mpGrid->at(mRow,mCol);
      }
    
      pointer operator->() const throw(std::out_of_range, std::runtime_error){
        return &(mpGrid->at(mRow,mCol));
      }
    
      int row()const{
        return mRow;
      }
    
      int col()const{
        return mCol;
      }
    
      friend bool operator!=<>(rectIterator<T> const& left, rectIterator<T> const& right);
    
    };
    
    template<class T>
    bool operator!=  (rectIterator<T> const& left, rectIterator<T> const& right){
      return (left.mpGrid != right.mpGrid);
      //DIRTY this is no full compare but fast and sufficient at the moment
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-06
      • 1970-01-01
      • 2018-10-17
      • 2022-01-17
      • 1970-01-01
      相关资源
      最近更新 更多