螺旋迭代

3
我需要一种算法,可以从中心扫描像素。问题在于不同的长度和大小,有时无法到达位置(见下面蓝色部分的图像)。
为了更好地说明问题,我将展示一个输出示例:
如果您比较这两张图片,您会注意到它按螺旋形进行扫描,并且输出与常规for循环匹配,显然问题是不能正确打印蓝色部分。
以下是代码:
#include<iostream>
#include<string>
#include<math.h>

int arr[] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
int arrSize = sizeof(arr) / sizeof(arr[0]);
int width = 5;
int height = 3;

void normal2DArray() {
    int index = 0;
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            std::cout << std::to_string(x) << "," << std::to_string(y) << " = " << std::to_string(arr[index]) << "\n";
            index++;
        }
    }
}

int convertToInex(int x, int y) {
    int left = x * y; // elements to the left
    int right = (width - x) * y; // elements to the right
    return left + right + x;
}

void spiralArray() {
    // calculate middle point, which is also the start point
    int x = round((float)width / 2) - 1;
    int y = round((float)height / 2) - 1;

    int direction = 0; // 0=right, 1=up, 2=left, 3=down
    int turnCounter = 1;
    int numSteps = 1;
    int step = 1;
    int index;

    while (true) {

        index = convertToInex(x, y); // defines the index position in arr
        std::cout << std::to_string(x) << "," << std::to_string(y) << " = " << std::to_string(arr[index]) << "\n";

        switch (direction) {
        case 0: x++; break;
        case 1: y--; break;
        case 2: x--; break;
        case 3: y++; break;
        }
        index = convertToInex(x, y);

        if (step % numSteps == 0) {
            direction = (direction + 1) % 4;
            turnCounter++;
            if (turnCounter % 2 == 0) numSteps++;
        }
        step++;
        if (step > arrSize) break;
    }
}

void main() {
    std::cout << "Output of Normal 2D Array:\n";
    normal2DArray();

    std::cout << "\n"; // better spacing

    std::cout << "Output of Spiral Array:\n";
    spiralArray();
}

我尽量将代码保持简单和小。它应该可以随时导入和使用。 是的,我已经在网上搜索了我的答案,但我没有找到任何覆盖这里的问题,也没有类似于我拥有的1D arr和组合2D数组WIDTH/HEIGHT以及肯定不是c++。

❗同时,我需要适用于所有宽度和高度以及arr大小并且也适用于任何一侧的解决方案 ❗

希望您能提供有用的答案,我会感激好的和快速的算法实现和优化

编辑: 感谢这个帖子中的回复。目前我决定采用@ldog的解决方案,即使我对此并不完全满意。

以下是编辑后的代码部分:

    int failcounter = 0;
    while (true) {
    index = convertToInex(x, y); // defines the index position in arr
    if (index < 0 || index > arrSize) failcounter++;
    else std::cout << std::to_string(x) << "," << std::to_string(y) << " = " << std::to_string(arr[index]) << "\n";

// unchanged code inbetween

if (step > arrSize + failcounter) break;

2
你想要那个数组的什么顺序?如果你从8开始,就没有好的答案。 - Beta
1
Start from 7 or 9 - Onyambu
@Beta 我只想要一个从中心开始获取每个像素的算法。它不一定要是这个螺旋形的,但我认为这可能是最有效的一个。 - The Developer Fish
1
那么,你想要什么顺序? 试试看。用铅笔从8开始尝试。没有好的答案。 - Beta
@Beta它们不需要连接。它只需检测到它在数组大小之外(在这种情况下为-1),并且不扫描它们并找到下一个继续点。因此,它将继续如下:5、1、6、11。 - The Developer Fish
显示剩余2条评论
2个回答

3

根据你的评论:

@Beta他们不需要连接。它只需检测到它在数组大小之外(在这种情况下为-1),并且不扫描它们,找到下一个连续点。因此,它会像这样继续:5、1、6、11

看起来你不关心螺旋是否“越界”。在这种情况下,简单的答案是,将没有螺旋的形状嵌入到总是保证有一个螺旋的形状中。

因此,如果你的输入矩形是 N x M,那么将其嵌入大小为 max(M,N) x max(M,N) 的矩形中,在后者中解决问题,打印时忽略原始问题中不存在的数字。因此,你打印的序列总是唯一的,取决于嵌入的方式。最合理的嵌入方式是尽可能地将较小的矩形居中在较大的矩形中,但这由你决定。

在这种情况下,你不需要算法,如果你愿意记录和弄清楚涉及的公式,你可以通过计算来得出一切。


是的,这是一个简单的解决方案,我也考虑过。但这意味着我需要比数组中实际像素更大的循环。这可能会导致数百个不必要的检查,而这些可以通过智能算法来避免。由于我关心速度和性能,我想选择更好的选项,即使这需要更多的工作。 - The Developer Fish
1
正如我在上一段中提到的那样,这不需要算法,而是需要一个公式,这意味着你应该能够在每个要计算值的项上以 O(1) 的时间实现它(总时间为 O(n))。 - ldog

0

您可以在四个位置遇到死路(即退出网格)。在每种情况下,跳到下一个活动像素,如果仍有活动单元,则会到达该单元。

通过跟踪最远离起始像素的四个角落来轻松完成此操作。使用指南针坐标和N表示向上,这些是访问的NE,NW,SW和SE极端情况。

如果从NE像素向N走时遇到死路,请跳到NW像素左侧的像素并将移动方向设置为向下。如果那也是死路,请跳到SW像素下面一个像素并将移动方向设置为向右。等等... 当所有四个角落和死路都被访问后,就完成了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接