旋转外部N x N个正方形数组,同时保持内部正方形数组不移动
本文关键字:数组 正方形 内部 移动 外部 旋转 | 更新日期: 2023-09-27 18:09:15
如何旋转(或移动)一个二维正方形数组,但留下任何元素,不在数组的"边界"未移动?
的例子:
1 2 3 4
12 13 14 5
11 15 16 6
10 9 8 7
我想要的:
12 1 2 3
11 13 14 4
10 15 16 5
9 8 7 6
这只是一个例子。我需要它在任何宽度为N的方阵上工作,其中2
如果数组存储为rank为2的正方形.NET数组,则代码非常简单,主要由四个循环组成-每个边一个:
var array = new [,] {
{ 1, 2, 3, 4, 5 },
{ 16, 17, 18, 19, 6 },
{ 15, 24, 25, 20, 7 },
{ 14, 23, 22, 21, 8 },
{ 13, 12, 11, 10, 9 }
};
// Rank = 2 and "square" and side length >= 2 checks removed for clarity.
var sideLength = array.GetLength(0);
// Save first element from top edge.
var element00 = array[0, 0];
// Rotate left edge.
for (var y = 1; y < sideLength; y += 1)
array[y - 1, 0] = array[y, 0];
// Rotate bottom edge.
for (var x = 1; x < sideLength; x += 1)
array[sideLength - 1, x - 1] = array[sideLength - 1, x];
// Rotate right edge.
for (var y = sideLength - 2; y >= 0; y -= 1)
array[y + 1, sideLength - 1] = array[y, sideLength - 1];
// Rotate top edge.
for (var x = sideLength - 2; x > 0; x -= 1)
array[0, x + 1] = array[0, x];
// Put saved element in place.
array[0, 1] = element00;
现在原始数组已经按照问题中的描述进行了旋转。
如果数组存储为一维数组,则更容易创建一个类来执行旋转。该类可以存储可跨方法调用使用的属性(数组和边长),以简化代码。
四个循环包含相同的逻辑,尽管它们看起来不同:
class ArrayRotator<T> {
public ArrayRotator(T[] array) {
if (array == null)
throw new ArgumentNullException("array");
var sideLength = (Int32) Math.Sqrt(array.Length);
if (sideLength*sideLength != array.Length)
throw new ArgumentException("Not a square.", "array");
Array = array;
SideLength = sideLength;
}
public T[] Array { get; private set; }
public Int32 SideLength { get; private set; }
public void RotateArray() {
if (SideLength < 3)
return;
// Save first element from top edge.
var element00 = Array[0];
// Rotate left edge.
for (var y = 1; y < SideLength; y += 1)
CopyElement(0, y, 0, y - 1);
// Rotate bottom edge.
for (var x = 1; x < SideLength; x += 1)
CopyElement(x, SideLength - 1, x - 1, SideLength - 1);
// Rotate right edge.
for (var y = SideLength - 2; y >= 0; y -= 1)
CopyElement(SideLength - 1, y, SideLength - 1, y + 1);
// Rotate top edge.
for (var x = SideLength - 2; x > 0; x -= 1)
CopyElement(x, 0, x + 1, 0);
// Put saved element in place.
Array[1] = element00;
}
void CopyElement(Int32 x1, Int32 y1, Int32 x2, Int32 y2) {
Array[GetIndex(x2, y2)] = Array[GetIndex(x1, y1)];
}
Int32 GetIndex(Int32 x, Int32 y) {
return y*SideLength + x;
}
}
下面是如何使用这个类:
var array = new [] {
1, 2, 3, 4,
12, 13, 14, 5,
11, 15, 16, 6,
10, 9, 8, 7
};
var arrayRotator = new ArrayRotator<Int32>(array);
arrayRotator.RotateArray();
现在原始数组已经按照问题中的描述进行了旋转。
我发现这个问题很有趣,我设计了一个小解决方案,只要数组符合完全平方,这应该工作,无论边长
注意:这不是最优化的解决方案(我很想尝试做一个更优雅的解决方案,但这应该足够了)。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ArraySquareRotation
{
class Program
{
static void Main(string[] args)
{
int[] arr = new int[]
{
1, 2, 3, 4, 5, 3,
12, 13, 14, 5, 6, 1,
11, 15, 16, 6, 7, 22,
10, 9, 8, 7, 8, 30,
11, 15, 16, 6, 7, 22,
1, 2, 3, 4, 5, 3
};
// detect array size
int size = arr.Length;
// calculate the side length of the array (in terms of index)
int sideLength = BruteForceSquareDimensions(size);
// find the start of the last side of the square
int lastRowStartIndex = size - sideLength;
// a placeholder for us to generate a shifted array
int[] arrRotated = new int[size];
Console.WriteLine("Detected square with side length {0}", sideLength);
Console.WriteLine();
for (int i = 1; i <= size; i++)
{
// side rotation
if ((i % sideLength) == 0 && i != size)
{
// is multiple of
// right hand side, shift down
arrRotated[i + sideLength - 1] = arr[i - 1];
// left hand side, shift up
arrRotated[i + sideLength - (sideLength * 2)] = arr[i];
} else if (i < sideLength)
{
int lastRowIndex = sideLength * (sideLength - 1);
// first row, shift right
arrRotated[i] = arr[i - 1];
// last row, shit left
arrRotated[i + lastRowIndex - 1] = arr[i + lastRowStartIndex];
} else if(i < lastRowStartIndex)
{
// the inner square (this case may need some work)
arrRotated[i - 1] = arr[i - 1];
}
}
Console.WriteLine("Printing original array");
Console.WriteLine("======================");
PrintSquareArray(arr);
Console.WriteLine();
Console.WriteLine("Printing Shifted array");
Console.WriteLine("======================");
PrintSquareArray(arrRotated);
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
/// <summary>
/// there is definately a better way.
/// </summary>
/// <param name="size"></param>
/// <returns></returns>
static int BruteForceSquareDimensions(int size)
{
int sideLength = 0;
for (int i = 1; i < size; i++)
{
if ((i * i) == size)
{
sideLength = i;
}
}
return sideLength;
}
/// <summary>
/// This method just prints the array in the desired readable format
/// </summary>
/// <param name="arr"></param>
static void PrintSquareArray(int[] arr)
{
int size = arr.Length;
int sideLength = BruteForceSquareDimensions(size);
for(int i = 1; i <= size; i++)
{
if ((i % sideLength) == 0)
{
Console.WriteLine(arr[i - 1]);
}
else
{
Console.Write(arr[i - 1] + "'t");
}
}
}
}
}
输出应该如下所示(正方形):
Detected square with side length 4
Printing original array
======================
1 2 3 4
12 13 14 5
11 15 16 6
10 9 8 7
Printing Shifted array
======================
12 1 2 3
11 13 14 4
10 15 16 5
9 8 7 6
Press any key to exit
这是一个6 * 6的
Detected square with side length 6
Printing original array
======================
1 2 3 4 5 3
12 13 14 5 6 1
11 15 16 6 7 22
10 9 8 7 8 30
11 15 16 6 7 22
1 2 3 4 5 3
Printing Shifted array
======================
12 1 2 3 4 5
11 13 14 5 6 3
10 15 16 6 7 1
11 9 8 7 8 22
1 15 16 6 7 30
2 3 4 5 3 22
Press any key to exit
这是我得到的。在您提供的4x4和以下5x5方形阵列上进行了测试。此外,我假设数据存储在锯齿数组中,这样一个数组包含n个数组,每个数组的长度为n。
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
static int[][] Transform(int[][] old)
{
var maxIdx = old.Length-1;
var canvas = new List<int[]>();
//top border
var top = new List<int>();
top.Add(old[1][0]);
for (var i = 0; i < maxIdx; i++)
{
top.Add(old[0][i]);
}
//bottom border
var bottom = new List<int>();
for (var i = 1; i < maxIdx+1; i++)
{
bottom.Add(old[maxIdx][i]);
}
bottom.Add(old[maxIdx - 1][maxIdx]);
//middle
var middle = new List<int[]>();
for (var i = 1; i < maxIdx; i++) //for each inner array
{
var inside = new List<int>();
inside.Add(old[i + 1][0]);
for (var j = 1; j < maxIdx; j++)
{
inside.Add(old[i][j]);
}
inside.Add(old[i - 1][maxIdx]);
middle.Add(inside.ToArray());
}
//Rebuild
canvas.Add(top.ToArray());
foreach (var arr in middle)
{
canvas.Add(arr);
}
canvas.Add(bottom.ToArray());
return canvas.ToArray();
}