【问题标题】:How to split a vector into n "almost equal" parts如何将向量拆分为 n 个“几乎相等”的部分
【发布时间】:2011-10-15 05:19:22
【问题描述】:

我有一个问题,我想使用 ImageMagick 的 convert.exe 合并大量图像,但在 Windows 下我有 8192 字节长的命令行限制。

我对此的解决方案是将任务拆分为较小的子任务,运行它们,然后执行将它们组合在一起的最终任务。

我的想法是编写一个函数,它接受一个图像向量和一个整数,并将向量拆分为 n 个子向量,所有子向量都具有“几乎相等”的部分。

例如,如果我想将 11 人分成 3 组,那就是 4-4-3。

你能告诉我如何在 C++ 中做到这一点吗?我的意思是,写一个函数

split_vec( const vector<image> &images, int split )

哪个分裂?

另外,你能告诉我如果我不需要创建新向量,只需遍历子部分,最有效的方法是什么吗?像std::substr 函数和std::string 一样吗?

注意:我已经在项目中使用了 Boost,所以如果 Boost 中有一些不错的工具,那么它对我来说是完美的。

【问题讨论】:

    标签: c++ visual-studio-2010 boost vector iterator


    【解决方案1】:

    要获得每个部分大小的基数,只需将总和除以部分数:11/3 = 3。显然,某些部分需要大于该值才能获得正确的总和,但是这只是余数:11 % 3 = 2。所以现在您知道其中 2 个部分的尺寸为 3+1,剩下的部分将是 3。

    【讨论】:

    • 谢谢,这是我想出的:双循环 = 数字 / 部分; for( int i = 0; i
    • @zsero,如果numberparts 都是整数,您需要在进行除法之前将1 转换为double。此外,您还需要担心舍入错误,在某些情况下,当您转换回整数时,您可能会遇到非一的错误。
    • 实际上我在函数定义中使用了双精度数,并在开始和结束时使用了 round() 函数。您认为使用 round() 函数时可能会出现舍入错误吗? (我用stringstream来取整)
    • @zsero,如果你在开始和结束时使用舍入而不是截断,你应该没问题。您在之前的评论中留下了那部分。
    【解决方案2】:

    CreateProcess has a 32kb limit

    或者,如果你想通过 shell,

    vec::const_iterator i = vec .begin ();
    vec::const_iterator j = i + stride;
    
    while (j < vec .end ()) {
        do_range (i, j);
        i = j;
        j += stride;
    }
    
    do_range (i, vec .end ());
    

    【讨论】:

      【解决方案3】:

      您可以使用iterators 来遍历问题的子部分。迭代器的用法类似于指向vector元素的指针

      你想对图像做的事情可以实现为一个函数

      using namespace std; 
      void do_some_work(vector<image>::iterator begin, vector<image>::iterator end) {
          vector<image>::iterator i = begin ;
          while(i != end) {
              // do something using *i , which will be of type image
              ++i ;
          }
      }
      

      【讨论】:

        【解决方案4】:

        您是否考虑过使用xargs 程序。这可能是问题的高级解决方案。

        【讨论】:

        • 我一直在我的 Windows 机器上使用“unix”实用程序。结帐:unxutils.sf.net 和/或 www.cygwin.com
        • 感谢您的提示,虽然我担心这不会帮助他在别人的计算机上运行代码:-P
        • 为什么? xargs 是一个独立程序。与他的程序一起分发。
        【解决方案5】:

        您不必创建新的子向量,使用如下所示:

        size_t ProcessSubVec(const vector<Image>& images, size_t begin, size_t end)
        {
            // your processing logic
        }
        
        void SplitVec(const vector<Image>& images, int cnt)
        {
            size_t SubVecLen = images.size() / cnt,
                   LeftOvers = images.size() % cnt,
                   i = 0;
        
            // Split into "cnt" partitions
            while(i < images.size())
                i += ProcessSubVec(images, i, i + SubVecLen + (LeftOvers-- == 0 ? 0 : 1));
        }
        

        希望这会有所帮助。

        【讨论】:

        • Brandon ProcessSubVec 应该返回什么?我没听懂。
        【解决方案6】:

        这是我的解决方案:

        template<typename T>
        std::vector<std::vector<T>> SplitVector(const std::vector<T>& vec, size_t n)
        {
            std::vector<std::vector<T>> outVec;
        
            size_t length = vec.size() / n;
            size_t remain = vec.size() % n;
        
            size_t begin = 0;
            size_t end = 0;
        
            for (size_t i = 0; i < std::min(n, vec.size()); ++i)
            {
                end += (remain > 0) ? (length + !!(remain--)) : length;
        
                outVec.push_back(std::vector<T>(vec.begin() + begin, vec.begin() + end));
        
                begin = end;
            }
        
            return outVec;
        }
        

        【讨论】:

          【解决方案7】:

          您可以创建一个返回 std::vector 的模板 并接收要分割的向量和分割数。 使用 for 和迭代器非常简单。

          #include <iostream>
          #include <iomanip>
          #include <vector>
          #include <algorithm>
          #include <numeric>
          
          template<typename T>
          std::vector< std::vector<T> > split(std::vector<T> vec, uint64_t n) {
            std::vector< std::vector<T> > vec_of_vecs(n);
          
            uint64_t quotient = vec.size() / n;
            uint64_t reminder = vec.size() % n;
            uint64_t first = 0;
            uint64_t last;
            for (uint64_t i = 0; i < n; ++i) {
              if (i < reminder) {
                last = first + quotient + 1;
                vec_of_vecs[i] = std::vector<T>(vec.begin() + first, vec.begin() + last);
                first = last;
            }
              else if (i != n - 1) {
              last = first +  quotient;
              vec_of_vecs[i] = std::vector<T>(vec.begin() + first, vec.begin() + last);
              first = last;
            }
              else
              vec_of_vecs[i] = std::vector<T>(vec.begin() + first, vec.end());
          }
          
          return vec_of_vecs;
          }
          
          #define ONE_DIMENSION 11
          #define SPLITS 3
          
          int main(void)
          {
            std::vector<uint64_t> vector(ONE_DIMENSION);
            std::iota(std::begin(vector), std::end(vector), 1);
          
            std::vector<std::vector<uint64_t>> vecs(SPLITS);
            vecs = split(vector, SPLITS);
          
            for (uint64_t m = 0; m < vecs.size(); ++m) {
              for (auto i : vecs[m])
                std::cout << std::setw(3) << i << " ";
              std::cout << std::endl;
            }
          
          
            return 0;
          }
          

          【讨论】:

            猜你喜欢
            • 2011-03-22
            • 2018-10-04
            • 1970-01-01
            • 1970-01-01
            • 2012-12-13
            • 2022-01-16
            • 2020-06-22
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多