从中心顺时针扩展螺旋打印二维数组

问题描述 投票:0回答:6

我保证是一个完美的方阵。我想从矩阵的中心开始,在这种情况下它将是

matrix[2][2]
,我知道如何计算中心
(int)(dimensions / 2)
。我需要以下面的向外螺旋模式输出数组的内容。当然,该算法应该适用于任何完美的方阵。我不确定这个算法是否已经存在,我不想重新发明轮子。

int dimensions / 2;

21 22 23 24 25
20 7  8  9  10
19 6  1  2  11
18 5  4  3  12 
17 16 15 14 13

此示例的输出应为

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
c++ algorithm loops matrix 2d
6个回答
10
投票

让我们先识别模式..

偶数尺寸方阵,示例:4x4

  07 > 08 > 09 > 10
  ^               v
  06  (01)> 02   11
  ^          v    v
  05 < 04 < 03   12
                  v
 [16]< 15 < 14 < 13

Starting Point: [2, 2] ~ [SIZE/2, SIZE/2]

Ending Point: [4, 1] ~ [SIZE, 1]

Chains: Count(K-chain)=2 for K = 1..(SIZE-2)
        + 3 for Count = SIZE-1

奇数尺寸方阵,示例:5x5

  21 > 22 > 23 > 24 >[25]
  ^
  20   07 > 08 > 09 > 10
  ^    ^               v
  19   06  (01)> 02   11
  ^    ^          v    v
  18   05 < 04 < 03   12 
  ^                    v
  17 < 16 < 15 < 14 < 13

Starting Point: [2, 2] ~ [⌊SIZE/2⌋, ⌊SIZE/2⌋]

Ending Point: [1, 5] ~ [1, SIZE]

Chains: Count(K-chain)=2 for K = 1..(SIZE-2)
        + 3 for Count = SIZE-1

实时代码

void print_spiral (int ** matrix, int size)
{
    int x = 0; // current position; x
    int y = 0; // current position; y
    int d = 0; // current direction; 0=RIGHT, 1=DOWN, 2=LEFT, 3=UP
    int c = 0; // counter
    int s = 1; // chain size

    // starting point
    x = ((int)floor(size/2.0))-1;
    y = ((int)floor(size/2.0))-1;

    for (int k=1; k<=(size-1); k++)
    {
        for (int j=0; j<(k<(size-1)?2:3); j++)
        {
            for (int i=0; i<s; i++)
            {
                std::cout << matrix[x][y] << " ";
                c++;

                switch (d)
                {
                    case 0: y = y + 1; break;
                    case 1: x = x + 1; break;
                    case 2: y = y - 1; break;
                    case 3: x = x - 1; break;
                }
            }
            d = (d+1)%4;
        }
        s = s + 1;
    }
}

6
投票

因为这闻起来像家庭作业,所以没有代码或直接答案,而只是一些提示:

您可以将其视为海龟问题:

m
1
细胞的运动,
r
为沿螺旋方向(顺时针或逆时针)旋转
90
度。那么螺旋可以被编码为一系列形成此模式的海龟命令(从起点开始):

    m,r,m,r, 
    m,m,r,m,m,r,
    m,m,m,r,m,m,m,r,
    m,m,m,m,r,m,m,m,m,r,
    m,m,m,m,m,r 

正如您所看到的,您从 1x 移动开始,然后在两次重复后旋转,切换到 2x 移动,2 次移动后切换到 3x 移动,...等等。这只需几个 for 循环即可完成(或者只需进行一些适当的迭代,并在击中单元格的矩阵数量时停止......或击中端点角)

您需要处理偶数/奇数矩阵大小

对于奇数矩阵大小来说,中间点很容易。对于偶数尺寸,情况会稍微复杂一些。如果使用顺时针旋转,则使用将大小减半的向下舍入除法结果,并开始向右移动。 (如果您需要不同的螺旋,则需要将

+1
添加到
x
和/或
y
并更改起始方向),以便螺旋保持居中。

因此,如果你得到偶数大小的矩阵,那么最后一次移动是两次,如果你得到奇数大小,那么最后一次移动只有一次(就像在这个例子中一样)

旋转

将方向存储为 2D 矢量。例如

d=(+1,0)
表示正确。要旋转 2D 矢量,您只需交换坐标并取反一个轴(这意味着 CW/CCW)。例如
(x,y) -> (y,-x)

运动

也将当前位置存储为 2D 矢量。运动只是将当前方向矢量添加到其中。

享受解决这个问题的乐趣......


0
投票
    int radius = 0;
    int i = centerX;
    int j = centerY;
    Debug.Log("i=" + i + "; j=" + j);
    ++i;
    radius += 2;
    while ((i < dimm) && (i >= 0))
    {
        for (int c = j; j < c + radius; j++)
            Debug.Log("i=" + i + "; j=" + j);
        --j;
        --i;
        for (int c = i; i > c - radius + 1; i--)
            Debug.Log("i=" + i + "; j=" + j);
        if (i < 0)
            break;
        else
            Debug.Log("i=" + i + "; j=" + j);
        --j;
        for (int c = j; j > c - radius; j--)
            Debug.Log("i=" + i + "; j=" + j);
        ++i;
        ++j;
        for (int c = i; i < c + radius; i++)
            Debug.Log("i=" + i + "; j=" + j);
        radius += 2;
    }

此代码将从自定义中心(CenterX,CenterY)输出逆时针平方矩阵(dimm X dimm)索引;如果超出矩阵大小,则结束。


