預分配的重要性

MATLAB 中的陣列作為連續塊儲存在記憶體中,由 MATLAB 自動分配和釋放。MATLAB 隱藏了記憶體管理操作,例如在易於使用的語法背後調整陣列大小:

a = 1:4

a =

     1     2     3     4

a(5) = 10  % or alternatively a = [a, 10]

a =

     1     2     3     4    10

重要的是要理解上面不是一個簡單的操作,a(5) = 10 將導致 MATLAB 分配一個大小為 5 的新記憶體塊,複製前 4 個數字,並將第 5 個數字設定為 10.這是一個 O(numel(a)) 操作,而不是 O(1)

考慮以下:

clear all
n=12345678;
a=0;
tic
for i = 2:n
    a(i) = sqrt(a(i-1)) + i;
end
toc

Elapsed time is 3.004213 seconds.

a 在此迴圈中重新分配了 5 次(不包括 MATLAB 進行的一些優化)! 請注意,MATLAB 給出了一個警告:

“變數’a’似乎在每次迴圈迭代時改變大小。考慮預先分配速度。”

我們預先分配時會發生什麼?

a=zeros(1,n);
tic
for i = 2:n
    a(i) = sqrt(a(i-1)) + i;
end
toc

Elapsed time is 0.410531 seconds.

我們可以看到執行時間減少了一個數量級。

預分配方法:

MATLAB 根據使用者的具體要求提供各種向量和矩陣分配功能。這些包括: zerosonesnaneyetrue 等。

a = zeros(3)       % Allocates a 3-by-3 matrix initialized to 0
a =

     0     0     0
     0     0     0
     0     0     0

a = zeros(3, 2)     % Allocates a 3-by-2 matrix initialized to 0
a =

     0     0
     0     0
     0     0

a = ones(2, 3, 2)      % Allocates a 3 dimensional array (2-by-3-by-2) initialized to 1
a(:,:,1) =

     1     1     1
     1     1     1

a(:,:,2) =

     1     1     1
     1     1     1

a = ones(1, 3) * 7  % Allocates a row vector of length 3 initialized to 7
a =

     7     7     7

還可以指定資料型別:

a = zeros(2, 1, 'uint8');  % allocates an array of type uint8

克隆現有陣列的大小也很容易:

a = ones(3, 4);       % a is a 3-by-4 matrix of 1's
b = zeros(size(a));  % b is a 3-by-4 matrix of 0's

並克隆型別:

a = ones(3, 4, 'single');       % a is a 3-by-4 matrix of type single
b = zeros(2, 'like', a);        % b is a 2-by-2 matrix of type single

注意’喜歡’也克隆了複雜性稀疏性

使用任何返回最終所需大小陣列的函式隱式實現預分配,例如 randgallerykronbsxfuncolon 等等。例如,分配具有線性變化元素的向量的常用方法是使用冒號運算子(使用 2 或 3 運算元變數 1 ):

a = 1:3 
a =

     1     2     3

a = 2:-3:-4
a =

     2    -1    -4

可以使用 cell() 函式分配單元陣列,其方式與 zeros() 非常相似。

a = cell(2,3)
a = 

    []    []    []
    []    []    []

請注意,單元格陣列的工作方式是將指標指向單元格內容的記憶體中的位置。因此,所有預分配技巧也適用於單個單元陣列元素。

進一步閱讀: