c++ 如何获取std::vector的迭代器的索引?

zkure5ic  于 2023-05-20  发布在  其他
关注(0)|答案(9)|浏览(240)

我迭代一个向量,需要迭代器当前指向的索引。以下方法的优缺点是什么?

  • it - vec.begin()
  • std::distance(vec.begin(), it)
5jdjgkvh

5jdjgkvh1#

我更喜欢it - vec.begin(),因为Naveen给出了相反的理由:所以如果你把vector变成一个列表,它就不会被编译。如果你在每次迭代中都这样做,你很容易将一个O(n)算法变成一个O(n^2)算法。
另一种选择是,如果在迭代过程中不在容器中跳转,则将索引作为第二个循环计数器。
注意:it是容器迭代器std::container_type::iterator it;的通用名称。

9njqaruj

9njqaruj2#

我更喜欢std::distance(vec.begin(), it),因为它允许我在不更改任何代码的情况下更改容器。例如,如果您决定使用std::list而不是不提供随机访问迭代器的std::vector,您的代码仍然可以编译。由于std::distance根据迭代器特性选择最佳方法,因此您也不会有任何性能下降。

ars1skjm

ars1skjm3#

正如UncleBens和Naveen所表明的那样,两者都有很好的理由。哪一个“更好”取决于你想要什么样的行为:您是希望保证恒定时间行为,还是希望在必要时回退到线性时间?
it - vec.begin()需要恒定的时间,但是operator -只定义在随机访问迭代器上,所以代码根本不会编译列表迭代器。
std::distance(vec.begin(), it)适用于所有迭代器类型,但如果用于随机访问迭代器,则仅为常数时间操作。
两者都不是“更好”。用你需要的那个。

pwuypxnk

pwuypxnk4#

我喜欢这个:it - vec.begin(),因为对我来说它清楚地说“从开始的距离”。对于迭代器,我们习惯于从算术的Angular 来思考,所以-符号是这里最清晰的指示符。

s71maibg

s71maibg5#

如果你已经限制/硬编码了你的算法,只使用std::vector::iteratorstd::vector::iterator,那么最终使用哪种方法并不重要。您的算法已经具体化,超出了选择其中一个可以产生任何差异的点。他们俩做的是完全一样的事情。这只是个人喜好的问题。我个人会使用显式减法。
另一方面,如果你想在你的算法中保持更高程度的通用性,也就是说,允许将来某一天它可能被应用到其他迭代器类型,那么最好的方法取决于你的意图。这取决于您希望对这里可以使用的迭代器类型有多严格的限制。

  • 如果你使用显式减法,你的算法将被限制在一个相当狭窄的迭代器类中:随机访问迭代器。(这是你现在从std::vector得到的)
  • 如果你使用distance,你的算法将支持更广泛的迭代器类:输入迭代器。

当然,在一般情况下,计算非随机访问迭代器的distance是一种低效的操作(而对于随机访问迭代器,它与减法一样有效)。这取决于你决定你的算法是否对非随机访问迭代器有意义,效率方面。如果由此导致的效率损失是毁灭性的,以至于你的算法完全无用,那么你最好坚持减法,从而禁止低效的使用,并迫使用户寻找其他迭代器类型的替代解决方案。如果非随机访问迭代器的效率仍然在可用范围内,那么应该使用distance,并证明该算法在随机访问迭代器上工作得更好。

1cosmwyk

1cosmwyk6#

根据http://www.cplusplus.com/reference/std/iterator/distance/,由于vec.begin()是一个 * 随机访问 * 迭代器,因此距离方法使用-运算符。
所以答案是,从性能的Angular 来看,这是一样的,但如果有人必须阅读和理解您的代码,那么使用distance()可能更容易理解。

ny6fqffe

ny6fqffe7#

我只对std::vector使用-变体--它的含义非常清楚,而且操作的简单性(不超过指针减法)由语法(另一方面,distance听起来像毕达哥拉斯,不是吗?正如UncleBen所指出的,-还充当了一个静态Assert,以防vector意外更改为list
我也认为这是更常见的-没有数字来证明这一点,虽然。主参数:it - vec.begin()的源代码更短-输入工作更少,占用的空间更少。很明显,你的问题的正确答案归结为品味问题,这也可以是一个有效的论点。

fnatzsnv

fnatzsnv8#

我刚发现这个:https://greek0.net/boost-range/boost-adaptors-indexed.html

for (const auto & element : str | boost::adaptors::indexed(0)) {
        std::cout << element.index()
                  << " : "
                  << element.value()
                  << std::endl;
    }
blmhpbnm

blmhpbnm9#

除了int float字符串等,当使用diff时,你可以把额外的数据放在.second中。类型如:

std::map<unsigned long long int, glm::ivec2> voxels_corners;
std::map<unsigned long long int, glm::ivec2>::iterator it_corners;

struct voxel_map {
    int x,i;
};

std::map<unsigned long long int, voxel_map> voxels_corners;
std::map<unsigned long long int, voxel_map>::iterator it_corners;

long long unsigned int index_first=some_key; // llu in this case...
int i=0;
voxels_corners.insert(std::make_pair(index_first,glm::ivec2(1,i++)));

long long unsigned int index_first=some_key;
int index_counter=0;
voxel_map one;
one.x=1;
one.i=index_counter++;

voxels_corners.insert(std::make_pair(index_first,one));

正确类型||结构中,你可以在.second中放入任何东西,包括一个在插入时递增的索引号。
而不是

it_corners - _corners.begin()

std::distance(it_corners.begin(), it_corners)

之后

it_corners = voxels_corners.find(index_first+bdif_x+x_z);

索引简单地是:

int vertice_index = it_corners->second.y;

使用glm::ivec2类型时

int vertice_index = it_corners->second.i;

在结构数据类型的情况下

相关问题