Matlab小练习:按照对角线方向依次分配矩阵

 2024-02-11 05:02:46  阅读 0

这个问题来自知乎,我觉得挺有趣的。 在留给学生回答的同时,我也思考了一下,想出了三个解决办法。

主题如下:

matlab取矩阵中的元素_matlab取矩阵中的元素_matlab取矩阵的元素

以n=80为例,

———————————————————————

1、首先根据n确定矩阵的阶k。

如果你首先生成一个足够大的矩阵,然后删除所有零列,那就有点太低了。 那么首先想一个算法:

观察数据放置的特点,不难发现这样的关系:

\frac{k(k-1)}{2} < n \leq \frac{k(k+1)}{2}

形变:

k^2-k < 2n \leq k^2+k

观察到,如果 k 足够大,k^2 起着决定性作用,\sqrt{2n} 必须四舍五入为 k

k(或n)更小,对吗? 试一试。

测试 n=1 到 56:

n=1:56;
round(sqrt(2*n))

正好!

2. 按斜杠顺序放置 1 \sim n

无非是找到放置模式和放置数字。 放置意味着使用行和列标签来分配值,因此它是找到行和列标签模式。

首先写下一个数的方便观察模式,例如n=20

方法1.分别在行和列标签中查找模式

1 \sim n 按顺序赋值

行标签:1; 〜1,2; 〜1,2,3; ~1,2,3,4; ~1,\cdots 总共k组n个数字

列标签:1; 〜2,1;〜3,2,1; ~4,3,2,1; ~5, \cdots 总共 k 组 n 个数字

(因为有k个斜杠)

这种情况下,只需按照上述规则生成(拼接)行标签和列标签,然后赋值即可。

写入函数

function A=DiagNum1(n)
k=round(sqrt(2*n));  %确定矩阵阶数k
A=zeros(k);
%% 生成行标, 列标
I=[];
J=[];
for i=1:k
    I=[I,1:i];
    J=[J,i:-1:1];
end
IND=sub2ind(size(A),I,J); %二维索引转化为一维索引
A(IND(1:n))=1:n;

注意,生成行列索引后,[I,J]作为二维索引值,不能直接使用A([I,J]) = 1:n进行赋值,所以做了二维索引转化为一维索引。 指数转换。

测试功能:

DiagNum1(80)

方法 2. 通过行和列标签一起查找模式

1 \sim n 按顺序赋值

行和列标签:(1,1); 〜(1,2),(2,1); 〜(1,3),(2,2),(3,1); 〜(1,4),(2,3),\cdots

首先是“sum is 2”,然后是“sum is 3”,然后是“sum is 4”,...; 在每个子组中,行标签从小到大排列。

因此,首先生成所有行和列标签组合(1\sim n 和 1 \sim n 的笛卡尔积)。 第一个关键字按“行和列标签之和”排序,然后第二个关键字按行标签排序。 ,按顺序取出前n个,依次赋值1\sim n。

写入函数:

function A=DiagNum2(n)
k=round(sqrt(2*n));  %确定矩阵阶数k
A=zeros(k);
%% 生成所有下标组合(笛卡尔积)
[X,Y]=meshgrid(1:n,1:n);
subn=[X(:),Y(:)];
%% 选取索引并赋值
ind=sortrows([subn,sum(subn,2)],3); %对下标求和, 按该和排序, 已经满足要求
IND=sub2ind(size(A), ind(1:n,1),ind(1:n,2)); %选出前n个二维索引, 并转化为一维
A(IND)=1:n;

测试功能(略)

方法三、使用循环语句实现

使用循环语句控制行列标签按照这个规则出现,并按顺序赋值:

(1,1) \quad k=1 \quad i=1 \quad j=1 \\ (1,2) \quad k=2 \quad i=1 \quad j=2 \\ (2,1) \四边形 k=2 \quad i=2 \quad j=1 \\ (1,3) \quad k=3 \quad i=1 \quad j=3 \\ (2,2) \quad k=3 \quad i=2 \quad j=2 \\ (3,1) \quad k=3 \quad i=3 \quad j=1 \\ \cdots \cdots

写入函数:

function A=DiagNum3(n)
k=round(sqrt(2*n));  %确定矩阵阶数k
A=zeros(k);
val=1;
for m=1:k
    for i=1:m
        A(i,m+1-i)=val;
        val=val+1;
        if val>n
            break;
        end
    end
end

注意,外层循环使用m来控制从第1列开始到第k列的对角线; 对于每条对角线,i首先从1循环到m; 并且总是存在 i+j=m+1。

测试功能(略)

3.稍微改进一下

仅分配 1 \sim n 不太实用。 如果我们改进它,将给定向量 V 的 V 中的值分配给对角线方向的矩阵会怎么样?

这很简单。 将参数从n改为向量V,那么V的长度就是需要的n,然后将最终赋值时使用的1:n换成V。

改进的第一个功能:

function A=DiagNum1(V)
n=length(V);
k=round(sqrt(2*n));  %确定矩阵阶数k
A=zeros(k);
%% 生成行标, 列标
I=[];
J=[];
for i=1:k
    I=[I,1:i];
    J=[J,i:-1:1];
end
IND=sub2ind(size(A),I,J); %二维索引转化为一维索引
A(IND(1:n))=V;

改进的第二个功能:

function A=DiagNum2(V)
n=length(V);
k=round(sqrt(2*n));  %确定矩阵阶数k
A=zeros(k);
%% 生成所有下标组合(笛卡尔积)
[X,Y]=meshgrid(1:n,1:n);
subn=[X(:),Y(:)];
%% 选取索引并赋值
ind=sortrows([subn,sum(subn,2)],3); %对下标求和, 按该和排序
IND=sub2ind(size(A), ind(1:n,1),ind(1:n,2)); %选出前n个二维索引, 并转化为一维
A(IND)=V;

改进的第三个函数(略有不同):

function A=DiagNum3(V)
n=length(V);
k=round(sqrt(2*n));  %确定矩阵阶数k
A=zeros(k);
val=1;
for m=1:k
    for i=1:m
        A(i,m+1-i)=V(val);
        val=val+1;
        if val>n
            break;
        end
    end
end

如果你仍然想得到原来问题的结果,只需像这样调用函数:

DiagNum1(1:n)
DiagNum2(1:n)
DiagNum3(1:n)

标签: 索引 矩阵 函数

如本站内容信息有侵犯到您的权益请联系我们删除,谢谢!!


Copyright © 2020 All Rights Reserved 京ICP5741267-1号 统计代码