迭代器性能的重点应该放在高级还是元素访问上

Should the focus regarding iterator performance be in advancement or element access?

本文关键字:高级 元素 访问 性能 迭代器      更新时间:2023-10-16

问题

我有一个矩阵类,它连续存储对称矩阵。由于这些矩阵具有轴对称的良好性质(相对于对角线上的镜像),存储可以被优化为上三角矩阵或下三角矩阵。

下面的方案指示作为上三角矩阵存储的6x6对称矩阵的存储方案。

r\c 0 1 2 3 4 5-------------------------------------0|0|1|2|3|4|5|-------------------------------------1||6|7|8|9|10|-------------------------------------2|||11|12|13|14|-------------------------------------3||||15|16|17|-------------------------------------4|||||18|19|-------------------------------------5 ||||20|-------------------------------------

现在,我想为该矩阵的行和列设计一个迭代器。我不想迭代实际的行和列,而是迭代几乎完全对称矩阵的行和行。

Exmaple:

for (the_iterator i=matrix.row(2).begin(); i!=matrix.row(2).end(); ++i)
{
    cout << *i << " ";
}

这应该打印元素的内容

2 7 11 12 13 14

(如果矩阵是如上所示的6x6三角形矩阵)。

幸运的是,在对称矩阵的情况下,行i的序列等于列i的序列,所以我只需要一个迭代器类型。

矩阵类提供了一种根据元素的行和列索引访问元素的方法

reference operator() (size_type const r, size_type const c) { /*...*/ }

关于如何设计迭代器,我有两个想法。将数学从一个点切换到另一个点。

1.使用矩阵引用轻松推进迭代器

一方面,我可以存储对矩阵的引用、所需行/列的编号以及该行/列中的当前元素。

matrix_type & m;
size_type fixed;
size_type free;

这将允许使用我的矩阵类的operator()来解引用,以及方便的迭代器推进。

class the_iterator
  // ...
{
  // ...
  reference operator* () const _NOEXCEPT 
  { 
    return *m(fixed, free);
  }
  // ...
  this_type & operator++ (void) _NOEXCEPT
  { // increment then return
    ++free;
    return *this; 
  }
  // ...
};

这有一个明显的缺点:每次调用operator()都需要使用行和列索引来计算底层内存中的连续索引。

2.使用指向元素的指针轻松取消引用

另一方面,可以具有指针p(矩阵值类型元素指针)和一些控制值来控制迭代器前进。在垂直部分(2->7->11;参考上面的例子),指针需要前进5+4,而在水平部分(11->12->13->14),pointer需要改变1+1+1。这不是琐碎的,但也不是很难,并且可以在不迭代的情况下以代数方式解决。

取消引用/元素访问不再与任何计算相关联,因为可以使用*p。这就是我目前的做法。

问题是:

我应该在哪里进行"计算工作",你会走哪条路(为什么)?

我可以有

  • 简单快速的迭代器前进,但要求元素访问或
  • 要求先进,但元件访问简单快捷

我倾向于第二个,因为迭代器很可能每个周期只前进一次(在循环中),而它可能会被多次取消引用。

除非您真的、真的需要像您的示例中那样排列数据,否则我会首先利用三角形数组的基本特性来加快索引。这将使您的第一选择变得更好:存储对矩阵、固定行/列和当前空闲索引值的引用,并依靠快速索引来提高性能。

我知道的最简单的单位三角矩阵索引映射是:

int unitriangular_index(int row, int col)
{
    assert(row >= 0);
    assert(col >= row);
    int base = (col * (col + 1)) / 2;
    return (base + row);
}

如果你可以这样排列值,访问矩阵的一个切片看起来像:

int reflected_index(int row, int col)
{
    assert(row >= 0);
    assert(col >= 0);
    if (col < row)
    {
        return (unitriangular_index(col, row));
    }
    else
    {
        return (unitriangular_index(row, col));
    }
}