假設我有一個向量Q = [Q1 Q2 .... QN]。
我想創建一個矩陣A,使得矩陣的第k個“環”等于Qk,具有以下約束:
如果N是奇數,則中心補丁由一個數字組成,即QN
這Q = [12 3 27]將是:
A =
12 12 12 12 12
12 3 3 3 12
12 3 27 3 12
12 3 3 3 12
12 12 12 12 12
如果N是偶數,則中央補丁是QN重復的 2x2 補丁
因為Q = [12 3]這將是
A =
12 12 12 12
12 3 3 12
12 3 3 12
12 12 12 12
兩個 for 回圈
兩個 for 回圈可以作業,但速度太慢(5000x5000 矩陣約 13.3 秒)(代碼如下):
%% Two for loops :
% Generate random integer vector Q with unique values
N = 5;
n = 15 * N;
Q = randperm(n,N).';
% Double for loop method
if mod(N,2)==1
mSize = 2*N-1;
else
mSize = 2*N;
end
A = zeros(mSize);
for ii=1:(mSize)
for jj=1:(mSize)
IDX = min([ii,jj,mSize-ii 1,mSize-jj 1]);
A(ii,jj) = Q(IDX);
end
end
更快的方法
我找到了一種更快的方法,它非常好(5000x5000 矩陣約為 1.46 秒),但可能仍有一些改進空間:
if mod(N,2)==1
mSize = 2*N-1;
I_idx = (1:mSize)-N;
A_fast = Q(end-max(abs(I_idx.'),abs(I_idx)));
else
I_idx = [(N-1):-1:0 0:(N-1)];
A_fast = Q(end-max(I_idx.',I_idx));
end
有任何想法嗎?
uj5u.com熱心網友回復:
如果您遵循Wolfie 評論中的建議,代碼的邏輯會稍微簡單一些,并且只計算您重復的一個象限:
I_idx = 1:N;
B = Q(min(I_idx,I_idx.'));
if mod(N,2)==1
B = [B,B(:,end-1:-1:1)]; % same as [B,fliplr(B(:,1:end-1))]
B = [B;B(end-1:-1:1,:)]; % same as [B;flipud(B(1:end-1,:))]
else
B = [B,fliplr(B)];
B = [B;flipud(B)];
end
這取決于Q是偶數還是奇數大小,速度是 2-2.5 倍。
史蒂夫的評論建議先建立一個三角形,但我認為這不會更快,因為索引矩陣的上三角形或下三角形很復雜。
測驗代碼:
N = 5000;
n = 15 * N;
Q = randperm(n,N).';
tic
if mod(N,2)==1
mSize = 2*N-1;
I_idx = (1:mSize)-N;
A = Q(end-max(abs(I_idx.'),abs(I_idx)));
else
I_idx = [(N-1):-1:0 0:(N-1)];
A = Q(end-max(I_idx.',I_idx));
end
toc
tic
I_idx = 1:N;
B = Q(min(I_idx,I_idx.'));
if mod(N,2)==1
B = [B,B(:,end-1:-1:1)];
B = [B;B(end-1:-1:1,:)];
else
B = [B,fliplr(B)];
B = [B;flipud(B)];
end
toc
isequal(A,B)
uj5u.com熱心網友回復:
我想出了一個使用 repmat 的解決方案,然后沿對角線翻轉以獲得解決方案的四分之一,最后翻轉和反轉兩次以獲得完整的輸出矩陣。
function A = flip_it_and_reverse_it(Q)
N = length(Q);
QQ = repmat(Q(:), 1, N);
quarter_A = triu(QQ) triu(QQ, 1).';
half_A = [quarter_A, quarter_A(:, end-1:-1:1)];
A = [half_A; half_A(end-1:-1:1, :)];
end
可以通過一些巧妙的轉置進行改進,以獲得更快的翻轉/反轉。
對于更新問題中的偶數情況,以half_A和開頭的行中的索引A應該end:-1:1代替end-1:-1:1.
運行一些快速計時,看起來我的解決方案與您的更快方法相當(有時稍慢):
N = 5000;
n = 15 * N;
Q = randperm(n,N).';
disp('double loop')
tic
double_loop(Q);
disp(toc)
disp('faster approach')
tic
faster_approach(Q);
disp(toc)
disp('flip_it_and_reverse_it')
tic
flip_it_and_reverse_it(Q);
disp(toc)
結果:
double loop
14.4767
faster approach
1.8137
flip_it_and_reverse_it
1.6556
注意:有時faster_approach會贏,有時flip-我的筆記本電腦上正在運行其他一些作業。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/481551.html
上一篇:連續JOIN和別名:執行順序
