首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >逐步增长的单元阵列类

逐步增长的单元阵列类
EN

Stack Overflow用户
提问于 2012-12-03 09:13:00
回答 1查看 105关注 0票数 2

我编写了以下类,以便在matlab中实现“逐步增长”的单元格数组:

代码语言:javascript
复制
classdef growinglist < handle 
    properties (GetAccess='private',SetAccess='private')
        inner_cells % inner pre-allocated cell array
    end
    properties (GetAccess='public',SetAccess='private')
        n_elements % current number of elements (index of last valid element in inner_cells)
    end
    methods
        %% constructor
        function self=growinglist(varargin)
            % you can pass the initial capacity of inner_cells to constructor
            if nargin == 1 
                self.inner_cells =cell(ceil(varargin{1}),1);
            else
                self.inner_cells =cell(4,1); % initial size is 4
            end
            self.n_elements = 0;
        end
        function add(self, element)
            % inner_cells is not enough, double it before adding
            if self.n_elements + 1 > size(self.inner_cells,1)
                n = floor(size(self.inner_cells,1) * 2) - size(self.inner_cells,1) + 1;
                self.inner_cells = [self.inner_cells; cell(n,1)];
            end
            self.n_elements = self.n_elements + 1;
            self.inner_cells{self.n_elements} = element;
        end
        function elements = get_elements(self)
            elements = self.inner_cells(1:self.n_elements,1);
        end
    end
end

然而,它似乎并不像预期的那样快。

实际上,执行这些测试:

代码语言:javascript
复制
n = 30000;

%%%%%% concat everytime
tic
lst = {};
for i=1:n
    lst = [lst; 1:10];
end
disp('1 - concat everytime');
toc
%%%%%% exact pre-allocation
tic
lst = cell(n,1);
for i=1:n
    lst{i} = 1:10;
end
disp('2 - exact pre-allocation');
toc
%%%%%% "progressive" pre-allocation
tic
inner_cells = cell(4,1);
n_elements = 0;
for i=1:n
    if n_elements + 1 > size(inner_cells,1)
       n1 = floor(size(inner_cells,1) * 2) - size(inner_cells,1) + 1;
       inner_cells = [inner_cells; cell(n1,1)];
    end
    n_elements = n_elements+1;
    inner_cells{n_elements} = 1:10;
end
elements = inner_cells(1:n_elements,1);
disp('3 - "progressive" pre-allocation');
toc
%%%%%% using growing list class
tic
glst = growinglist();
for i=1:n
    glst.add(1:10);
end
elements = glst.get_elements();
disp('4 - using growing list class');
toc
%%%%%% using growing list class with exact allocation
tic
glst = growinglist(n);
for i=1:n
    glst.add(1:10);
end
elements = glst.get_elements();
disp('5 - use growing list class with exact allocation');
toc

我得到以下结果:

代码语言:javascript
复制
1 - concat everytime
Elapsed time is 4.954054 seconds.
2 - exact pre-allocation
Elapsed time is 0.006791 seconds.
3 - "progressive" pre-allocation
Elapsed time is 0.099431 seconds.
4 - using growing list class
Elapsed time is 11.618202 seconds.
5 - use growing list class with exact allocation
Elapsed time is 12.774726 seconds.

实际上,我预计测试n.4和n.5所用的时间更接近测试n.3。但他们甚至比测试n.1慢(我预计这将是最坏的)。此外,奇怪的是,测试n.5比n.4慢。

也许每次设置inner_cells数组时都会复制该数组,或者修改其他一些副本,但我不明白为什么,因为我从handle类派生了类以支持可变性。

我刚加入matlab所以我可能遗漏了一些重要的东西..。

有洞察力吗?

提前谢谢。

附注:

我正在使用MATLAB 2011 a。

编辑:

正如@Edric所建议的那样,我使用分析器查找瓶颈,并发现慢度的罪魁祸首是在方法Add() (--不知道为什么是)中调用的函数。

以这种方式修改类(以减少size()调用):

代码语言:javascript
复制
classdef growinglist < handle 
    properties (GetAccess='private',SetAccess='private')
        inner_cells
        inner_cells_size
    end
    properties (GetAccess='public',SetAccess='private')
        n_elements % current number of elements (index of last valid element in inner_cells)
    end
    methods
        % constructor
        function self=growinglist(varargin)
            % you can pass the initial capacity of inner_cells to constructor
            if nargin == 1 
                self.inner_cells =cell(ceil(varargin{1}),1);
                self.inner_cells_size = ceil(varargin{1});
            else
                self.inner_cells =cell(4,1); % initial size is 4
                self.inner_cells_size = 4;
            end
            self.n_elements = 0;
        end
        function add(self, element)
            % inner_cells is not enough, double it before adding
            if self.n_elements + 1 > self.inner_cells_size
                n = floor(size(self.inner_cells,1) * 2) - size(self.inner_cells,1) + 1;
                self.inner_cells = [self.inner_cells; cell(n,1)];
                self.inner_cells_size = self.inner_cells_size + n;
            end
            self.n_elements = self.n_elements + 1;
            self.inner_cells{self.n_elements} = element;
        end
        function elements = get_elements(self)
            elements = self.inner_cells(1:self.n_elements,1);
        end
    end
end

试验现在产生:

代码语言:javascript
复制
1 - concat everytime
Elapsed time is 6.825776 seconds.
2 - exact pre-allocation
Elapsed time is 0.011783 seconds.
3 - "progressive" pre-allocation
Elapsed time is 0.088668 seconds.
4 - using growing list class
Elapsed time is 0.841975 seconds.
5 - use growing list class with exact allocation
Elapsed time is 0.818212 seconds.

这更有道理。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-12-03 11:05:52

不幸的是,与内置功能相比,MATLAB对象系统通常要慢一些--特别是当您运行数千个方法调用时,每个调用只执行微不足道的计算量,就像在本例中一样。

一件可能有用的事情是使用函数调用样式进行方法调用(不确定是否有更好的术语)。无论如何,它看起来是这样的:

代码语言:javascript
复制
add(glst, 1:10);

而不是

代码语言:javascript
复制
glst.add(1:10);

这使得MATLAB可以立即意识到,您指的是方法调用,而不是字段引用。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13680124

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档