首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >从中心以螺旋形式填充矩阵

从中心以螺旋形式填充矩阵
EN

Stack Overflow用户
提问于 2021-12-27 20:01:49
回答 2查看 756关注 0票数 1

我最近为我正在做的一个项目做了一个算法。

简单地说,我的项目的一部分需要填写一个矩阵,如何完成它的要求如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- Fill the matrix in form of spiral, from the center.
- The size of the matrix must be dynamic, so the spiral can be large or small.
- Every two times a cell of the matrix is filled, //DO STUFF must be executed.

最后,我做的代码工作了,这是我最大的努力,我无法对它进行更多的优化,这让我感到有点困扰,因为我不得不使用这么多的ifs,我想知道是否有人可以查看我的代码,看看是否有可能进一步优化它或者进行一些建设性的评论(它很好,但如果它更快一些,因为这个算法将在我的项目中执行几次)。也让其他人可以使用它!

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>

typedef unsigned short u16_t;
const u16_t size = 7; //<-- CHANGE HERE!!! just odd numbers and bigger than 3
const u16_t maxTimes = 2;
u16_t array_cont[size][size] = { 0 };

u16_t counter = 3, curr = 0;
u16_t endColumn = (size - 1) / 2, endRow = endColumn;
u16_t startColumn = endColumn + 1, startRow = endColumn + 1;
u16_t posLoop = 2, buffer = startColumn, i = 0;

void fillArray() {
    if (curr < maxTimes) {
        if (posLoop == 0) { //Top
            for (i = buffer; i <= startColumn && curr < maxTimes; i++, curr++)
                array_cont[endRow][i] = counter++;
            if (curr == maxTimes) {
                if (i <= startColumn) {
                    buffer = i;
                } else {
                    buffer = endRow;
                    startColumn++;
                    posLoop++;
                }
            } else {
                buffer = endRow;
                startColumn++;
                posLoop++;
                fillArray();
            }
        } else if (posLoop == 1) { //Right
            for (i = buffer; i <= startRow && curr < maxTimes; i++, curr++)
                array_cont[i][startColumn] = counter++;
            if (curr == maxTimes) {
                if (i <= startRow) {
                    buffer = i;
                } else {
                    buffer = startColumn;
                    startRow++;
                    posLoop++;
                }
            } else {
                buffer = startColumn;
                startRow++;
                posLoop++;
                fillArray();
            }
        } else if (posLoop == 2) { //Bottom
            for (i = buffer; i >= endColumn && curr < maxTimes; i--, curr++)
                array_cont[startRow][i] = counter++;
            if (curr == maxTimes) {
                if (i >= endColumn) {
                    buffer = i;
                } else {
                    buffer = startRow;
                    endColumn--;
                    posLoop++;
                }
            } else {
                buffer = startRow;
                endColumn--;
                posLoop++;
                fillArray();
            }
        } else if (posLoop == 3) { //Left
            for (i = buffer; i >= endRow && curr < maxTimes; i--, curr++)
                array_cont[i][endColumn] = counter++;
            if (curr == maxTimes) {
                if (i >= endRow) {
                    buffer = i;
                } else {
                    buffer = endColumn;
                    endRow--;
                    posLoop = 0;
                }
            } else {
                buffer = endColumn;
                endRow--;
                posLoop = 0;
                fillArray();
            }
        }
    }
}

int main(void) {
    array_cont[endColumn][endColumn] = 1;
    array_cont[endColumn][endColumn + 1] = 2;
    //DO STUFF

    u16_t max = ((size * size) - 1) / maxTimes;
    for (u16_t j = 0; j < max; j++) {
        fillArray();
        curr = 0;
        //DO STUFF
    }

    //Demostration
    for (u16_t x = 0; x < size; x++) {
        for (u16_t y = 0; y < size; y++)
            printf("%-4d ", array_cont[x][y]);
        printf("\n");
    }

    return 0;
}

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-12-27 21:37:51

注意,沿对角线的数字(1,9,25,49)是奇数的平方。这是一个重要的线索,因为它表明矩阵中心的1应该被看作螺旋的末端

从每个螺旋的末尾开始,x,y坐标应该向上调整,然后向右1调整。然后,通过向下、左、上、右移动相同的量,就可以构造下一层螺旋。

例如,从1的位置开始,向上移动,向右移动(9的位置),然后用以下过程形成一个循环:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 move down, and place the 2  
 move down, and place the 3  
 move left, and place the 4  
 move left, and place the 5  
 etc.

