【问题标题】:Copying from one dimensional vector vector<int> starts to first element of two dimensional vector pair vector<pair<int,int>>matrix从一维向量vector<int>开始复制到二维向量对vector<pair<int,int>>matrix的第一个元素
【发布时间】:2020-07-08 15:41:45
【问题描述】:

我有多个 3 个一维向量 (vector&lt;int&gt; starts, vector&lt;int&gt; ends, vector&lt;int&gt; points)。每个都有特定数量的元素。

我想以这样的顺序创建一个二维向量vector&lt;pair&lt;int,int&gt;&gt;matrix

  1. matrix的开头到start的大小第一个元素matrixvector&lt;int&gt; starts的元素,第二个元素是“-1”
  2. 现在将vector&lt;int&gt; ends 的元素附加到matrix,这样matrix第一个 元素是vector&lt;int&gt; ends 的元素,第二个 元素是“-2 "
  3. 现在将vector&lt;int&gt; points 的元素附加到matrix,这样matrixfirst 元素是vector&lt;int&gt; points 的元素,second 元素是点的索引.

    视觉表现:-

    输入:

    开始:{1, 2, 3} 结束:{4, 5, 6} 积分:(7, 8, 9}

    输出:

    矩阵:{ {1, -1}, {2, -1}, {3, -1}, {4, -2}, {5, -2}, {6, -2}, {7, 0}, {8, 1}, {9, 2} }

目前我正在使用带有 for-loop 函数的 push_back,它工作得非常好,但是当输入大小很大时,代码非常慢。

我使用的代码如下:

vector<pair<int,int>> fast_count_segments(
    vector<int> starts, 
    vector<int> ends, 
    vector<int> points) 
{
   int i = 0;
   vector<pair<int,int>>matrix;

   for(i; i<starts.size(); i++) {
       matrix.push_back(make_pair(starts[i],-1));
   }
   for(i; i<starts.size()+ends.size(); i++) {
       matrix.push_back(make_pair(ends[i-starts.size()],-2));
   }
   for(i; i<starts.size()+ends.size()+points.size(); i++) {
        matrix.push_back(make_pair(
            points[i-starts.size()-ends.size()],
            i-(starts.size()+ends.size())
        ));
   }
   return matrix;
}

您能否帮助您了解如何在不遍历每个元素的情况下快速填充 2D 向量。我正在使用 C++11。提前致谢!!

【问题讨论】:

  • 不要用 C 标签标记 C++ 问题。它不会帮助您结交朋友和影响他人。
  • vector&lt;pair&lt;int,int&gt;&gt; ...呃,这不是它的工作原理。这将创建一个成对的 int 的一维向量。还有boost.org/doc/libs/1_72_0/libs/multi_array/doc/user.html
  • @datenwolf:这可能是矩阵的稀疏表示。
  • @epinpoklum 仅 2×N 矩阵或 N×2 矩阵。也许你想要vector&lt;tuple&lt;x,y,value&gt;&gt;
  • @einpoklum:仅当您要表示的稀疏矩阵的元素是集合{False | True} 的成员时。或者,如果您想表示一个双对角矩阵。无论哪种方式,这都是一种非常低效的方法。

标签: c++ c++11 vector c++14 c++17


【解决方案1】:

初步关注:正如@datenwolf 和其他人所指出的 - 您生成的数据结构不是二维矩阵(除非您指的是稀疏表示中的布尔矩阵)。您确定这就是您要填充的内容吗?

无论如何,这里有一些可能提高速度的想法:

  1. 不要按值取输入向量!那是无用的复制...取他们的.data(),或者他们的.cbegin()迭代器,或者取一个span&lt;int&gt;参数。
  2. 对目标向量使用reserve() 方法以避免多次重新分配。
  3. 使用.emplace_back() 而不是.push_back() 在适当位置构造点,而不是先构造然后移动每个点。不过,老实说,编译器很可能会优化掉这些结构。
  4. 将输入向量的.size() 值放入局部变量中。仅当由于某种原因编译器怀疑在函数执行过程中大小不会保持不变时,这才会有所帮助。
  5. 确保将优化开关传递给编译器(例如,将 -O2 或 -O3 传递给 GCC 和 clang)。这对您来说似乎很明显,但有时很明显,您会忘记检查它是否真的完成了。

