用螺旋填充二维数组

Fill two dimensional array with spiral

任务是将二维数组 [N][M] 填入螺旋状,数字从 1 开始。

当其中一个元素(N 或 M)为奇数或两者均为奇数时,我的代码无法运行。 当我使用两个不同的偶数或两个相同的偶数时,它起作用了。

我需要帮助才能做到这一点,这样它在任何情况下都能工作,任何 N 和 M。

p.s。请保留我的代码(不要制作动态数组,保留定义等)

https://pastebin.com/9HufHYBg

#include <iostream>

#define N 6
#define M 4

int nums = 1; 
int p = 1;

int arr[N][M];

using namespace std;

void printArr(){
    for (int i = 0; i < N; i++){
        for (int j = 0; j < M; j++){
            cout << arr[i][j] << "\t";
        }
        cout << endl;
    }
}

void circle (int k){    
    
    // levo pravo
    for (int i = 0+k; i < M-k; i++){
        arr[N-N+k][i] = nums;
        nums++;
    }
    // verh niz
    nums--;
    for (int i = 0+k; i < N-k; i++){
        arr[i][M-1-k] = nums;
        nums++;
    }
    // pravo levo
    nums--;
    for (int i = M-p; i >= 0+k; i--){
        arr[N-1-k][i] = nums;
        nums++;
    }
    // niz verh
    nums--;
    for (int i = N-p; i > 0+k; i--){
        arr[i][0+k] = nums;
        nums++;
    }
    p++;
}


int main(){
    
    if (M<N){   
        for (int k = 0; k < M/2; k++){      
            circle(k);  
        }   
    } else {
        for (int k = 0; k < N/2; k++){      
            circle(k);  
        }
    }
    
    printArr();
    
    return 0;
}

总而言之,我设法通过两个更改解决了问题: 首先,我们更改主调用的限制,以便我们每次都能到达中心,其次,我们避免覆盖已经填充的索引。在这里,我通过在每次赋值之前使用 if 语句进行检查来停止这种覆盖。但是,可能会有更清洁的解决方案。

测试了各种组合(奇-奇、偶-偶、奇-偶、奇-奇-不相同、奇-奇-相同等)

#include <iostream>

#define N 9
#define M 7

int nums = 1; 
int p = 1;

int arr[N][M];

using namespace std;

void printArr(){
    for (int i = 0; i < N; i++){
        for (int j = 0; j < M; j++){
            cout << arr[i][j] << "\t";
        }
        cout << endl;
    }
}

void circle (int k){    
    
    // levo pravo
    for (int i = 0+k; i < M-k; i++){
        if (arr[N-N+k][i] == 0)
            arr[N-N+k][i] = nums;
        nums++;
    }
    // verh niz
    nums--;
    for (int i = 0+k; i < N-k; i++){
        if (arr[i][M-1-k] == 0)
            arr[i][M-1-k] = nums;
        nums++;
    }
    // pravo levo
    nums--;
    for (int i = M-p; i >= 0+k; i--){
        if (arr[N-1-k][i]==0)
            arr[N-1-k][i] = nums;
        nums++;
    }
    // niz verh
    nums--;
    for (int i = N-p; i > 0+k; i--){
        if (arr[i][0+k] == 0)
            arr[i][0+k] = nums;
        nums++;
    }
    p++;
}


int main(){
    
    if (M<N){   
        for (int k = 0; k < (M+1)/2; k++){      
            circle(k);  
        }   
    } else {
        for (int k = 0; k < (N+1)/2; k++){      
            circle(k);  
        }
    }
    
    printArr();
    
    return 0;
}

对于奇数 NM 你应该在最后一次迭代后打印一行。您不能打印圆,因为要打印的表面没有 2 条或更多条线。一种方法是检查 NM 是否为奇数,然后打印一条线来填充螺旋线:https://godbolt.org/z/6oavKGPqf

我已将 vert_line 函数和 hor_line 添加到您的代码中以打印最后一行(垂直或水平)。

void hor_line(int k){
    for (int i = 0+k; i < M-k; i++){
        arr[N-N+k][i] = nums;
        nums++;
    }
}

void vert_line(int k){
    for (int i = 0+k; i < N-k; i++){
        arr[i][M-1-k] = nums;
        nums++;
    }
}

int main(){
    if (M<N){   
        int k{0};
        for (; k < M/2; k++){      
            circle(k);  
        }
        if (M % 2 != 0){
            vert_line(k);
        }
    } else {
        int k{0};
        for (; k < N/2; k++){      
            circle(k);  
        }
        if (N % 2 != 0){
            hor_line(k);
        }
    }
    
    printArr();
    
    return 0;
}