为 C++ 选择 begin() 和 end()

Posted

技术标签:

【中文标题】为 C++ 选择 begin() 和 end()【英文标题】:Selecting the begin() and end() for C++ 【发布时间】:2018-02-13 12:16:15 【问题描述】:

我有一个项目要求我按特定列从 .csv 文件读取值并对其进行排序。 我在 C++ 中使用算法库,即#include <algorithm> 该库具有我计划使用的功能sort()。 它要求我指定开始和结束,例如,对于一个名为 vect 的 2d 向量,它需要 vect.begin()vect.end()。 我的问题是,是否可以为 sort() 函数指定确切的开始位置和结束位置。这就像从 vect[1][0] 开始并在 vect[9][9] 结束。

感谢您的帮助

【问题讨论】:

你不能std::sort 2D 向量/数组。你希望这样做会有什么结果? 如果vect.begin()是向量的第一个元素(假设它不为空),那么你认为vect.begin() + 1是什么? 对列进行间接排序,然后使用索引访问行。在此处查看示例:***.com/questions/48764471/… @HolyBlackCat 好吧,当我根据一列对值进行排序时,它确实有效,尽管它也将表格的标题移到了底部,这就是我试图避免的 @HolyBlackCat :当然你可以对二维向量进行排序。向量的排序向量的自然定义是结果具有按字典顺序存储的内部向量(因此 [[4, 5, 6], [1, 2, 3], [1, 2, 4]] 将是输出为 [[1, 2, 3], [1, 2, 4], [4, 5, 6]])。当然,实际上,std::vector 没有定义 operator <。无论如何,OP 都需要一个客户比较函子来选择列。 【参考方案1】:

为了便于讨论,我假设您正在使用std::vector<std::vector<int> >。同样的讨论也适用于其他类型的二维向量。

如果您想对单个 ints 进行排序,以便它们在 std::vector<std::vector<int> > 中排序,则无法直接进行。没有可以直接从 std::vector<std::vector<int>> 获得的迭代器,它运行在所有嵌套的 ints 上。

一种方法可能是在std::vector<int> 中设置一个临时副本(即创建一个扁平的一维向量),对其进行排序,然后将元素复制回来。例如;

 std::vector<std:vector<int> > vec;

   // populate vec somehow

 std::vector<int> elements(0);

 // create a single std::vector<int> from the vector<vector<int>> by
 //    appending the vector<int>s end to end

 for (const auto &row : vec)
 
      elements.insert(elements.end(), row.begin(), row.end());
 

 std::sort(elements.begin(), elements.end());   // sort in ascending order

 //   now copy the sorted elements back

 auto start = elements.begin();

 for (auto &row : vec)   //  non-const here since we seek to change the vector<int>s within vec
 
      auto end = start + row.size();
      std::copy(start, end, row.begin());
      start = end;
 

最后一个循环中row.size()row.begin() 的恶作剧处理了vec 中的vector&lt;int&gt; 大小不同的可能性,因此会发生变化

 5,6,7, 1,2, 3,4,8

成为

 1,2,3, 4, 5, 6,7,8

而不是其他东西,例如

 1,2, 3,4,5, 6, 7, 8;     //   vector<int>s resized

如果您假设所有内部向量的大小相同,则可以稍微简化一下。

或者,您可以尝试手动滚动 struct/class 类型,该类型具有随机访问迭代器的所有属性(这是 std::sort() 所要求的)。该结构(或其成员函数/运算符)将需要同时跟踪 std::vector&lt;int&gt;(在 2D 向量内)和它所引用的该向量内的特定 int。这将是相当棘手的(例如,如果自定义迭代器引用特定 std::vector&lt;int&gt; 的最后一个元素,递增它必须给出引用下一个 vector&lt;int&gt; 的第一个元素的结果)。 std::vector&lt;std::vector&lt;int&gt; &gt; 根本没有任何内置功能可以直接为您提供这样的迭代器。我将滚动这样一个自定义迭代器作为练习。

【讨论】:

【参考方案2】:

鉴于您知道迭代的顺序,您可以指定相对于开始的元素。

vect.begin()     // first element
vect.begin() + 2 // third element

因此,如果您只想对第一个元素进行排序,比如说 10 个元素,请使用以下内容:

std::sort(vect.begin(), vect.begin() + 10);

更多here.

正如其他人已经提到的,您不能真正对 2D 矢量进行排序。因此,您要么单独对每个向量进行排序,要么将其展平为 1D 向量并使用索引计算进行 2D 解释。

【讨论】:

那么,考虑到我想防止列标题和行号不被排序,我将如何将 2D 向量展平为 1D 并将其带回 2D。我使用了sort(vect.begin() + 1, vect.end()),它阻止了对列名进行排序,但仍然对行号进行排序。 谢谢 您不想一直切换数据布局。我想到的是例如如果您有一个 NxN 矩阵,则将其存储在大小为 NxN 的一维向量 v 中。要访问位置 i/j 处的元素,您将使用 v[i * N + j]。如果这不符合您的想法,可以提供您拥有的矩阵以及您希望如何对其进行排序的示例。【参考方案3】:
    将排序依据的列加载到std::vector&lt; std::pair &gt; index; 并设置 作为向量行索引的第一个元素 (0,1,2,...) 第二个元素将是行和列中的值 使用此问题按配对的第二项对其进行排序:How do I sort a vector of pairs based on the second element of the pair? 现在您有了按向量 中的列值排序的行索引,您可以创建新的二维向量并使用原始二维向量中的行填充其行。在每次迭代中,使用index 向量中的第一项选择原始二维向量中具有索引的行。

【讨论】:

以上是关于为 C++ 选择 begin() 和 end()的主要内容,如果未能解决你的问题,请参考以下文章

C++ begin( ) cbegin( ) end() cend()区别

兼容性IE10不支持参数默认值即可选参数

排序算法:选择排序和冒泡排序

排序算法:选择排序和冒泡排序

排序算法:选择排序和冒泡排序

排序算法:选择排序和冒泡排序