在工作线程中几乎平均地划分数据集

时间:2018-04-24 07:21:20

标签: c++ algorithm logic

我有 n 数量的元素和 p 线程数。我试图在线程中尽可能平等地划分元素。

例如:

If n = 8 and p = 1, then [8]
If n = 8 and p = 2, then [4, 4]
If n = 8 and p = 3, then [2, 3, 3]
If n = 8 and p = 4, then [2, 2, 2, 2]
If n = 8 and p = 5, then [1, 1, 2, 2, 2]
If n = 8 and p = 6, then [1, 1, 1, 1, 2, 2]
If n = 8 and p = 7, then [1, 1, 1, 1, 1, 1, 2]
If n = 8 and p = 8, then [1, 1, 1, 1, 1, 1, 1, 1]

我制作了一个几乎可以工作但不完全的解决方案。

#include <vector>
#include <stdio.h>
#include <cmath>

int main(int argc, char **argv)
{
    int p = 5;
    const int SIZE = 8;
    int i = 0;
    int num = 0;

    std::vector<int> iter;

    if (p == 1)
        iter.push_back(SIZE);
    else
    {
        if (SIZE % p == 0)
        {
            num = SIZE / p;

            for (i = 0; i < p; ++i)
                iter.push_back(num);
        }
        else
        {
            num = (int)floor((float)SIZE / (float)p);

            for (i = 0; i < p - 1; ++i)
                iter.push_back(num);

            iter.push_back((SIZE - (num * (p - 1))));
        }
    }

    for (unsigned int j = 0; j < iter.size(); ++j)
        printf("[%d] = %d\n", j, (int)iter[j]);

    return 0;
}

我的解决方案产生的结果:

If n = 8 and p = 1, then [8]
If n = 8 and p = 2, then [4, 4]
If n = 8 and p = 3, then [2, 2, 4]
If n = 8 and p = 4, then [2, 2, 2, 2]
If n = 8 and p = 5, then [1, 1, 1, 1, 4]
If n = 8 and p = 6, then [1, 1, 1, 1, 1, 3]
If n = 8 and p = 7, then [1, 1, 1, 1, 1, 1, 2]
If n = 8 and p = 8, then [1, 1, 1, 1, 1, 1, 1, 1]

3 个答案:

答案 0 :(得分:4)

试着想一想。如果你有更少的对象然后线程,那么每个线程将获得一个对象。如果你有更多的物体然后线程(桶),那么考虑如何将100个网球分成8个桶。 你可以一次拿一个球并把它放在下一个水桶中,一旦你从第一个水桶开始通过所有水桶,这将确保每个水桶大小之间的差异最多为1个。

#include <vector>
#include <stdio.h>

int main(int argc, char **argv)
{
    int p = 5;
    const int SIZE = 8;

    int p_size = SIZE > p ? p : SIZE;

    std::vector<int> iter(p_size);

    for (int i = 0; i < SIZE; i++)
    {
        iter[i%p_size] += 1;
    }


    for (unsigned int j = 0; j < iter.size(); ++j)
        printf("[%d] = %d\n", j, (int)iter[j]);

    return 0;
}

答案 1 :(得分:1)

你可以试试这个:

std::vector<int> iter(p);
std::generate(iter.begin(), iter.end(), [&]()
{
    num += 1;
    return SIZE / p + (num <= SIZE % p ? 1 : 0);
});

第一行创建所需数量的元素,第二行使用实际数据填充此向量。它的编写没有显式循环,使代码更具表现力。

答案 2 :(得分:1)

这不是您特定问题/问题的答案,而是针对您预期问题的替代方法。

你的解决方案是复杂的方法...这个代码也是一样的,除了额外的任务被放在前面......

#include <iostream>
#include <vector>

int main(int argc, char **argv)
{
    int p = 5;
    const int n = 8;

    // calculate number of tasks every thread have to do...
    int every = n / p;

    // calculate rest
    int rest = n % p;

    // initialize the vector with the number of tasks every thread have to do
    std::vector<int> lst(p, every);

    // split rest on the threads
    for(int i=0; i<rest; ++i)
        lst[i]++;

    // print out
    for(auto it : lst)
        std::cout << it << ",";

    return 0;
}

技巧是整数截断,不需要浮点算术,正如你可能看到的那样,其他答案也可以...