Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 在MATLAB中预分配阵列的替代方案是什么?_Arrays_Optimization_Memory_Matlab - Fatal编程技术网

Arrays 在MATLAB中预分配阵列的替代方案是什么?

Arrays 在MATLAB中预分配阵列的替代方案是什么?,arrays,optimization,memory,matlab,Arrays,Optimization,Memory,Matlab,可能重复: 因此,在我当前的MATLAB脚本中,我有一个非常大的不确定大小的增长数组。目前我对此无能为力,因为如果我真的预先分配,它将占用比它所需要的内存多数倍的内存(最大可能值为每像素640,但通常是2-5) 通常,在这种情况下,我将使用C++中的向量或其他东西,在那里它相对于给定容量呈指数增长。但是我认为Matlab中的矩阵开始比目标驱动的C++矢量快得多。 你们认为什么是最好的选择?或者我应该坚持使用普通数组,并希望按顺序添加大约100k个元素会起作用吗 提前感谢。您可以尝试一下std:

可能重复:

因此,在我当前的MATLAB脚本中,我有一个非常大的不确定大小的增长数组。目前我对此无能为力,因为如果我真的预先分配,它将占用比它所需要的内存多数倍的内存(最大可能值为每像素640,但通常是2-5)

通常,在这种情况下,我将使用C++中的向量或其他东西,在那里它相对于给定容量呈指数增长。但是我认为Matlab中的矩阵开始比目标驱动的C++矢量快得多。 你们认为什么是最好的选择?或者我应该坚持使用普通数组,并希望按顺序添加大约100k个元素会起作用吗


提前感谢。

您可以尝试一下
std::vector
在重新分配元素时所做的操作——每次填充时容量加倍,摊销成本为O(1)

测试: 输出: 运行时间为3.489820秒

运行时间为0.006710秒

使用电池 运行时间为2.740792秒


您可以增加一个比阵列便宜得多的单元阵列,然后使用
cell2mat
转换为阵列(需要两倍的内存,但如果有,这是最简单的方法)

如果您知道可以预先分配适当大小的单元格数组的像素数,请使用实际值数组(最多640个,但通常为2-5个)填充每个单元格,然后使用
cell2mat
将其转换为连续数组


如果您担心碎片问题,您可以在加载单元后进行
打包
,在执行
cell2mat
转换之前,该单元应该对内存进行碎片整理(将所有内容授权到磁盘,并再次连续加载)。

增加阵列通常是一件坏事,至少如果您多次这样做的话。有几个技巧可以使用。(我都试过了,如果你愿意的话,我还编写了一些工具,可以自动为你做到这一点。)

问题是与阵列增长相关的时间是一个O(N^2)操作。如果以后需要创建一个大型数组,它还会导致内存碎片化,从而给您带来潜在的问题

一种方法是将数组预先分配到某个固定大小,然后在超出数组大小时追加大量的零块。现在使用矩阵索引将新值插入现有数组。其想法是在需要重新分配阵列时将其大小增加一倍。这只会导致少量的重新分配,但最终可能会追加许多不需要填充的零。最后,转储无关和未使用的数组元素

第二个技巧是使用单元格数组。每次要附加新元素或新元素块时,只需将这些元素附加到一个新单元格中即可。最后,你做一个cell2mat操作。单元技巧的一个问题是,它仍然是一个O(N^2)操作,因为单元数组本身本质上是一个指针数组,并且在附加新元素时必须重新分配指针列表

有一个组合技巧,你可以这样做,我喜欢,但它需要一个工具来实现操作。其想法是创建包含10000个元素块的单元。用零填充第一个块。然后使用矩阵索引在生成新元素时插入新元素。矩阵索引当然很快。当该单元格中的空间用完时,将附加一个新的大单元格。最后,将所有单元连接在一起,小心地删除未使用的元素

最后一个方案涉及相对较少的要追加的新单元元素,因此如果有数百万个追加步骤,那么总体上是最有效的

这些方法中的每一种都体现在我多年来发布的几个文件交换提交中。第一个可以找到,它在内部管理附加步骤,为您担心矩阵索引


稍后,我使用函数句柄或持久变量构建了最后一个方案,以维护存储的信息。包含这些实现的工具如下所示。

在前面的一个问题中,我已经发布了作者建议的工具

我后来比较了大多数可用选项的性能(上面对这些选项进行了很好的总结)。以下是我在机器上得到的结果:

NUM = 50000;

