N次矩阵旋转错误

时间:2016-01-30 10:37:32

标签: c# algorithm

我有一项任务是旋转具有n列和m行的2D矩阵R`times enter image description here。旋转应沿逆时针方向旋转。

我的代码存在以下问题:

  1. 看起来StepValuesOperation方法错误地从矩阵中获取或设置了值。我已经打破了头脑,找出问题所在。
  2. 是否可以旋转值而不将其移动到分离的数组中?
  3. 关于代码:

    • 我有一个控制台应用程序,它通过InitializeParams方法随机初始化矩阵大小,其值和旋转计数;
    • 我得到了矩阵的迭代次数,并且每次都通过StepValuesOperation方法得到当前迭代的值数组;
    • 根据旋转计数,可能大于当前迭代中的位数,我通过rotCount操作得到mod
    • 然后按RorateValues方法旋转值,并按StepValuesOperation

      将其移回矩阵
      private static void Main(string[] args)
      {
          int m, r, n;
          long[,] matrix;
          InitializeParams(out n, out m, out r, out matrix);
      
          Console.WriteLine("Rotation times: " + r);
          Console.WriteLine("Input matrix:");
          PrintMatrix(matrix);
      
          Console.WriteLine();
          int deep = Math.Min(m, n) / 2;
          for (int step = 0; step < deep; step++)
          {
              List<long> oldArr = new List<long>((n + m) * 2);
              StepValuesOperation(false, step, oldArr, matrix);
      
              int perim = oldArr.Count;
              int rotCount = perim < r ? r % perim : r;
              if (rotCount != 0 && rotCount != perim)
              {
                  long[] newArr = new long[perim];
                  Console.WriteLine($"Rest rotation count {rotCount} from {r} with perimeter {perim}");
                  Console.WriteLine(string.Join(", ", oldArr));
      
                  RorateValues(rotCount, newArr, oldArr);
      
                  Console.WriteLine(string.Join(", ", newArr));
                  StepValuesOperation(true, step, newArr, matrix);
              }
      
              Console.WriteLine();
          }
      
      
          Console.WriteLine();
          Console.WriteLine("Output matrix:");
          PrintMatrix(matrix);
          Console.ReadLine();
      }
      
      private static void RorateValues(int rotCount, IList<long> newArr, IList<long> oldArr)
      {
          int perim = oldArr.Count;
          for (int i = 0; i < perim; i++)
          {
              int pos = i + rotCount;
              if (pos >= perim)
              {
                  pos -= perim;
              }
      
              newArr[pos] = oldArr[i];
          }
      }
      

    矩阵的随机初始化参数

        private static void InitializeParams(out int n, out int m, out int r, out long[,] matrix)
        {
            Random rand = new Random();
            n = 4;//rand.Next(2, 7) * 2;
            m = 6;//rand.Next(1, 5) * 2;
            r = rand.Next(1, 10000);
            matrix = new long[n, m];
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < m; j++)
                {
                    matrix[i, j] = rand.Next(i + j, i + j + n * 10);
                }
            }
        }
    

    移出或填充矩阵

    的值
        private static void StepValuesOperation(bool initialized, int step, IList<long> arr, long[,] matrix)
        {
            int sizeI = matrix.GetLength(0) - step;
            int sizeJ = matrix.GetLength(1) - step;
            int pos = 0;
            for (int i = step; i < sizeI; i++, pos++)
            {
                if (!initialized)
                    arr.Add(matrix[i, step]);
                else
                    matrix[i, step] = arr[pos];
            }
            for (int j = step; j < sizeJ; j++, pos++)
            {
                if (!initialized)
                    arr.Add(matrix[sizeI - 1, j]);
                else
                    matrix[sizeI - 1, j] = arr[pos];
            }
            for (int i = sizeI - 1; i > step; i--, pos++)
            {
                if (!initialized)
                    arr.Add(matrix[i, sizeJ - 1]);
                else
                    matrix[i, sizeJ - 1] = arr[pos];
            }
            for (int j = sizeJ - 1; j > step; j--, pos++)
            {
                if (!initialized)
                    arr.Add(matrix[step, j]);
                else
                    matrix[step, j] = arr[pos];
            }
        }
    
        private static void PrintMatrix(long[,] matrix)
        {
            int n = matrix.GetLength(0);
            int m = matrix.GetLength(1);
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < m; j++)
                    Console.Write(matrix[i, j] + " ");
                Console.WriteLine();
            }
        }
    

    我的错误输出:

      

    轮换时间:9402

         

    输入矩阵:

         

    29 3 24 9 39 28

         

    9 38 31 20 24 44

         

    27 27 38 31 10 37

         

    32 15 25 40 40 42

         

    输出矩阵:

         

    44 37 42 42 40 40

         

    28 20 24 10 10 25

         

    39 38 27 27 31 15

         

    24 3 29 9 27 32

2 个答案:

答案 0 :(得分:1)

是的,轮换可以就地完成。我不是 C#程序员,所以我坚持 C ++ 语法非常接近。

  1. 我会创建旋转矩形周长的功能

    可以使用单个临时值(与 jackmott 建议完全相同)来完成。像这样的东西:

    void matrix_rect_ccw(int **a,int x0,int y0,int xs,int ys)
        {
        int x,y,xx,yy,x1,y1,a0;
        // prepare constants
        x1=x0+xs-1;
        y1=y0+ys-1;
        // rotate CCW
        a0=a[x0][y0];   // store first element to temp
        x=x0; y=y0;     // destination
        xx=x; yy=y;     // source
        for (xx++;x<x1;x++,xx++) a[x][y]=a[xx][yy]; xx--;
        for (yy++;y<y1;y++,yy++) a[x][y]=a[xx][yy]; yy--;
        for (xx--;x>x0;x--,xx--) a[x][y]=a[xx][yy]; xx++;
        for (yy--;y>y0;y--,yy--) a[x][y]=a[xx][yy]; yy++;
        a[x0][y0+1]=a0; // restore last element from temp
        }
    

    其中x0,y0是矩形的左上角,xs,ys是其大小。 a[][]是矩阵。如果矩形完全位于...

    ,则无需矩阵大小参数

    要进行调试,您可以使用增加索引来旋转填充循环,例如:

    int i=0;
    for (xx++;x<x1;x++,xx++,i++) a[x][y]=i; xx--;
    for (yy++;y<y1;y++,yy++,i++) a[x][y]=i; yy--;
    for (xx--;x>x0;x--,xx--,i++) a[x][y]=i; xx++;
    for (yy--;y>y0;y--,yy--,i++) a[x][y]=i; yy++;
    

    或:

    int i=0;
    for (xx++;x<x1;x++,xx++,i++) a[xx][yy]=i; xx--;
    for (yy++;y<y1;y++,yy++,i++) a[xx][yy]=i; yy--;
    for (xx--;x>x0;x--,xx--,i++) a[xx][yy]=i; xx++;
    for (yy--;y>y0;y--,yy--,i++) a[xx][yy]=i; yy++;
    

    因此,您可以检查迭代是否以正确的顺序通过正确的元素。这是(x,y)调用所有循环的结果:

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

    这是(xx,yy)案例:

      13   0   1   2   3
      12   5   0   1   4
      11   4   3   2   5
      10   9   8   7   6
    
  2. 执行for循环以旋转整个矩阵

    只需为所有循环调用#1 的旋转。还有整整step次。像这样:

    void matrix_ccw(int **a,int xs,int ys,int step)
        {
        int i,j,n;
        // smallest size / 2 ... number of loops to rotate
        n=xs; if (n<ys) n=ys; n/=2;
        for (j=0;j<step;j++)
         for (i=0;i<n;i++)
          matrix_rect_ccw(a,i,i,xs-i-i,ys-i-i);
        }
    

    只需更改#1 中的for循环顺序,即可单独处理CW / CCW。您还应该将步长绑定到模数循环大小。如果步长较大,则循环大小的一半然后将其转换为反向旋转以加速该过程。这是我测试的输入矩阵:

      11  12  13  14  15
      21  22  23  24  25
      31  32  33  34  35
      41  42  43  44  45
    

    这在 CCW 方向上由step=1轮换:

      12  13  14  15  25
      11  23  24  34  35
      21  22  32  33  45
      31  41  42  43  44
    

    您还应该处理无效的矩阵大小以便轮换,以避免在将来使用时出现混淆......

  3. <强> [注释]

    旋转也可以在没有步骤循环整个事件的情况下通过直接复制step偏移来完成,但为此你需要存储a0[step]值而不是单一的值使这一点复杂化。

答案 1 :(得分:0)

我想知道你是否可以通过将外部点表示为一个循环链接列表而将内部点表示为另一个来简化它。然后使用单个临时变量将它们旋转到位变得非常容易。如果性能是一个问题,你可以为每个使用一维数组,只需处理开始和结束时的边缘情况。

编辑 - 看起来算法必须更加通用,这意味着“n”循环链接列表,这可能不是更简单。