C++ 十进制因子的降尺度数组

C++ 十进制因子的降尺度数组,c++,arrays,algorithm,c++11,C++,Arrays,Algorithm,C++11,是否有有效的方法通过十进制因子来减少数组中元素的数量 我想将一个数组中的元素按一定的比例缩小 例如: 如果我有10个元素,需要按因子2缩小 1 2 3 4 5 6 7 8 9 10 scaled to 1.5 3.5 5.5 7.5 9.5 将2按2分组并使用算术平均值 我的问题是,如果需要将数组从10个元素缩减为6个元素,该怎么办?理论上,我应该将1.6个元素分组,并找出它们的算术平均值,但如何做到这一点呢 所以你必须卷起袖子去上班。在这一点上,什么是“有效”的方式做它的问题归结为它的最基本

是否有有效的方法通过十进制因子来减少数组中元素的数量

我想将一个数组中的元素按一定的比例缩小

例如: 如果我有10个元素,需要按因子2缩小

1 2 3 4 5 6 7 8 9 10
scaled to
1.5 3.5 5.5 7.5 9.5
将2按2分组并使用算术平均值


我的问题是,如果需要将数组从10个元素缩减为6个元素,该怎么办?理论上,我应该将1.6个元素分组,并找出它们的算术平均值,但如何做到这一点呢 所以你必须卷起袖子去上班。在这一点上,什么是“有效”的方式做它的问题归结为它的最基本的。这意味着:

1) 计算输出数组的大小。根据问题的描述,您应该能够在查看输入数组中的值之前进行计算。您知道输入数组的
size()
,可以计算目标数组的
size()

2) 因此,您需要预先调整目标阵列的大小。现在,您不必再担心在通过输入数组进行计算时,以增量方式增加动态输出数组的大小所浪费的时间

3) 剩下的就是实际工作:迭代输入数组,并计算缩小的值

auto b=input_array.begin();
auto e=input_array.end();

auto p=output_array.begin();

除了蛮力迭代和计算之外,这里没有其他选择。从
b
迭代到
e
,获取样本,计算每个缩小的值,并将结果值保存到
*p++
中。您需要采用某种形式的插值,因为要平均的元素数不是整数

可以考虑计算数组的前缀和,即

0 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 10
总和收益率

0  1  2  3  4  5  6  7  8  9
1  3  6 10 15 21 28 36 45 55
然后执行线性插值以获得缺少的中间值,如at
0*、10/6、20/6、30/5*、40/6、50/6、60/6*
。(带星号的可随时获取)

现在通过成对减去值得到分数和。第一个平均值是

(15/3-1)/(10/6) = 12/5

在提出解决方案之前,让我们以更正式的方式定义“精简”。我建议这一定义:

缩编从一个数组
a[N]
开始,并生成一个数组
b[M]
,从而满足以下条件:


  • M你所说的“理论上我应该将1.6个元素分组”是什么意思?元素计数始终是一个自然数。你总是按2进行缩放吗?@Superlokkus我认为OP的意思是“按1.666666(6)进行分组,即按10.0/6.0进行分组。当你说你想“将一个数组缩小到10到6”时,你如何处理第二个元素?也就是说,如果你采用元素0和元素1的60%,你是否打算在下一次迭代中采用整个元素1,跳过它(去掉剩下的部分),或者只取另外40%(需要取元素2,然后取元素3的20%)?我不确定在负元素的情况下,求和声明的行为如何。我正在处理有符号的整数。其他两个声明是正确的。@Steva
    sum
    在负片上的工作方式应该与在示例中求平均值的工作方式相同。想象一下将
    1,-1,2,-2,3,-3,4,-4,5
    向下扩展到5个元素。求平均值将产生
    0,0,0,0,0
    @dasblinkenlight 6/10不是2/3。也就是说,6/10是.6,不是.6666…你(M/N)的基本公式是正确的,但使用他的例子的简化版本不是。它应该是
    a[0]+.6*a[1]
    @ZacHowland 2/3来自(10/6)-1,即(5/3)-1。我的意思是“缩小”除以“,因此结果是10/6的除法,或0.6的乘法。我再次通过Excel运行这些数字,以确保结果与预期值匹配(即55*0.6之和,即33),并且我的数字确实匹配。好的,应该这样做。我将尝试实现它并查看其行为,但我看不出这不起作用的任何原因:)谢谢!:)我曾考虑过插值,但我的数组中有大约9百万个元素,如果不是无法使用的话,计算多项式插值会非常慢。@steva:我没有建议多项式插值。多项式插值不适用于超过10个点。但也有很好的分段多项式格式,速度很快。(我的例子使用了简单的分段线性插值。)我的主要观点是插值需要在前缀和上执行,而不是在原始序列上执行。
    (15/3-1)/(10/6) = 12/5
    
    b[0] = a[0] + (2/3)*a[1]              = 2.33333
    b[1] = (1/3)*a[1] + a[2] + (1/3)*a[3] = 5
    b[2] = (2/3)*a[3] + a[4]              = 7.66666
    b[3] = a[5] + (2/3)*a[6]              = 10.6666
    b[4] = (1/3)*a[6] + a[7] + (1/3)*a[8] = 13.3333
    b[5] = (2/3)*a[8] + a[9]              = 16
                                            --------
                                    Total = 55
    
    1.4 3 4.6 6.4 8 9.6 (Total = 33)
    
    double need = ((double)a.size()) / b.size();
    double have = 0;
    size_t pos = 0;
    for (size_t i = 0 ; i != a.size() ; i++) {
        if (need >= have+1) {
            b[pos] += a[i];
            have++;
        } else {
            double frac = (need-have); // frac is less than 1 because of the "if" condition
            b[pos++] += frac * a[i];   // frac of a[i] goes to current element of b
            have = 1 - frac;
            b[pos] += have * a[i];     // (1-frac) of a[i] goes to the next position of b
        }
    }
    for (size_t i = 0 ; i != b.size() ; i++) {
        b[i] /= need;
    }