排版——螺旋打印

4 篇文章 0 订阅

题目描述:
给定一个自然数n,打印1-n之间所有的数,要求:按螺旋形状顺时针打印。

  • 由内而外的打印

    这里写图片描述

  • 分析

    最简单且直观的方法就是k * k的二维数组存储数字,先将数字按照要求填入数组,然后输出整个数组即可

  • 分配数组

    对于n个数而言,令k = Ceil(sqrt(n)), 则分配k*k的二维数组即可。比如n = 5时,分配3*3的数组即可。

  • 如何填数

    起始点
    以左上角为起始点

  • 方向

    用一个整数flag来标识方向
    flag = 1 - 向右
    flag = 2 - 向下
    flag = 3 - 向左
    flag = 4 - 向上

  • 边界判断

    当到达边界的时候应该变换方向,即向右转,如何判断边界?我的方法是,将所有数组元素初始化为-1,则有如下两种情况
    1.下标超出二维数组边界,则需转向(注意,转向之前下标需要退回一格)
    2.下标未越界,但下一个位置的值不是-1,那么说明它被填充过,也需转向。

  • 填充

    重复以下过程直到所有数据填充完毕。

    1. 从左至右填充数组,如遇右边界或者下一位置已经被填充过,则改变方向,转入步骤2
    2. 从上至下填充数组,如遇下边界或者下一位置已经被填充过,则改变方向,转入步骤3
    3. 从右至左填充数组,如遇左边界或者下一位置已经被填充过,则改变方向,转入步骤4
    4. 从下至上填充数组,如遇上边界或者下一位置已经被填充过,则改变方向,转入步骤1

代码实现:

#include <iostream>
#include <iomanip>
using namespace std;

//从外向内螺旋打印num
void SpiralPrint1(int num)
{
    //计算二维数组的维数k
    int k = ceil(sqrt(num));        //ceil()向上取整

    //动态分配一个二维数组
    int **a = new int*[k];
    for (int i = 0; i < k; i++)
    {
        a[i] = new int[k];
    }
    //初始化动态分配的二维数组
    for (int i = 0; i < k; i++)
        for (int j = 0; j < k; j++)
            a[i][j] = -1;

    int i = 0, j = 0;
    a[i][j] = 1;

//  用一个整数flag来标识方向
//  flag -> 1 向右(j++) | flag -> 2 向下(i++) | flag -> 3 向左(j--) | flag -> 向上(i--)  

    int flag = 1;
    int m = 1;
    while (a[i][j] < num)
    {
        m++;
        if (flag == 1)
        {
            j++;
            if (j >= k || a[i][j] != -1)
            {
                j--;
                flag = 2;
            }
        }
        if (flag == 2)
        {
            i++;
            if (i >= k || a[i][j] != -1)
            {
                i--;
                flag = 3;
            }
        }
        if (flag == 3)
        {
            j--;
            if (j <= -1 || a[i][j] != -1)
            {
                j++;
                flag = 4;
            }
        }
        if (flag == 4)
        {
            i--;
            if (a[i][j] != -1 || i <= -1)
            {
                i++;
                flag = 1;
                j++;
                if (j >= k || a[i][j] != -1)
                {
                    j--;
                }
            }
        }
        a[i][j] = m;
    }

    for (int i = 0; i < k; i++)
    {
        for (int j = 0; j < k; j++)
            cout << right << setw(5) << a[i][j] << " ";
        cout << endl;
    }
}

int main()
{
    SpiralPrint1(25);
    system("pause");
    return 0;
}

  • 由内而外的打印

    这里写图片描述

  • 起始位置

    由于是从内向外填充,所以起始位置不再是(0, 0),需要重新计算,而且还与二维数组的阶数k的奇偶性相关
    1 当k为奇数时,起始位置为(k / 2, k / 2),如下:
    2 当k为偶数时,起始位置为(k / 2 - 1, k / 2 - 1),如下:

  • 边界判断

    与从外向内填充不同的是,边界判断中不会再出现下标越界的情况,只需判断当前位置是否填充过即可

  • 方向转换

    从内向外填充时,能转向时优先转向,不能转向时才继续向前填充,而从外向内填充则恰恰相反,无法继续向前填充时才转向

代码实现:

#include <iostream>
#include <iomanip>
using namespace std;