因此,代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int size = 7;
int matrix[size][size];
int dy[] = { 1,  0, -1, 0 };
int dx[] = { 0, -1,  0, 1 };
int directionCount = 4;

int ringCount = (size - 1) / 2;
int y = ringCount;
int x = ringCount;
int repeatCount = 0;
int value = 1;

matrix[y][x] = value++;
for (int ring = 0; ring < ringCount; ring++)
{
    y--;
    x++;
    repeatCount += 2;
    for (int direction = 0; direction < directionCount; direction++)
        for (int repeat = 0; repeat < repeatCount; repeat++)
        {
            y += dy[direction];
            x += dx[direction];
            matrix[y][x] = value++;
        }
}
票数 3
EN

Stack Overflow用户

发布于 2021-12-28 05:02:40

我已经看到了很多螺旋形的方法。所有这些基本上都是画出来的,沿着一条路走。

但是,你也可以给出一个螺旋的解析计算公式。

因此,没有递归或迭代的解决办法,遵循一条路径或类似的。如果我们有运行数,我们可以直接计算矩阵中的指数。

我将从在一个笛卡尔坐标系中的数学正方向(逆时针方向)的螺旋开始。我们将集中讨论X和Y坐标。

我制作了一个简短的Excel,并由此导出了一些公式。下面是一张简短的图片:

根据要求,我们知道矩阵是二次的。这会让事情变得更简单。更棘手的是,获得矩阵数据的对称性。但有一些简单的公式,从价格,这并不是一个真正的问题。

然后我们可以用一些简单的语句来计算x和y坐标。请参阅下面的长变量名称示例程序,以更好地理解。代码是用一步一步的方法来说明实现的。当然,它可以变得更紧凑。不管怎么说。让我们来看看。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <cmath>
#include <iomanip>

int main() {
    // Show some example values
    for (long step{}; step < 81; ++step) {

        // Calculate result
        const long roundedSquareRoot = std::lround(std::sqrt(step));
        const long roundedSquare = roundedSquareRoot * roundedSquareRoot;
        const long distance = std::abs(roundedSquare - step) - roundedSquareRoot;
        const long rsrIsOdd = (roundedSquareRoot % 2);

        const long x = (distance + roundedSquare - step - rsrIsOdd) / (rsrIsOdd ? -2 : 2);
        const long y = (-distance + roundedSquare - step - rsrIsOdd) / (rsrIsOdd ? -2 : 2);
        // Show ouput
        std::cout << "Step:" << std::setw(4) << step << std::setw(3) << x << ' ' << std::setw(3) << y << '\n';
    }
}

所以,你看,我们真的有一个分析的解决方案。给定任意数,我们可以用公式计算x和y坐标。凉爽的。

获取矩阵中的索引只是添加了一些偏移量。

有了这些知识,我们现在就可以很容易地计算出完整的矩阵。而且,由于根本不需要运行时活动,所以我们可以让编译器来完成这项工作。我们将简单地对每件事使用constexpr函数。

然后编译器将在编译时创建此矩阵。在运行时,什么都不会发生。

请看一个非常紧凑的解决方案:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <iomanip>
#include <array>

constexpr size_t MatrixSize = 15u;

using MyType = long;
static_assert(MatrixSize > 0 && MatrixSize%2, "Matrix size must be odd and > 0");
constexpr MyType MatrixHalf = MatrixSize / 2;

using Matrix = std::array<std::array<MyType, MatrixSize>, MatrixSize >;

// Some constexpr simple mathematical functions ------------------------------------------------------------------------------
// No need for <cmath>
constexpr MyType myAbs(MyType v) { return v < 0 ? -v : v; }
constexpr double mySqrtRecursive(double x, double c, double p) {return c == p? c: mySqrtRecursive(x, 0.5 * (c + x / c), c); }
constexpr MyType mySqrt(MyType x) {return (MyType)(mySqrtRecursive((double)x,(double)x,0.0)+0.5); }

