创建一个“金字塔”矩阵。

13
假设给定一个长度为奇数的对称行向量,向量中前半部分每个元素都比后面的元素小,后半部分每个元素都比下一个元素大,中间的元素最大。(例如[1 2 3 2 1][10 20 50 20 10])。
我想创建一个正方形矩阵,其中这个行向量是它的中间行,相应的列向量 (v') 是其中间列,每一行或每一列的“原始元素”都是给定向量根据该行或列的中间元素缩减而来。当没有更多的“原始元素”时,我们放置0
例如: 如果 v = [1 2 3 2 1],则得到以下结果:
0 0 1 0 0  
0 1 2 1 0  
1 2 3 2 1  
0 1 2 1 0  
0 0 1 0 0

如果 v = [3 5 3],我们会得到

0 3 0  
3 5 3  
0 3 0  

我的所作所为:我写了以下代码,成功创建了一个以v作为中间行,v'作为中间列的矩阵:

s = length(vector);
matrix= zeros(s);
matrix(round(s/2),:) = vector;
matrix(:, round(s/2)) = vector';

但在指定其他值时卡住了。

3个回答

9

更加实用的方法是将矩阵作为马赛克来制作,从一个 hankel 矩阵开始。为了进行性能比较,这里提供了一种使用与 @Divakar 的解决方案 相同格式的版本:

function out=pyramid_hankel(v)

%I suggest checking v here
%it should be odd in length and a palindrome    

i0=ceil(length(v)/2);
v2=v(i0:end);

Mtmp=hankel(v2);
out=zeros(length(v));
out(i0:end,i0:end)=Mtmp;
out(1:i0-1,i0:end)=flipud(Mtmp(2:end,:));
out(:,1:i0-1)=fliplr(out(:,i0+1:end));

>> pyramid_hankel([1 2 3 2 1])

ans =

     0     0     1     0     0
     0     1     2     1     0
     1     2     3     2     1
     0     1     2     1     0
     0     0     1     0     0

对于v=[1 2 3 2 1],起始块是hankel([3 2 1]),即

ans =

     3     2     1
     2     1     0
     1     0     0

从这里开始,应该清楚正在发生什么。


1
@Adrian 和 @AndrasDeak:hankel 函数在内部使用 bsxfun - horchler
哦,不要这样!我使用bsxfun的方式与使用bsxfun实现hankel的方式不相似。据我所知,hankelbsxfun(@plus) - Divakar

8
这里有一种方法 -
function out = pyramid(v)

hlen = (numel(v)+1)/2;
updown_vec = [1:(numel(v)+1)/2 (numel(v)-1)/2:-1:1];
upper_part = cumsum(bsxfun(@le,(hlen:-1:1)',updown_vec));  %//'
out = [upper_part ; flipud(upper_part(1:end-1,:))];
out = changem(out,v,updown_vec);

这里有另一种方法,可能更简单 -
function out = pyramid_v2(v)

hlen = (numel(v)+1)/2;
updown_vec = [1:(numel(v)+1)/2 (numel(v)-1)/2:-1:1];
mask = bsxfun(@le,([hlen:-1:1 2:hlen])',updown_vec); %//'
M = double(mask);
M(hlen+1:end,:) = -1;
out = changem(cumsum(M).*mask,v,updown_vec);

样例运行 -

>> v = [1 2 3 2 1];
>> pyramid(v)
ans =
     0     0     1     0     0
     0     1     2     1     0
     1     2     3     2     1
     0     1     2     1     0
     0     0     1     0     0
>> v = [3 5 3];
>> pyramid(v)
ans =
     0     3     0
     3     5     3
     0     3     0

>> v = [99,3,78,55,78,3,99];
>> pyramid(v)
ans =
     0     0     0    99     0     0     0
     0     0    99     3    99     0     0
     0    99     3    78     3    99     0
    99     3    78    55    78     3    99
     0    99     3    78     3    99     0
     0     0    99     3    99     0     0
     0     0     0    99     0     0     0

@Mikhail_Sam 感谢您在基准测试方面的努力!所以,您测试的是“_v2”版本,对此表示感谢 :) - Divakar
谢谢@Mikhail_Sam的反馈!:)正是我想知道的。我并不奇怪Divakar的方法更快,只是有点抱歉偷了答案:P Mikhail:就我所知,如果没有发现hankel,我也不会尝试回答它。我意识到如果没有必要的内置函数,Divakar用bsxfun绝对会打败我;) - Andras Deak -- Слава Україні
@Divakar 不是,我试过 v1。我有一个问题:updown_vec = [1:(numel(v)+1)/2 (numel(v)-1)/2:-1:1]; - updown_vec 总是返回与 v 相同的向量。对我有什么用处? - Mikhail_Sam
@Mikhail_Sam 我认为这并不适用于 v = [99,3,78,55,78,3,99];。我只在最后使用 changem 时才使用 v - Divakar
@Divakar,我看了你的例子,遇到了一些问题:请看看你的v2方法!我认为M(hlen+1,:) = -1;有错误。 - Mikhail_Sam
显示剩余4条评论

5

以下是另一种方法:

v = [1 2 3 2 1]; %// symmetric, odd size
m = (numel(v)-1)/2;
w = [0 v(1:m+1)];
t = abs(-m:m);
result = w(max(m+2-bsxfun(@plus, t, t.'),1));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接