0
投票
bool IsIterationComplete(int iteration, int nCenter, std::vector<std::vector<bool>>& vVisited)
{
    int nHigh = nCenter+iteration;
    int nLow = nCenter-iteration;
    //cout<<endl<<"High "<<nHigh<<"Low "<<nLow<<endl;
    for(int i=nLow;i<=nHigh;i++)
    {
        if(!vVisited[nHigh][i] || !vVisited[nLow][i]) 
            return false;
    }

    for(int i=nLow;i<=nHigh;i++)
    {
        if(!vVisited[i][nHigh] || !vVisited[i][nLow])
            return false;
    }

    return true;
}
void PrintSpiral(std::vector<std::vector<int>>& vMat,std::vector<std::vector<bool>>& vVisited, int row, int col, int nCenter, int iteration)
{
    cout<<vMat[row][col];
    vVisited[row][col]=true;

    if(row==0 && col==0)
        return;

    if(IsIterationComplete(iteration,nCenter,vVisited))
        iteration++;

    //cout<<endl<<"row "<<row<<" column "<<col<<"Iteration "<<iteration<<endl;

//left
    if(col-1>=0 && !vVisited[row][col-1] && col-1>=nCenter-iteration)
    {
        cout<<"Left "<<endl;
        PrintSpiral(vMat,vVisited,row,col-1,nCenter,iteration);
    }

    //Down
    if((row+1)<vMat.size() && !vVisited[row+1][col] && row+1<=nCenter+iteration)
    {
        cout<<"Down "<<endl;
        PrintSpiral(vMat,vVisited,row+1,col,nCenter,iteration);
    }

    //right
    if((col+1)<vMat.size() && !vVisited[row][col+1] && col+1<=nCenter+iteration)
    {
        cout<<"Right "<<endl;
        PrintSpiral(vMat,vVisited,row,col+1,nCenter,iteration);
    }

    //up    
    if(row-1>=0 && !vVisited[row-1][col] && row-1>=nCenter-iteration)
    {
        cout<<"Up "<<endl;
        PrintSpiral(vMat,vVisited,row-1,col,nCenter,iteration);
    }
}


int main (int argc, const char * argv[])
{
    int nCount=1;
    std::vector<std::vector<int>> vMat;
    std::vector<std::vector<bool>> vVisited;
    for(int i=0; i<7; i++)
    {
        std::vector<int> row;
        std::vector<bool> visitedRow;
        for(int j=0; j<7; j++)
        {
            row.push_back(nCount);
            cout<<nCount<<'\t';
            nCount++;
            visitedRow.push_back(false);
        }
        cout<<'\n';
        vMat.push_back(row);
        vVisited.push_back(visitedRow);
    }
    cout<<'\n';
    PrintSpiral(vMat,vVisited,vMat.size()/2,vMat.size()/2,vMat.size()/2,0);
    return 0;
}

0
投票

这是一个简单的Python解决方案:

def spiral_matrix(n): 
    # Create an n x n matrix filled with zeros
    mat = [[0 for i in range(n)] for j in range(n)]   
    
    # Start from the middle of the matrix
    x = n // 2
    y = n // 2

    # If n is even, adjust the start position
    if n % 2 == 0:
        x -= 1
        y -= 1

    # Initialize the first value to be filled into the matrix
    val = 1

    # Initialize the directions for movement (right, down, left, up)
    dirs = [(0,1), (1,0), (0,-1), (-1,0)]
    dir = 0  # Start with the first direction (right)

    # Begin filling the matrix
    while val <= n * n:  # Continue until all cells are filled
        # If the next cell is within the matrix and has not been visited
        if 0 <= x < n and 0 <= y < n and mat[x][y] == 0:
            # Fill the cell and increment the value
            mat[x][y] = val
            val += 1
        else:  # If the next cell is outside the matrix or already visited
            # Move back to the previous cell and change the direction
            x = px
            y = py
            dir -= 2  # Go back two steps in the direction sequence

        # Save the current position
        px = x
        py = y

        # Move to the next cell in the current direction
        x += dirs[dir][0]
        y += dirs[dir][1]

        # Change the direction (right -> down -> left -> up -> right -> ...)
        dir = (dir + 1) % 4

    # Return the filled matrix
    return mat

# Test the function with n = 5
n = 4           
mat = spiral_matrix(n)

# Print the filled matrix
for row in range(n):
    for col in range(n):
        print(mat[row][col], end="\t")
    print()

0
投票

有一个基于 Khaled.K 的答案的 C# 版本

        /// <summary>
        /// 从中心向外螺旋遍历
        /// </summary>
        /// <param name="matrix"></param>
        /// <param name="action"></param>
        /// <typeparam name="T"></typeparam>
        private static void TraverseSpiralExpand<T>(T[,] matrix, Action<T> action)
        {
            var length = matrix.GetLength(0);
            if (length != matrix.GetLength(1))
            {
                throw new InvalidDataException("SpiralExpand only supported on Square Matrix.");
            }

            // starting point
            var x = (length - 1) / 2;
            var y = (length - 1) / 2;

            // 0=>x++, 1=>y++, 2=>x--, 3=>y--
            var direction = 0;

            action(matrix[x, y]);
            for (var chainSize = 1; chainSize < length; chainSize++)
            {
                for (var j = 0; j < (chainSize < length - 1 ? 2 : 3); j++)
                {
                    for (var i = 0; i < chainSize; i++)
                    {
                        switch (direction)
                        {
                            case 0:
                                x++;
                                break;
                            case 1:
                                y++;
                                break;
                            case 2:
                                x--;
                                break;
                            case 3:
                                y--;
                                break;
                        }
                        action(matrix[x, y]);
                    }
                    direction = (direction + 1) % 4;
                }
            }
        }
© www.soinside.com 2019 - 2024. All rights reserved.