void SpiralPrint2(int num)
{
    //计算二维数组的维数k
    int k = ceil(sqrt(num));
    //动态分配一个二维数组
    int **a = new int*[k];
    for (int i = 0; i < k; i++)
    {
        a[i] = new int[k];
    }
    //初始化动态分配的二维数组
    for (int i = 0; i < k; i++)
        for (int j = 0; j < k; j++)
            a[i][j] = -1;

    int i, j;
    if (k % 2 == 0)
        i = j = k / 2 - 1;
    else
        i = j = k / 2;
    a[i][j] = 1;
    int m = 1;


    int flag = 1;
    while (m < num)
    {
        m++;
        if (flag == 1)
        {
            j++;
            if (a[i][j] == -1)
            {
                a[i][j] = m;
                flag = 2;
            }
            else
            {
                j--;
                i--;
                if (a[i][j] == -1)
                {
                    a[i][j] = m;
                    flag = 1;
                }
            }
        }
        else if (flag == 2)
        {
            i++;
            if (a[i][j] == -1)
            {
                a[i][j] = m;
                flag = 3;
            }
            else
            {
                i--;
                j++;
                if (a[i][j] == -1)
                {
                    a[i][j] = m;
                    flag = 2;
                }
            }
        }
        else if (flag == 3)
        {
            j--;
            if (a[i][j] == -1)
            {
                a[i][j] = m;
                flag = 4;
            }
            else 
            {
                j++;
                i++;
                if (a[i][j] == -1)
                {
                    a[i][j] = m;
                    flag = 3;
                }
            }
        }
        else if (flag == 4)
        {
            i--;
            if (a[i][j] == -1)
            {
                a[i][j] = m;
                flag = 1;
            }
            else
            {
                i++;
                j--;
                if (a[i][j] == -1)
                {
                    a[i][j] = m;
                    flag = 4;
                }
            }

        }
    }
    for (int i = 0; i < k; i++)
    {
        for (int j = 0; j < k; j++)
        {
            cout << right << setw(5) << a[i][j] << " ";
        }

        cout << endl;
    }
}
int main()
{
    SpiralPrint1(25);
    system("pause");
    return 0;
}

题目描述:

把一个个大小差一圈的框叠起来,使得从上往下看时,边框花色交错,这个工作现在要让计算机来完成

输入:

输入时一个个的三元组,分别是,外框尺寸n(n为满足0

输出:

输出叠在一起的框案,中心花色和外框花色字符从内层起交错相叠,多狂想叠时,最外框的角总是被打磨掉。叠框和叠框之间一行间隙

样例输入:

5 @ w

样例输出:

    @   @   @
@   w   w   w   @
@   w   @   w   @
@   w   w   w   @
    @   @   @

样例输入:

11 B A

样例输出:

    A   A   A   A   A   A   A   A   A
A   B   B   B   B   B   B   B   B   B   A
A   B   A   A   A   A   A   A   A   B   A
A   B   A   B   B   B   B   B   A   B   A
A   B   A   B   A   A   A   B   A   B   A
A   B   A   B   A   B   A   B   A   B   A
A   B   A   B   A   A   A   B   A   B   A
A   B   A   B   B   B   B   B   A   B   A
A   B   A   A   A   A   A   A   A   B   A
A   B   B   B   B   B   B   B   B   B   A
    A   A   A   A   A   A   A   A   A

思想关键:按照由最内圈至最外圈的顺序来完成图形的排序。在完成每圈打印时,注意两个要点:首先需要确定最上角的坐标。我们将以这个坐标作为参照点来完成该圈的其他位置上的字符位置的确定

代码实现

#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
    int n;
    char a, b;
    while (cin >> n >> a >> b)
    {
        //动态创建一个二维数组用于存储数据
        char **output = new char*[n];
        for (int i = 0; i < n; i++)
        {
            output[i] = new char[n];
        }

        int k = n / 2;
        output[k][k] = a;
        for (int i = 1; i <= n / 2; i++)
        {
            char c;
            if (i % 2 == 0)
                c = a;
            else
                c = b;
            for (int j = 0; j < 2 * i + 1; j++)
            {
                output[k - i][k - i + j] = c;  //上面一行的字符确定
                output[k - i + j][k - i] = c;  //左边一列的字符确定
                output[k + i - j][k + i] = c;  //右边一列的字符确定
                output[k + i][k + i - j] = c;  //下边一行的字符确定
            }
        }
        if (n != 1)
        {
            output[0][0] = ' ';
            output[n - 1][0] = ' ';
            output[0][n - 1] = ' ';
            output[n - 1][n - 1] = ' ';
        }
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
                cout << setw(3) << output[i][j] << " ";
            cout << endl;
        }

    }

    system("pause");
    return 0;
}

本文参考:
http://www.cnblogs.com/graphics/archive/2010/06/05/1739658.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值