旋转矩阵

时间:2013-04-05 04:43:43

标签: c# winforms math matrix

目标

想象一下,我们有像

这样的矩阵
a11 a12 a13
a21 a22 a23
a31 a32 a33

我想要做的是,从文本框值旋转此矩阵,以便,例如,如果我写2并按 rotate ,程序必须保持矩阵的两个对角值(在这种情况下为a11, a22,a33,a13,a31)并顺时针旋转2次其他值。所以结果必须像

a11 a32 a13
a23 a22 a21
a31 a12 a33

它必须适用于所有N x N大小的矩阵,正如您所看到的,每4次旋转将矩阵置于默认状态。

我做了什么

所以想法就是这样,我有两种形式。首先获取矩阵的大小(1值,例如,如果它是5,则生成5x5矩阵)。当我按确定时,它会生成第二个表单文本框矩阵,如

表格1代码

    private void button1_Click(object sender, EventArgs e)
    {
        int matrixSize;
        matrixSize = int.Parse(textBox1.Text);
        Form2 form2 = new Form2(matrixSize);
        form2.Width = matrixSize * 50 + 100;
        form2.Height = matrixSize *60 + 200;
        form2.Show();            
        //this.Hide();
    }

表单2代码从给定值生成文本框矩阵,并将随机值放入此字段

public Form2(int matrSize)
        {
            int counter = 0;
            InitializeComponent();
            TextBox[] MatrixNodes = new TextBox[matrSize*matrSize];
            Random r = new Random();
            for (int i = 1; i <= matrSize; i++)
            {
                for (int j = 1; j <= matrSize; j++)
                {
                    var tb = new TextBox();                    
                    int num = r.Next(1, 1000);
                    MatrixNodes[counter] = tb;
                    tb.Name = string.Format("Node_{0}{1}", i, j);
                    Debug.Write(string.Format("Node_{0}{1}", i, j));
                    tb.Text = num.ToString();
                    tb.Location = new Point(j * 50, i * 50);
                    tb.Width = 30;
                    tb.Visible = true;
                    this.splitContainer1.Panel2.Controls.Add(tb);
                    counter++;
                }
            }

        }

表单2有1个用于控制旋转的文本框(其他文件框是以编程方式生成的)。我想要做的是,当我输入旋转计数并在此文本框中按 Enter 时,我想旋转文本框矩阵,如上所述。无法弄清楚该怎么做。

4 个答案:

答案 0 :(得分:9)

将两个对角线复制到单独的阵列,然后旋转矩阵并替换对角线。下面的代码显示了每个步骤:

class Program
{
    static void Main(string[] args)
    {
        int matrixSize = 3;
        string[,] matrix = new string[matrixSize,matrixSize];

        //create square matrix
        for (int x = 0; x < matrixSize; x++)
        {
            for (int y = 0; y < matrixSize; y++)
            {
                matrix[x, y] = "a" + (x + 1).ToString() + (y + 1).ToString();
            }
        }

        Console.WriteLine(Environment.NewLine + "Base square matrix");

        for (int x = 0; x < matrixSize; x++)
        {              
            for (int y = 0; y < matrixSize; y++)
            {
                Console.Write(matrix[x, y] + " ");
            }
            Console.Write(Environment.NewLine);
        }
        Console.ReadKey();

        //copy diagonals
        string[] leftDiagonal = new string[matrixSize];
        string[] rightDiagonal = new string[matrixSize];
        for (int x = 0; x < matrixSize; x++)
        {
            leftDiagonal[x] = matrix[x, x];
            rightDiagonal[x] = matrix[matrixSize - 1 - x, x];
        }

        Console.WriteLine(Environment.NewLine + "Diagonals");

        for (int x = 0; x < matrixSize; ++x)
        {
            Console.Write(leftDiagonal[x] + " " + rightDiagonal[x] + Environment.NewLine);
        }
        Console.ReadKey();

        //rotate matrix
        string[,] rotatedMatrix = new string[matrixSize, matrixSize];
        for (int x = 0; x < matrixSize; x++)
        {
            for (int y = 0; y < matrixSize; y++)
            {
                rotatedMatrix[x, y] = matrix[matrixSize - y - 1, x];
            }
        }
        Console.WriteLine(Environment.NewLine + "Rotated");

        for (int x = 0; x < matrixSize; x++)
        {
            for (int y = 0; y < matrixSize; y++)
            {
                Console.Write(rotatedMatrix[x, y] + " ");
            }
            Console.Write(Environment.NewLine);
        }
        Console.ReadKey();

        //rotate matrix again
        string[,] rotatedMatrixAgain = new string[matrixSize, matrixSize];
        for (int x = 0; x < matrixSize; x++)
        {
            for (int y = 0; y < matrixSize; y++)
            {
                rotatedMatrixAgain[x, y] = rotatedMatrix[matrixSize - y - 1, x];
            }
        }
        Console.WriteLine(Environment.NewLine + "Rotated again");

        for (int x = 0; x < matrixSize; x++)
        {
            for (int y = 0; y < matrixSize; y++)
            {
                Console.Write(rotatedMatrixAgain[x, y] + " ");
            }
            Console.Write(Environment.NewLine);
        }
        Console.ReadKey();

        //replace diagonals
        for (int x = 0; x < matrixSize; x++)
        {
            rotatedMatrixAgain[x, x] = leftDiagonal[x];
            rotatedMatrixAgain[matrixSize - 1 - x, x] = rightDiagonal[x];
        }

        Console.WriteLine(Environment.NewLine + "Completed" + Environment.NewLine);

        for (int x = 0; x < matrixSize; x++)
        {
            for (int y = 0; y < matrixSize; y++)
            {
                Console.Write(rotatedMatrixAgain[x, y] + " ");
            }
            Console.Write(Environment.NewLine);
        }
        Console.ReadKey();
    }
}