// Main constexpr function will fill the matrix with a spiral pattern during compile time -------------------------------------
constexpr Matrix fillMatrix() {
    Matrix matrix{};
    for (int i{}; i < (MatrixSize * MatrixSize); ++i) {
        const MyType rsr{ mySqrt(i) }, rs{ rsr * rsr }, d{ myAbs(rs - i) - rsr }, o{ rsr % 2 };
        const size_t col{ (size_t)(MatrixHalf +((d + rs - i - o) / (o ? -2 : 2)))};
        const size_t row{ (size_t)(MatrixHalf -((-d + rs - i - o) / (o ? -2 : 2)))};
        matrix[row][col] = i;
    }
    return matrix;
}
// This is a compile time constant!
constexpr Matrix matrix = fillMatrix();

// All the above has been done during compile time! -----------------------------------------


int main() {

    // Nothing to do. All has beend done at compile time already!
    // The matrix is already filled with a spiral pattern

    // Just output
    for (const auto& row : matrix) {
        for (const auto& col : row) std::cout << std::setw(5) << col << ' '; std::cout << '\n';
    }
}

不同的坐标系或其他螺旋方向可以很容易地适应。

编码愉快。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70502661

复制
相关文章
EFI 引导问题:EFI 引导配置错误,导致无法启动
是山河呀
2025/02/04
6800
Linux启动引导参数grub
内核引导参数大体上可以分为两类:一类与设备无关、另一类与设备有关。与设备有关的引导参数多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导参数。比如,如果你想知道可以向 AHA1542 SCSI 驱动程序传递哪些引导参数,那么就查看 drivers/scsi/aha1542.c 文件,一般在前面 100 行注释里就可以找到所接受的引导参数说明。大多数参数是通过"__setup(... , ...)"函数设置的,少部分是通过"early_param(... , ...)"函数设置的,逗号前的部分就是引导参数的名称,后面的部分就是处理这些参数的函数名。
mingjie
2022/05/12
9.6K0
如何在Linux上编辑内核引导参数
更改或编辑内核启动参数非常重要,当您想要修复在引导过程中导致错误,测试新功能,激活其他驱动程序或禁用系统上的功能的问题。 这些参数作为文本存储在引导加载程序的配置文件中,内核在“init”过程中解析。 要确定系统上次启动时使用的参数,应在终端上输入以下内容:
子润先生
2021/06/14
3.3K0
旁观者.个性引导页个性引导页
这款个人主页简约而不失优雅,背景图片为随机api,共有38张随机图片,每次刷新都会看到不一样的美图。
小化先森
2023/03/05
1.1K0
GRUB 引导加载程序问题:GRUB 配置错误或损坏
是山河呀
2025/02/04
1610
CentOS开机时出现GRUB引导错误怎么办
CentOS在开机的时候,突然出现了GRUB引导错误,导致系统进入不了,遇到这种情况很多人就束手无策了,其实这类的问题不难解决,请按照以下步骤进行操作即可。
拓荒者
2019/09/05
3.7K0
CentOS开机时出现GRUB引导错误怎么办
Spring Boot引导过程
引导Spring Boot应用程序的一种方法是使用Spring Initializer。为此需要访问Spring Initializer 网页 www.start.spring.io[1] 并选择 Build,Spring Boot版本和平台。此外还需要提供组,工件和所需的依赖项来运行应用程序。
黑洞代码
2021/07/14
9070
Spring Boot引导过程
使用OC引导ubuntu
按任意键进入输入模式,然后我们需要找到ubuntu的grub引导所在的分区. 直接输入 FS0: 回车,就能进入这个分区,然后再输入ls回车,查看里面的文件,看这个是不是存grub引导的地方.
GOOPHER
2022/03/31
3.3K0
使用OC引导ubuntu
window引导配置bcdedit
以前的系统上有boot.ini配置,现在没有了只能bcdedit修改系统配置,或者msconfig修改(可修改项有限)
sofu456
2020/07/26
9520
uefi shell 修复引导_磁盘主引导损坏怎么办
1、 红旗DC5.0 32bit莫名其妙死机,(服务器是ibm x3650 2008年左右的机器),硬重启后无法启动,极其缓慢,到最后报错:
全栈程序员站长
2022/09/24
2.4K0
SpringBoot之引导类[Application]
  我们不管是做Spring的程序也好,还是做springMvc的程序也好,最终都会运行出一个spring容器出来,而我们所有的对象全部都已Bean的形式交给Spring容器管理。
