【问题标题】:What's time complexity to delete the last element in array by MATLAB?MATLAB 删除数组中最后一个元素的时间复杂度是多少?
【发布时间】:2018-09-11 22:28:47
【问题描述】:

我不知道 MATLAB 中数组的数据结构。它使用 FiFo 吗?

我尝试从列和行向量中删除最后一个元素。时间复杂度取决于大小N

如何删除O(1)中的最后一个元素?

pop().

【问题讨论】:

  • 我建议您检查that
  • 添加元素时,MATLAB 分配的内存块比所需的更大,因此重复添加元素的摊销成本为 O(log(n)),而不是每个元素的 O(n)。我假设删除最后一个元素是 O(1)。

标签: arrays matlab data-structures


【解决方案1】:

按照this question 的计时脚本处理相反的问题——增长一个向量,我尝试了两种方法来删除最后一个元素:

building_array = building_array(1:end-1);
building_array(end) = [];

作为Tommaso noted,前者(蓝色)比后者(红色)快:

我猜测为什么这两种形式有不同的时序是 MATLAB 的 JIT(即时编译器)针对一种语法比另一种更优化。一个比另一个快没有技术原因。

我真的很惊讶成本与元素数量呈线性关系,与当时添加元素的行为截然不同。

测试代码(修改自Peter Barrett Bryan):

num_averages = 500;
num_sims = 10000;
time_store = nan(num_sims, num_averages);
for i = 1:num_averages
    building_array = rand(num_sims,1);
    for j = 1:num_sims
        tic;
        building_array = building_array(1:end-1);
        time_store(j, i) = toc;
    end
end

【讨论】:

    【解决方案2】:

    经过快速测试,我发现就地重新分配比删除元素快得多。但是这两种操作的性能仍然取决于向量的大小......我只是认为这在O(1) 中无法实现,因为Matlab 内部如何处理内存。

    第一种方法:

    A = rand(100,1);
    
    tic();
    A(end) = [];
    toc(); % Average elapsed time: 0.000015 seconds
    
    B = rand(10000,1);
    
    tic();
    B(end) = [];
    toc(); % Average elapsed time: 0.000061 seconds
    

    第二种方法:

    A = rand(100,1);
    
    tic();
    A = A(1:end-1);
    toc(); % Average elapsed time: 0.000007 seconds
    
    B = rand(10000,1);
    
    tic();
    B = B(1:end-1);
    toc(); % Average elapsed time: 0.000017 seconds
    

    我对 Matlab 的了解还不够深入,无法让我准确解释幕后发生的事情以及为什么这两种方法之间存在如此大的差异。不过我可以猜一猜。

    在第一种方法中,Matlab 必须:

    • end 评估为实向量偏移量;
    • 找出需要删除的元素数量;
    • 分配一个大小为total_elements - removed_elements的新数组;
    • 取出数组中未触及的部分并将它们缓冲复制到新数组中;
    • 用新的替换之前的数组引用;
    • 释放前一个数组。

    在第二个中,Matlab 必须:

    • end 评估为实向量偏移量;
    • 分配一个大小为indexed_elements的新数组;
    • 获取数组的所需范围并将它们缓冲区复制到新数组中;
    • 用新的替换之前的数组引用;
    • 释放前一个数组。

    然而,我们离O(1)还很远。

    【讨论】:

    • 我不明白您建议的两种方案之间的区别。 end 需要在这两种情况下进行评估。我希望 MATLAB 不会复制数组来删除一个元素,但也许它就是这样做的。诡异的。但我对执行时间的任何差异的猜测是,JIT 已针对一种语法进行了优化,但没有针对另一种语法进行优化。
    • 我做了一个更仔细的计时实验。这种行为令人惊讶!
    【解决方案3】:

    免责声明:这不是一个真正的建议,它只是实际获得 O(1) 运行时的愚蠢方法

    是的,在给出免责声明的情况下,实际上可以在“Matlab”中创建一个 O(1) 的弹出命令。解决方案是不在 Matlab 中,而是在 Python 中。使困惑?

    基本上,您可以使用 py.list() 将向量转换为 Python 列表,然后可以执行 O(1) pop 命令。因此,您可以执行以下操作:

    a = randn(1,1e4);
    li=py.list(a);
    b = li.pop;
    

    但是,正如您可能已经猜到的那样,通过 Matlab 进行类型转换和运行 python 并不是我所说的快速。因此,即使我们可以保持一个恒定的运行时间,但该常数太大而无法使用。

    在图中,蓝色是 Matlab/Python 解决方案,而红色(-ish)是最佳解决方案,由 Tommaso 和 Cris 给出。

    很明显,我们保持看起来像 O(1),但要付出代价。

    参考代码:

    num_averages = 100;
    num_sims = 10000;
    time_store = nan(num_sims, num_averages);
    for i = 1:num_averages
        building_array = rand(1,num_sims);
        li = py.list(building_array);
        for j = 1:num_sims
            tic;
            li.pop;
            time_store(j, i) = toc;
        end
    end
    

    编辑:这种方法比纯 Matlab 解决方案更快的大小实际上在某个合理的限制范围内,约为 150000。

    注意:由于我的耐心耗尽,这个数字的波动更大,因此我将平均数减少到 5 个。

    别搞错了,这个解决方案仍然很愚蠢,不应该使用。转换在大小上是线性的,再次转换会更加破坏它。因此,该解决方案实际上更好的唯一情况是,如果您对弹出的元素感兴趣,但在这种情况下,带有索引的 for 循环可以更快地完成相同的事情。

    【讨论】:

    • 太棒了!我喜欢不切实际的解决方案!
    • 很高兴你喜欢它:D 我真的不能接受不存在 O(1) 解决方案。
    【解决方案4】:

    取决于数组长度,使用tic <_code_under_test_> toc,测量时间

    A = ones(1,50);
    B = ones(1,10);
    
    tic
    A(1) = [];
    toc
    tic
    A(49) = [];
    toc
    tic
    B(1) = [];
    toc
    tic
    B(9) = [];
    toc
    
    Elapsed time is 0.000195 seconds.
    Elapsed time is 0.000085 seconds.
    Elapsed time is 0.000061 seconds.
    Elapsed time is 0.000051 seconds.
    

    可以看到,删除数组的最后一个元素比删除第一个元素要快。

    【讨论】:

    • 我看到 100、1000 和 5000 个元素的数组在 1000 次运行中所用的时间大致相同。也许您需要在更大的阵列上进行更多的运行。为什么要删除第一个元素?您是否希望这与删除最后一个元素具有相同的时间复杂度?
    • 您应该使用timeit 来衡量时间成本。我不确定您在这里测量的是什么,但是如果您将此代码放在函数中或将其复制粘贴到命令提示符中,它会有所不同。
    • 函数tic toc记录执行时的内部时间
    • @pfRodenas:我知道tictoc 做什么。我说的是我不确定你在这里测量的是什么。您记录的成本超过了执行一条语句的成本。它太便宜了,无法正确测量。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-23
    • 1970-01-01
    • 2020-04-17
    • 1970-01-01
    • 2015-05-20
    • 1970-01-01
    • 2021-02-10
    相关资源
    最近更新 更多