繁体   English   中英

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

[英]How do I get the index of an iterator of an std::vector?

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

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

我更喜欢it - vec.begin()正是因为 Naveen 给出的相反原因:所以如果你将向量更改为列表,它就不会编译。 如果你在每次迭代中都这样做,你很容易最终将 O(n) 算法变成 O(n^2) 算法。

另一种选择是,如果您在迭代期间不在容器中跳转,则将索引保留为第二个循环计数器。

注意: it是容器迭代器的通用名称, std::container_type::iterator it; .

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

正如 UncleBens 和 Naveen 所表明的那样,两者都有充分的理由。 哪个“更好”取决于您想要什么行为:您想保证恒定时间行为,还是希望它在必要时回退到线性时间?

it - vec.begin()需要固定时间,但operator -仅在随机访问迭代器上定义,因此代码根本无法使用列表迭代器编译。

std::distance(vec.begin(), it)适用于所有迭代器类型,但如果用于随机访问迭代器,则只会是恒定时间操作。

没有一个是“更好”的。 使用能满足您需求的那个。

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

如果您已经将您的算法限制/硬编码为仅使用std::vector::iteratorstd::vector::iterator ,那么最终使用哪种方法并不重要。 您的算法已经具体化,超出了选择另一个可以产生任何影响的程度。 他们都做同样的事情。 这只是个人喜好问题。 我个人会使用显式减法。

另一方面,如果您希望在算法中保留更高程度的通用性,即允许将来某天将其应用于其他迭代器类型,那么最佳方法取决于您的意图. 这取决于您希望对可在此处使用的迭代器类型的限制程度。

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

  • 如果您使用distance ,您的算法将支持更广泛的迭代器类:输入迭代器。

当然,计算非随机访问迭代器的distance通常是一种低效的操作(而对于随机访问的迭代器,它与减法一样有效)。 由你来决定你的算法是否对非随机访问迭代器有意义,效率方面。 如果由此导致的效率损失是毁灭性的,以至于使您的算法完全无用,那么您应该更好地坚持减法,从而禁止低效使用并迫使用户为其他迭代器类型寻求替代解决方案。 如果非随机访问迭代器的效率仍在可用范围内,那么您应该使用distance并记录该算法对随机访问迭代器的效果更好的事实。

根据http://www.cplusplus.com/reference/std/iterator/distance/ ,由于vec.begin()随机访问迭代器,因此距离方法使用-运算符。

所以答案是,从性能的角度来看,它是相同的,但如果有人必须阅读和理解您的代码,使用distance()可能更容易理解。

我只对std::vector使用-变体 - 它的含义很清楚,并且操作的简单性(不超过指针减法)由语法( distance ,在另一边,听起来像一读时的毕达哥拉斯,不是吗?)。 正如 UncleBen 指出的那样, -也充当静态断言,以防vector意外更改为list

此外,我认为它更为常见——不过,没有数字可以证明这一点。 主要论点: it - vec.begin()在源代码中更短 - 更少的打字工作,更少的空间消耗。 很明显,您问题的正确答案归结为品味问题,这可能是一个有效的论点。

我刚刚发现了这个: 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;
    }

除了 int float string 等,您可以在使用 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;

在结构数据类型的情况下

这是一个查找“所有”出现的 10 以及索引的示例。 认为这会有所帮助。

void _find_all_test()
{
    vector<int> ints;
    int val;
    while(cin >> val) ints.push_back(val);

    vector<int>::iterator it;
    it = ints.begin();
    int count = ints.size();
    do
    {
        it = find(it,ints.end(), 10);//assuming 10 as search element
        cout << *it << " found at index " << count -(ints.end() - it) << endl;
    }while(++it != ints.end()); 
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM