【问题标题】:Matrix and algorithm "spiral"矩阵和算法“螺旋”
【发布时间】:2012-01-06 12:02:38
【问题描述】:

我想问是否有一些算法准备好了,让我可以这样做:我有一个矩阵 m (col) x n (row) 和 m x n 个元素。我想给这个元素一个位置,从中心开始并像螺旋一样旋转,例如,对于一个 3x3 的矩阵,我有 9 个这样定义的元素:

 5  6  7
 4  9  8
 3  2  1 

或者对于 una 矩阵 4 x 3 我有 12 个元素,请定义:

  8   9  10  1
  7  12  11  2
  6   5   4  3

或者再次,一个 5x2 的矩阵我有 10 个这样定义的元素:

    3  4
    7  8
   10  9
    6  5 
    2  1

等等。 我基本上已经解决了定义一个 m x n 元素的整数数组并手动加载该值,但总的来说,我喜欢由算法自动生成的矩阵。 感谢谁能帮我找到这样的东西,非常感谢。

更新

这段代码完全符合我的要求,但不是在 delphi 中;只是我需要从 1 开始而不是从 0 开始。对我来说重要的是它对任何矩阵 m x n 都有效。谁帮我用delphi翻译一下?

(defun spiral (rows columns)  
  (do ((N (* rows columns))       
    (spiral (make-array (list rows columns) :initial-element nil))      
    (dx 1) (dy 0) (x 0) (y 0)    
   (i 0 (1+ i)))     
 ((= i N) spiral)   
 (setf (aref spiral y x) i)
    (let ((nx (+ x dx)) (ny (+ y dy)))  
    (cond       
       ((and (< -1 nx columns)       
       (< -1 ny rows)           
       (null (aref spiral ny nx)))    
    (setf x nx 
          y ny))  
     (t (psetf dx (- dy)                 
       dy dx)       
    (setf x (+ x dx)             
     y (+ y dy))))))) 


> (pprint (spiral 6 6))

#2A ((0  1  2  3  4  5)
    (19 20 21 22 23  6)
    (18 31 32 33 24  7)
    (17 30 35 34 25  8)
    (16 29 28 27 26  9)
    (15 14 13 12 11 10))


> (pprint (spiral 5 3))

#2A  ((0  1 2)
     (11 12 3)
     (10 13 4)
      (9 14 5)
      (8 7 6))

再次非常感谢。

【问题讨论】:

  • 在我看来,您的算法还没有明确定义。我预计 5x2 矩阵是 ((6 7) (5 8) (4 9) (3 10) (2 1))。
  • 我和大卫在一起。为什么1在不同的地方开始?每次都应该是同一个角落。
  • 我不懂你的算法。这是不一致的。例如 3x3 的经典螺旋算法应该是:(1 2 3)(8 9 4)(7 6 5)take a look here.
  • 你好,很可能我没有正确地告诉“螺旋”。这只是为了说明矩阵中的数字被放置设计一个螺旋例如6个数字它从6到1开始:6、5、4、3、2、1。元素6放置在矩阵的中心,并且矩阵的索引从左向右旋转为螺旋形。有这样的结果,如示例。再次原谅我糟糕的英语。如此设置此元素的矩阵将应用于随机数。
  • 首先,您可以在这里查看technicalinterviewquestions.net/2009/03/…

标签: algorithm delphi matrix delphi-xe2 spiral


【解决方案1】:

基于经典的spiral algorithm。支持非方阵:

program SpiralMatrix;
{$APPTYPE CONSOLE}
uses
  SysUtils;

type
  TMatrix = array of array of Integer;

procedure PrintMatrix(const a: TMatrix);
var
  i, j: Integer;
begin
  for i := 0 to Length(a) - 1 do
  begin
    for j := 0 to Length(a[0]) - 1 do
      Write(Format('%3d', [a[i, j]]));
    Writeln;
  end;
end;

var
  spiral: TMatrix;
  i, m, n: Integer;
  row, col, dx, dy,
  dirChanges, visits, temp: Integer;
begin
  m := 3; // columns
  n := 3; // rows
  SetLength(spiral, n, m);
  row := 0;
  col := 0;
  dx := 1;
  dy := 0;
  dirChanges := 0;
  visits := m;
  for i := 0 to n * m - 1 do
  begin
    spiral[row, col] := i + 1;
    Dec(visits);
    if visits = 0 then
    begin
      visits := m * (dirChanges mod 2) + n * ((dirChanges + 1) mod 2) - (dirChanges div 2) - 1;
      temp := dx;
      dx := -dy;
      dy := temp;
      Inc(dirChanges);
    end;
    Inc(col, dx);
    Inc(row, dy);
  end;
  PrintMatrix(spiral);
  Readln;
end.

3 x 3:

1  2  3
8  9  4
7  6  5

4 x 3:

 1  2  3  4
10 11 12  5
 9  8  7  6

2 x 5:

 1  2
10  3
 9  4
 8  5
 7  6

【讨论】:

    【解决方案2】:

    给你!!!经过 30 次语法错误...

    ideone.com 上,我进行了一些测试,它似乎运行良好。我认为您仍然可以在那里看到输出并自己运行它...

    我在代码中加入了一些 cmets。足以理解大部分内容。主导航系统有点难以解释。简而言之,做一个螺旋是在第一个方向 1 次,第二个 1 次,第三个 2 次,第四个 2 次,第五个 3 次,3、4、4、5、5,等等。我使用我所谓的 seedstep 来获得这种行为。

    program test;
    
    var
        w, h, m, n, v, d : integer; // Matrix size, then position, then value and direction.
        spiral : array of array of integer; // Matrix/spiral itself.
        seed, step : integer; // Used to travel the spiral.
    
    begin
        readln(h);
        readln(w);
        setlength(spiral, h, w);
        v := w * h; // Value to put in spiral.
        m := trunc((h - 1) / 2);  // Finding center.
        n := trunc((w - 1) / 2);
        d := 0; // First direction is right.
    
        seed := 2;
        step := 1;
    
        // Travel the spiral.
        repeat
            // If in the sub-spiral, store value.
            if ((m >= 0) and (n >= 0) and (m < h) and (n < w)) then
            begin
                spiral[m, n] := v;
                v := v - 1;
            end;
    
            // Move!
            case d of
                0: n := n + 1;
                1: m := m - 1;
                2: n := n - 1;
                3: m := m + 1;
            end;
    
            // Plan trajectory.
            step := step - 1;
            if step = 0 then
            begin
                d := (d + 1) mod 4;
                seed := seed + 1;
                step := trunc(seed / 2);
            end;
        until v = 0;
    
        // Print the spiral.
        for m := 0 to (h - 1) do
        begin
            for n := 0 to (w - 1) do
            begin
                write(spiral[m, n], ' ');
            end;
            writeln();
        end;
    
    end.
    

    如果你真的需要它来打印文本螺旋,我会让你对齐数字。只需用空格填充它们。

    编辑:

    忘记了...为了让它在ideone上工作,我把参数放在2行作为输入。 m,然后是 n。

    例如:

    5
    2
    

    产量

    3 4 
    7 8 
    10 9 
    6 5 
    2 1 
    

    【讨论】:

    • 非常感谢乔尼斯。这个解决方案是关于我搜索的,它工作得非常好。再次感谢;感谢所有其他也帮助过我的人。
    • 当我用 2x2 和 4x3 测试时,它产生了一些奇怪的螺旋
    • @kobik:是的,并非所有案例都给出了我们真正所谓的螺旋。中心由floor((height-1)/2)floor((width-1)/2) 定义,方向顺序从“右”开始,然后是“上”……这就是奇怪的非螺旋线的原​​因。 2x2 的中心在 (0, 0)=4,然后它移动到 (0, 1)=3,直到它变得“有意义”,但是我们必须往上走,没有任何东西往上走,所以我们走离开,回来,继续第二行的螺旋:2 和 1。这就是为什么你会得到奇怪的结果,比如 2x2 的 (4 3) (2 1)。
    【解决方案3】:

    这是您想要完成的已注释的 JavaScript 实现。

    // return an array representing a matrix of size MxN COLxROW
    function spiralMatrix(M, N) {
    var result = new Array(M * N);
    var counter = M * N;
    // start position
    var curCol = Math.floor((M - 1) / 2);
    var curRow = Math.floor(N / 2);
    // set the center
    result[(curRow * M) + curCol] = counter--;
    // your possible moves RIGHT, UP, LEFT, DOWN * y axis is flipped
    var allMoves = [[1,0], [0,-1], [-1,0], [0,1]];
    var curMove = 0;
    var moves = 1; // how many times to make current Move, 1,1,2,2,3,3,4,4 etc
    // spiral
    while(true) {
     for(var i = 0; i < moves; i++) {
      // move in a spiral outward counter clock-wise direction
      curCol += allMoves[curMove][0];
      curRow += allMoves[curMove][1];
      // naively skips locations that are outside of the matrix bounds
      if(curCol >= 0 && curCol < M && curRow >= 0 && curRow < N) {
       // set the value and decrement the counter
       result[(curRow * M) + curCol] = counter--;
       // if we reached the end return the result
       if(counter == 0) return result;
      }
     }
     // increment the number of times to move if necessary UP->LEFT and DOWN->RIGHT
     if(curMove == 1 || curMove == 3) moves++;
     // go to the next move in a circular array fashion
     curMove = (curMove + 1) % allMoves.length;
    }
    }
    

    代码不是最有效的,因为它天真地走着螺旋形,没有首先检查它所走的位置是否有效。它仅在尝试对其设置值之前检查当前位置的有效性。

    【讨论】:

      【解决方案4】:

      即使问题已经得到解答,这也是一种替代解决方案(可以说更简单)。 解决方案是在 python 中(使用 numpy 进行双向数组),但可以轻松移植。

      基本思想是利用步数已知(m*n)这一事实作为结束条件, 并在每次迭代时正确计算循环的下一个元素:

      import numpy as np
      
      def spiral(m, n):
          """Return a spiral numpy array of int with shape (m, n)."""
          a = np.empty((m, n), int)
          i, i0, i1 = 0, 0, m - 1
          j, j0, j1 = 0, 0, n - 1
          for k in range(m * n):
              a[i, j] = k
              if   i == i0 and     j0 <= j <  j1: j += 1
              elif j == j1 and     i0 <= i <  i1: i += 1
              elif i == i1 and     j0 <  j <= j1: j -= 1
              elif j == j0 and 1 + i0 <  i <= i1: i -= 1
              else:
                  i0 += 1
                  i1 -= 1
                  j0 += 1
                  j1 -= 1
                  i, j = i0, j0
          return a
      

      这里有一些输出:

      >>> spiral(3,3)
      array([[0, 1, 2],
             [7, 8, 3],
             [6, 5, 4]])
      >>> spiral(4,4)
      array([[ 0,  1,  2,  3],
             [11, 12, 13,  4],
             [10, 15, 14,  5],
             [ 9,  8,  7,  6]])
      >>> spiral(5,4)
      array([[ 0,  1,  2,  3],
             [13, 14, 15,  4],
             [12, 19, 16,  5],
             [11, 18, 17,  6],
             [10,  9,  8,  7]])
      >>> spiral(2,5)
      array([[0, 1, 2, 3, 4],
             [9, 8, 7, 6, 5]])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-07-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多