答案 1 :(得分:2)

我不知道C#,所以我只能提出伪代码的建议:

输入: N个N矩阵in

输出:按照OP out

中的说明旋转输入矩阵
for i = 1 to N
    for j = 1 to N
        if N - j != i and i != j // Do not change values on either diagonal
            out[j][N-i] = in[i][j]
        else
            out[i][j] = in[i][j]

免责声明:此算法未经测试。我建议你使用调试器检查它是否正常工作。

答案 2 :(得分:0)

这似乎是一个非常不正统的UI演示文稿,但是在能够实现您的功能方面你并没有太远。矩形阵列不是线性阵列,而是使您的工作更容易。实际旋转可以通过for循环重复单个旋转来实现(这将在case 1代码中实现),但我决定将它们组合成四种可能的情况。这实际上允许您输入旋转次数的负数。这提醒我,你真的应该做更多的错误检查。至少要防止int.Parse在它使用的地方抛出异常(使用try catch块或切换到int.TryParse)并确保它返回一个有意义的数字(大于0,可能为int.MaxValue中的matrixSize设置button1_Click以外的合理最大值。

namespace RotatingMatrices
{
    public class Form2 : Form
    {
        // note these class fields
        private TextBox[,] matrixNodes;
        private int matrixSize;

        public Form2(int matrSize)
        {
            InitializeComponent();

            // note these inits
            matrixSize = matrSize;
            matrixNodes = new TextBox[matrixSize, matrixSize];

            Random r = new Random();

            // note the new loop limits
            for (int i = 0; i < matrixSize; i++)
            {
                for (int j = 0; j < matrixSize; j++)
                {
                    var tb = new TextBox();                    
                    int num = r.Next(1, 1000);

                    // note the change in indexing
                    matrixNodes[i,j] = tb;
                    tb.Name = string.Format("Node_{0}_{1}", i, j);
                    Debug.Write(string.Format("Node_{0}_{1}", i, j));
                    tb.Text = num.ToString();
                    tb.Location = new Point(j * 50, i * 50);
                    tb.Width = 30;
                    tb.Visible = true;
                    this.splitContainer1.Panel2.Controls.Add(tb);
                }
            }
        }

        private void buttonRotate_Click(object sender, EventArgs e)
        {
            string[,] matrix = new string[matrixSize, matrixSize];
            int rotations = (4 + int.Parse(textBoxRotations.Text)) % 4; // note the addition of and mod by 4

            switch(rotations)
            {
                case 1: // rotate clockwise
                    for (int i = 0; i < matrixSize; i++)
                    {
                        for (int j = 0; j < matrixSize; j++)
                        {
                            matrix[j, matrixSize - i - 1] = matrixNodes[i, j].Text;
                        }
                    }
                    break;
                case 2:  // rotate 180 degrees
                    for (int i = 0; i < matrixSize; i++)
                    {
                        for (int j = 0; j < matrixSize; j++)
                        {
                            matrix[i, j] = matrixNodes[matrixSize - i - 1, matrixSize - j - 1].Text;
                        }
                    }
                    break;
                case 3: // rotate counter-clockwise
                    for (int i = 0; i < matrixSize; i++)
                    {
                        for (int j = 0; j < matrixSize; j++)
                        {
                            matrix[i, j] = matrixNodes[j, matrixSize - i - 1].Text;
                        }
                    }
                    break;
                default: // do nothing
                   return;
            }

            // restore diagonals
            for(int i = 0; i < matrixSize; i++)
            {
                matrix[i, i] = matrixNodes[i, i].Text;
                matrix[i, matrixSize - i - 1] = matrixNodes[i, matrixSize - i - 1].Text;
            }

            // write strings back to text boxes
            for (int i = 0; i < matrixSize; i++)
            {
                for (int j = 0; j < matrixSize; j++)
                {
                   matrixNodes[i, j].Text = matrix[i, j];
                }
            }
        }
    }
}

答案 3 :(得分:0)

我决定使用listView而不是文本框解决问题,这使我的逻辑变得更容易。使用这种方法,我能够将矩阵视为连续的框。我从外面开始向中间移动,每次都改变我的盒子的大小。

另外,我使用的不是两种形式。在顶部,我有一个文本框,用户输入他们想要数组的大小,以及标有&#34; Fill&#34; (按钮2)。在底部我有一个文本框,用户输入旋转度。当他们点击&#34;旋转时,&#34;它启动了一个向链表添加值,组合和移动列表,然后写回矩阵的过程。我确信我让它变得比以前更复杂,但这是一次很棒的学习练习。

在查看上面的杰里代码后,我想我会研究矩形阵列。 :)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Recycle
{
  public partial class Form1 : Form
  {
    public int size;
    public LinkedList<string> topRight = new LinkedList<string>();
    public LinkedList<string> bottomLeft = new LinkedList<string>();
    public LinkedList<string> myMatrix = new LinkedList<string>();
    public LinkedList<string> shiftMatrix = new LinkedList<string>();

    public Form1()
    {
        InitializeComponent();
    }

    private void button2_Click(object sender, EventArgs e)
    {
        listView1.Clear();

        size = int.Parse(textBox2.Text);
        int c = 0;
        int q = 0;
        int w = 0;
        string[] content = new string[size];
        Random rnd = new Random();

        for (c = 0; c < size; c++)
        {
            listView1.Columns.Add("", 25);
        }

        for (q = 0; q < size; q++) 
        {
            for (w = 0; w < size; w++)
            {
                content[w] = rnd.Next(9,100).ToString();
            }

            ListViewItem lvi = new ListViewItem(content);
            listView1.Items.Add(lvi);
        }

    }

    public bool iseven(int size)
    {
        if (size % 2 == 0)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public void button1_Click(object sender, EventArgs e)
    {
        if (listView1.Items.Count < 3)
        {
            MessageBox.Show("Matrix cannot be rotated.");
            return;
        }

        bool even = false;
        int shift = int.Parse(textBox1.Text); //amount to shift by
        int box = listView1.Items.Count - 1; //size of box
        int half = Convert.ToInt32(listView1.Items.Count / 2);
        int corner = 0; //inside corner of box

        if (shift > listView1.Items.Count)
        {
            shift = shift % ((listView1.Items.Count - 2) * 4);
        }

        do
        {
            eachPass(shift, box, corner);
            ++corner;
            --box;
        } while (box >= half + 1);

    }

    public void eachPass(int shift, int box, int corner)
    {
        int x;
        int i;

        //Read each non-diagonal value into one of two lists
        for (x = corner + 1; x < box; x++)
        {
            topRight.AddLast(listView1.Items[corner].SubItems[x].Text);
        }

        x = box;

        for (i = corner + 1; i < box; i++)
        {
            topRight.AddLast(listView1.Items[i].SubItems[x].Text);
        }

        for (x = box - 1; x  > corner; x--)
        {
            bottomLeft.AddLast(listView1.Items[box].SubItems[x].Text);
        }

        x = corner;

        for (i = box - 1; i > corner; i--)
        {
            bottomLeft.AddLast(listView1.Items[i].SubItems[x].Text);
        }

        string myTest = "";

        //join the two lists, so they can be shifted
        foreach (string tR in topRight)
        {
            myMatrix.AddLast(tR);
        }

        foreach (string bL in bottomLeft)
        {
            myMatrix.AddLast(bL);
        }

        int sh;

        //shift the list using another list
        for (sh = shift; sh < myMatrix.Count; sh++)
        {
            shiftMatrix.AddLast(myMatrix.ElementAt(sh));
        }

        for (sh = 0; sh < shift; sh++)
        {
            shiftMatrix.AddLast(myMatrix.ElementAt(sh));
        }

        //we need the sizes of the current lists
        int trCnt = topRight.Count;
        int blCnt = bottomLeft.Count;

        //clear them for reuse
        topRight.Clear();
        bottomLeft.Clear();

        int s;

        //put the shifted values back
        for (s = 0; s < trCnt; s++)
        {
            topRight.AddLast(shiftMatrix.ElementAt(s));
        }

        for (s = blCnt; s < shiftMatrix.Count; s++)
        {
            bottomLeft.AddLast(shiftMatrix.ElementAt(s));
        }

        int tRn = 0;
        int bLn = 0;

        //write each non-diagonal value from one of two lists
        for (x = corner + 1; x < box; x++)
        {
            listView1.Items[corner].SubItems[x].Text = topRight.ElementAt(tRn);
            ++tRn;
        }

        x = box;

        for (i = corner + 1; i < box; i++)
        {
            listView1.Items[i].SubItems[x].Text = topRight.ElementAt(tRn);
            ++tRn;
        }

        for (x = box - 1; x > corner; x--)
        {
            listView1.Items[box].SubItems[x].Text = bottomLeft.ElementAt(bLn);
            ++bLn;
        }

        x = corner;

        for (i = box - 1; i > corner; i--)
        {
            listView1.Items[i].SubItems[x].Text = bottomLeft.ElementAt(bLn);
            ++bLn;
        }

        myMatrix.Clear();
        shiftMatrix.Clear();
        topRight.Clear();
        bottomLeft.Clear();
    }
  }
}