【问题标题】:Build the matrix of all the combinations of given numbers using recursion [matlab]使用递归[matlab]构建给定数字的所有组合的矩阵
【发布时间】:2023-04-01 05:00:01
【问题描述】:

假设我们有向量v=[1,2,3],我们想要构建包含在v 中的所有数字组合的矩阵,即

 1     2     3
 1     3     2
 2     1     3
 2     3     1
 3     1     2
 3     2     1

由于我不擅长递归,首先我尝试编写代码来使用for循环构建这样一个矩阵

makeLoop([1,2,3])

function A = makeLoop(v)
    loops=length(v);
    for i = 1:loops
        dummy=v;
        m=factorial(loops)/loops;
        A((1+m*(i-1)):m*i,1)=v(i);
        v(i)=[];
        loops2=length(v);
        for j = 1:loops2
            dummy2=v;
            m2=factorial(loops2)/loops2;
            A(((1+m2*(j-1))+m*(i-1)):(m2*j+m*(i-1)),2)=v(j);
            v(j)=[];
            loops3=length(v);
            for k = 1:loops3
                m3=factorial(loops3)/loops3;
                A(((1+m2*(j-1))+m*(i-1)):(m2*j+m*(i-1)),3)=v(k);
            end
            v=dummy2;
        end
        v=dummy;
    end
end

它似乎可行,但显然为更大的v 写这一切就像地狱一样。无论如何我不明白如何正确编写递归,我认为递归结构将是这样的

function A = makeLoop(v)
if length(v)==1
    "do the last for loop"
else
    "do a regular loop and call makeLoop(v) (v shrink at each loop)"
end

但我不知道应该从原始代码中删除哪些部分,以及保留哪些部分。

【问题讨论】:

    标签: matlab matrix combinations


    【解决方案1】:

    你很亲密!您提出的整体结构是合理的,您的循环代码可以插入其中,几乎不需要任何更改:

    function A = makeLoop(v)
    % number of (remaining) elements in the vector
    loops = length(v);
    
    if loops==1 %"do the last for loop"
        A = v; %Obviously, if you input only a single number, the output has to be that number
    
    else %"do a regular loop and call makeLoop(v) (v shrink at each loop)"
        %preallocate matrix to store results
        A = zeros(factorial(loops),loops);
        %number of results per vector element
        m = factorial(loops)/loops;
    
        for i = 1:loops
            %For each element of the vector, call the function again with that element missing.
            dummy = v;
            dummy(i) = [];
            AOut = makeLoop(dummy);
            %Then add that element back to the beginning of the output and store it.
            A((1+m*(i-1)):m*i,:) = [bsxfun(@times,v(i),ones(m,1)) AOut];
        end
    end
    

    解释bsxfun()线:

    首先,阅读bsxfun documentation,它解释了它是如何工作的,比我做得更好。但长话短说,使用bsxfun(),我们可以通过将标量与一列向量相乘来轻松复制标量。例如。 bsxfun(@times,5,[1;1;1]) 将产生向量 [5;5;5]。请注意,从 Matlab 2016b 开始,bsxfun(@times,5,[1;1;1]) 可以写成更短的 5.*[1;1;1]

    对于手头的任务,我们想在它之后可能发生的所有排列的前面(作为第一列)添加v(i)。因此我们需要将v(i)复制到1.维度以匹配AOut的行数,这通过bsxfun(@times,v(i),ones(m,1))完成。然后我们将其与AOut 水平连接。

    【讨论】:

    • 感谢您的回复。哦,这只是if 声明中的A = v...比我想象的要简单!你能解释一下[bsxfun(@times,v(i),ones(m,1)) AOut]这行吗?您正在创建一个矩阵,但我之前从未见过bsxfun,它是如何工作的?总之非常感谢^^
    【解决方案2】:

    您可以简单地使用perms function 来实现:

    v = [1 2 3];
    perms(v)
    
    ans =
          3     2     1
          3     1     2
          2     3     1
          2     1     3
          1     3     2
          1     2     3
    

    如果您希望使用在所需输出中应用的相同标准对它们进行排序,请使用以下代码(请参阅 this page 以获取 sortrows 函数的官方文档):

    v = [1 2 3];
    p = perms(v);
    p = sortrows(p)
    
    p =   
        1     2     3
        1     3     2
        2     1     3
        2     3     1
        3     1     2
        3     2     1
    

    【讨论】:

    • 感谢您的回复,我已经知道 perms 函数,但我试图了解递归在这种情况下是如何工作的,因为我必须解决一个更困难的问题,它是概念上的类似于我的问题中的问题,但我不能使用 perms 函数。我必须使用递归,因为循环的数量取决于某个矩阵的大小。
    • 好的,这里的问题是内部循环的一部分依赖于外部循环(请参阅j)...实际上,我想说的不仅仅是递归,您需要实现相同的逻辑直到条件用尽(例如,v 的列将在计算中使用)。另一种方法是将所有内容矢量化...我必须考虑如何做到这一点,老实说,如果我不知道您要做什么,我将很难弄清楚。
    猜你喜欢
    • 2012-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-07
    • 1970-01-01
    • 2016-10-14
    • 1970-01-01
    • 2016-06-13
    相关资源
    最近更新 更多