%%# ========== MINE: ~0.07sec ==========
tic
BLOCK_SIZE = 2000;                           %# initial & increment size
listSize = BLOCK_SIZE;                       %# current list capacity
list = zeros(listSize, 2);                   %# actual list
listPtr = 1;                                 %# pointer to last free position
for i=1:NUM
    %# push items on list
    list(listPtr,:) = [rand rand];           %# store new item
    listPtr = listPtr + 1;                   %# increment position pointer
    %# add new block of memory if needed
    if( listPtr+(BLOCK_SIZE/10) > listSize ) %# less than 10%*BLOCK_SIZE free
        listSize = listSize + BLOCK_SIZE;    %# add new BLOCK_SIZE slots
        list(listPtr+1:listSize,:) = 0;
    end
end
list(listPtr:end,:) = [];                    %# remove unused slots
toc

%%# ========== PREALLOCATION (matrix): ~0.05sec ==========
tic
list = zeros(NUM,2);
for i=1:NUM
    list(i,:) = [rand rand];
end
toc

%%# ========== PREALLOCATION (cell): ~1.1sec ==========
tic
list = cell(NUM,1);
for i=1:NUM
    list{i} = [rand rand];
end
list = vertcat( list{:} );
toc

%%# ============ NO-PREALLOCATION (grow cell): ~5sec ========
tic
list = {};
for i=1:NUM
    list{i} = [rand rand];
end
list = vertcat( list{:} );
toc

%%# ============ NO-PREALLOCATION (grow matrix): ~24sec ========
tic
list = [];
for i=1:NUM
    list(i,:) = [rand rand];
end
toc

%%# ========== GROWDATA (by John D'Errico): ~3.3sec =========
tic
growdata                             %# The initialization call
for i = 1:NUM
    growdata( [rand rand] )          %# push items
end
list = growdata;                     %# unpacking step
toc

这让我有点难过,我要这样做,但这看起来是一个有效的解决方案。谢谢或者也许我应该用mexfile包装一个std::vector。。。是的,但是它很慢(我在回答中已经分析过)。@Jacob:对于像您的示例这样的单个元素来说,它很慢,但是我通常在想要连接更大的数组时使用这种方法,因为数组扩展会让您丧命。。。例如,在测试中,不要添加单个元素,而是添加长度为100000-1000000的随机数组。您还可以预先分配单元阵列。我想你会发现这比阵列扩展要快得多,但我敢肯定仍然没有你的std::vector克隆快(虽然在本例中这有点复杂)可能的副本:,dang,我也四处搜索过。应该使用“可生长”而不是可调整大小并预先分配为关键字:\n抱歉+1获得详细答案我将补充说,简单单元解决方案对于相对较少的单元是有效的。对于几千个细胞来说,这是一个很好的方法。即使对于50k电池,这仍然很快。当您开始移动到数百万个附件中时,具有数百万个单元的单元阵列可能会变得更加昂贵。您仍然需要增加指针数组。(我记得,在matlab的过去版本中,这个故事是不同的,我发现盈亏平衡点较低,所以我认为随着时间的推移,他们的情况有所改善。)@woodchips:看来你是对的,addi
%%# cell
tic;
A = cell(1,1);
for i = 1:LIM
    A(end+1) = {i};
end
toc
NUM = 50000;

%%# ========== MINE: ~0.07sec ==========
tic
BLOCK_SIZE = 2000;                           %# initial & increment size
listSize = BLOCK_SIZE;                       %# current list capacity
list = zeros(listSize, 2);                   %# actual list
listPtr = 1;                                 %# pointer to last free position
for i=1:NUM
    %# push items on list
    list(listPtr,:) = [rand rand];           %# store new item
    listPtr = listPtr + 1;                   %# increment position pointer
    %# add new block of memory if needed
    if( listPtr+(BLOCK_SIZE/10) > listSize ) %# less than 10%*BLOCK_SIZE free
        listSize = listSize + BLOCK_SIZE;    %# add new BLOCK_SIZE slots
        list(listPtr+1:listSize,:) = 0;
    end
end
list(listPtr:end,:) = [];                    %# remove unused slots
toc

%%# ========== PREALLOCATION (matrix): ~0.05sec ==========
tic
list = zeros(NUM,2);
for i=1:NUM
    list(i,:) = [rand rand];
end
toc

%%# ========== PREALLOCATION (cell): ~1.1sec ==========
tic
list = cell(NUM,1);
for i=1:NUM
    list{i} = [rand rand];
end
list = vertcat( list{:} );
toc

%%# ============ NO-PREALLOCATION (grow cell): ~5sec ========
tic
list = {};
for i=1:NUM
    list{i} = [rand rand];
end
list = vertcat( list{:} );
toc

%%# ============ NO-PREALLOCATION (grow matrix): ~24sec ========
tic
list = [];
for i=1:NUM
    list(i,:) = [rand rand];
end
toc

%%# ========== GROWDATA (by John D'Errico): ~3.3sec =========
tic
growdata                             %# The initialization call
for i = 1:NUM
    growdata( [rand rand] )          %# push items
end
list = growdata;                     %# unpacking step
toc