叫我阿杰好了
2022/11/07
6590
SpringBoot之引导类[Application]
ubuntu如何修复引导
****前言:**** 今晚快要下班的时候,cp文件夹到U盘里面,由于文件过大并且里面的文件都是代码小文件,想想接近700M大有多少小文件,然而电脑就发烧式的发烫,真不敢想象呢,前所未有的发热,于是我就想关机来让电脑来歇歇,万万没想到的就是,电脑关机出现异常了,这时候我已经意识到电脑maybe出了问题。然后我就立马开机,果然不出我所料,电脑系统进不了了。来公司前我安装了linux+win双系统,电脑开机默认进入的是win系统,看到提示,感觉是win除了问题,真是奇怪:上次使用win系统都没有问题的,让你w
AlicFeng
2018/06/08
9.5K0
【Linux】引导流程
在计算机科学领域,服务(Service)是指在计算机网络或分布式系统中执行的可独立访问的软件组件,它们提供特定的功能或任务。服务可以是网络服务,如Web服务器、数据库服务器,也可以是系统服务,如日志服务、时间同步服务。服务的目标是通过网络或系统调用为其他程序或用户提供某种功能,以促进系统的模块化和可扩展性。
人不走空
2024/02/21
1510
android覆盖式引导
我们在开发产品的时候,每次发版可能会有一些新的功能需要引导用户使用,以前大部分都是使用截图,然后让设计师把引导的问题修饰好放到图上,现在这张图片就是引导图片,我们只需要用这张图片放到界面上,这样基本上就可以满足引导的作用.
飞雪无情
2018/08/28
1K0
android覆盖式引导
如何引导访客注册
原文出处: gkogan 译文出处:TerryFan 许多初创公司的命运几乎完全取决于一个转换点:访问者何时转换成用户。 很多时候,这个关键的任务落在了再普通不过的“注册”按钮的肩上,而这个可怜的按钮在产品开发中却往往得不到任何考虑和关注。 如果你花一点时间来考虑注册按钮的措辞,也许就能大幅增加注册用户转化率。(当然在访客成为用户之后的事情至关重要,但一旦你有了用户的邮件地址,事情都会变得容易得多。) 各初创公司的注册按钮 为什么“注册”按钮起不了作用 它们被忽略了。当访客重复看到许多网站都共有的元
wangxl
2018/03/08
1.2K0
如何引导访客注册
OpenCore引导黑苹果
OpenCore(OC)是一种新的引导方式,随着越来越多的kexts开始放弃Clover, 我相信提早使用OC会对你未来使用黑苹果会有很大的帮助。这是一个自然的现象,就像变色龙被Clover淘汰,而现在OC代替Clover也是大势所趋。你应该需要看一些相关的文章,来帮助你理解我的正文内容,同时也需要下载我推荐的软件:
用户6808043
2022/02/25
2K0
anndroid 模糊引导界面
先上两张图,后面补上代码 我们以前的写法是在需要显示模糊引导的地方,写一个布局,然后第一次使用的时候显示出来。但是这样做代码结构不清晰,所以我们有必要将这些View独立出来,写成一个自定义的View
xiangzhihong
2018/02/01
7340
anndroid 模糊引导界面
揭秘vista引导机制
所谓的引导机制就是在操作系统内核运行前的一小段程序。其主要作用是初始化电脑硬件设备,建立内存空间的映射图。从而将系统的软件和硬件设备环境调配到一个适合的状态,以使电脑最终调用系统内核而准备好适合的环境。
全栈程序员站长
2022/11/18
5830
Netty中的引导类Bootstrap
Bootstrap是用来组织Netty的各个结构(pipeline,handler,eventloop),并使他们运行起来的类结构。分成两块,一个是客户端引导类Bootstrap,只用1个channel来处理所有的网络交互,另一个是服务端的ServerBootstrap,它提供一个父channel来接受客户端的请求,然后父channel创建多个子channel来用于的通信
爬蜥
2019/07/09
9560
利用threshold实现的遮罩引导
点击“开始引导”,则进入引导操作。除指定的按钮可以操作外,其它区域均不可点击。这种应用当新功能或是新产品上线后,用来引导用户来使用产品/功能,是十分有用的。facebook也有类似的引导,方法也很简单:用4个绝对定位的DIV(指定一个背景 + 一定透明度)遮住其它部分,这样可以被操作的区域就“留空”出来。
meteoric
2018/11/16
6160

相似问题

拦截对DOM函数的调用

13

jQuery:拦截原始DOM就绪事件?

26

拦截DOM和JS引擎调用

10

检测/拦截向DOM中插入<img>

43

如何在DOM中拦截导航事件?

13
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文