-2

目标

想象一下,我们有像这样的矩阵

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 矩阵)。当我按下OK它时,它会生成像这样的第二种形式的文本框矩阵

表格 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

4 回答 4

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();
    }
}
于 2013-04-05T07:50:46.877 回答
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]

免责声明:此算法未经测试。我建议您使用调试器来检查它是否按您的意愿工作。

于 2013-04-07T21:45:43.977 回答
0

这似乎是一个非常非正统的 UI 演示,但就能够实现您的功能而言,您并不算太远。代替线性阵列,矩形阵列将使您的工作更轻松。实际的旋转可以通过重复单个旋转的 for 循环来实现(这将在case 1代码中实现),但我决定将它们组合成四种可能的情况。这实际上允许您为旋转次数输入一个负数。这提醒了我,你真的应该做更多的错误检查。至少防止在int.Parse使用它的两个地方都抛出异常(使用 try catch 块或切换到int.TryParse),并确保它返回一个有意义的数字(大于0,可能设置一个合理的最大值,而不是int.MaxValuematrixSizebutton1_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];
                }
            }
        }
    }
}
于 2013-04-14T17:40:05.537 回答
0

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

另外,我没有使用两种形式,而是使用一种。在顶部,我有一个文本框,用户可以在其中输入他们希望数组的大小,以及一个标有“填充”的按钮(按钮 2)。在底部我有一个文本框,用户可以在其中输入旋转度数。当他们单击“旋转”时,它会启动向链表添加值、组合和移动列表,然后写回矩阵的过程。我确信我让它比它必须的更复杂,但这是一个很好的学习练习。

在查看了上面 jerry 的代码之后,我想我要研究一下矩形数组。:)

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();
    }
  }
}
于 2013-04-17T01:22:55.330 回答