一些美学元素:

  1. 无需对所有向量使用相同的计数器。 for(int i = 0; i &lt; whatever; i++) 可以多次使用。
  2. 不需要原始 for 循环,您可以在前两个循环中使用 for(const auto&amp; my_element : my_vector)。第三个循环比较棘手,因为您需要索引。您可以使用std::difference() 处理迭代器,或者使用here 中描述的Python 样式枚举。
  3. 您可以考虑将std::transform()back_emplacer 输出迭代器一起使用,而不是全部三个循环。无循环代码!这意味着在转换器 lambda 中使用 std::difference() 而不是第三个循环。

【讨论】:

  • 对于 1. 引用不是最自然的选择吗? 3. 算作审美,使用整数值生成的代码将是相同的。
  • @MarcGlisse:1. 不,我们使用迭代器、范围,或者在某些情况下使用跨度。除非我们在输入向量 as 上进行操作,否则我们不是。 3. 你可能是对的。
  • 向量是范围的一种特殊情况,因此您可以采用 T const&(或 C++20 中的 sized_range const&)为例。
【解决方案2】:

这包含了来自@einpoklum's answer 的建议,但也清理了代码。

std::vector<std::pair<int,int>> fast_count_segments(
    std::vector<int> const & starts, 
    std::vector<int> const & ends, 
    std::vector<int> const & points) 
{
   std::vector<std::pair<int,int>> matrix(starts.size() + ends.size() + points.size());

   auto out = std::transform(starts.cbegin(), starts.cend(),
                             matrix.begin(), 
                             [](int i) { return std::pair<int,int>{i, -1}; });

   out = std::transform(ends.cbegin(), ends.cend(),
                        out, 
                        [](int i) { return std::pair<int,int>{i, -2}; });

   int c = 0;
   std::transform(points.cbegin(), points.cend(),
                  out,
                  [&c](int i) { return std::pair<int,int>{i, c++}; });

   return matrix;
}

您甚至可以将所有转换写成一个表达式。这是否更容易阅读是非常主观的,所以我不推荐它本身。 (尝试像嵌套函数调用一样阅读它。)


std::vector<std::pair<int,int>> fast_count_segments(
    std::vector<int> const & starts, 
    std::vector<int> const & ends, 
    std::vector<int> const & points) 
{
   std::vector<std::pair<int,int>> matrix(starts.size() + ends.size() + points.size());
   int c = 0;

   std::transform(points.cbegin(), points.cend(),
        std::transform(ends.cbegin(), ends.cend(),
            std::transform(starts.cbegin(), starts.cend(),
                matrix.begin(), 
            [](int i) { return std::pair<int,int>{i, -1}; }),
        [](int i) { return std::pair<int,int>{i, -2}; }),
    [&c](int i) { return std::pair<int,int>{i, c++}; });

   return matrix;
}

【讨论】:

  • 不是每个transform都返回下一个的参数吗?
  • 是的,谢谢你的建议。我意识到我也可以嵌套转换,尽管我怀疑这不会使它更容易阅读。
  • 谢谢@cigien。我是cpp的初学者。不明白 [] 在变换中的意义。它还给出编译错误“返回初始化列表”。我也使用 C++11,因此对于 [c = 0],lambda 捕获初始化程序仅适用于 -std+c++14
  • [] 表示lambda expression 的开始。更新了在 c++11 中工作的答案。
  • 非常感谢@cigien。这真的很清楚。但是,如果我使用这种方法,当我使用 for 循环填充矩阵时,我无法读取矩阵。 cout &lt;&lt; matrix[i].first &lt;&lt; " " &lt;&lt; matrix[i].second &lt;&lt; endl;。我在哪里迭代循环的大小。可能是什么原因?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-16
  • 1970-01-01
  • 1970-01-01
  • 2018-04-07
  • 1970-01-01
  • 2011-05-04
  • 1970-01-01
相关资源
最近更新 更多