如何打印方阵的右半球

Posted

技术标签:

【中文标题】如何打印方阵的右半球【英文标题】:How to print the right hemisphere of a square matrix 【发布时间】:2015-06-16 19:49:13 【问题描述】:

我正在尝试打印矩阵的右半球。如果我们在矩阵中绘制主对角线和次对角线,我们会看到我们得到了 4 个相等的部分,右边的部分被称为(在我的算法教科书中)方阵的右半球。

例如,在下面的5 x 5 矩阵中,右半球由以下元素组成:-1, -3, -2, 0

我尝试解决此问题的方法是开始并组合第二对角线的一半,然后在左对角线元素的右侧打印每个元素。到达次对角线的中间后,我在主对角线的下部重复此过程。

类似的东西(至少,这是我在脑海中的看法):

这是一些打印5 x 5 矩阵右半球的工作代码。它可以工作,但是很难看,并且对于具有偶数行和列的矩阵(例如 4 x 4 矩阵)不能正常工作。

#include <iostream>

#define N 5
#define M 5

void printHemisphere(int matrix[N][M], int n, int m)

    int i = 1;
    for(int j = n - 1; j > n / 2; i++, j--)
    
        for (int k = j + 1; k < m; ++k)
        
            std::cout << matrix[i][k] << " ";
        
        std::cout << std::endl;
    

    for(int j = n / 2; j < n; i++, j++)
    
        for (int k = j + 1; k < m; ++k)
        
            std::cout << matrix[i][k] << " ";
        
        std::cout << std::endl;
    



int main(int argc, char const *argv[])

     int matrix5[N][M] = 
     
        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
     ;


    printHemisphere(matrix5, N, M);

    return 0;

你会如何解决这个问题?

【问题讨论】:

这应该支持非方阵吗?如果有,怎么做? 不,它应该只适用于方阵。 【参考方案1】:

我认为这应该适用于方阵:

void printHemisphere(int matrix[N][M], int n, int m)

    int mid = n / 2;
    for(int i = 1; i < mid; i++)
    
        for (int j = n - i; j < m; ++j)
        
            std::cout << matrix[i][j] << " ";
        
        std::cout << std::endl;
    

    for(int i = mid; i < n - 1; i++)
    
        for (int j = i + 1; j < m; ++j)
        
            std::cout << matrix[i][j] << " ";
        
        std::cout << std::endl;
    

外部循环跳过第一行和最后一行,因为它们不能有输出。

【讨论】:

此解决方案与 marom 的问题相同。如果你尝试一下,你会看到输出只有12,而它应该是8 12。解决方案:对于j,您应该使用n-1 而不是n。因此,j 从(n-1)-i+1 = n-i 开始。此外,顶部的行在 [0, (N/2) -1] 范围内,底部的行在 [N/2, N-1] 范围内。所以,第一个循环可能是for(int i = 1; i &lt; mid; i++),第二个循环可能是for(int i = mid; i &lt; n - 1; i++)。你可以在ideone.com/PzJOAN查看它 @FabioTurati - 感谢您对此进行测试(我应该在发布之前完成 - 让我感到羞耻)。我已经更新了我的代码来解决问题(包括消除伪造的k 下标)。 各位,非常感谢你们帮我解决这个问题。我不得不承认,这个解决方案对我来说并不是那么明显,我不得不稍微努力去理解它(真正意义上的)。您是否应用了一些模式来解决这类问题,或者只是靠直觉(通过实践发展)? @cristid9 - 我以前处理过这种问题,所以我应用了经验。 (另外,正如在 cmets 中明显的,一些反复试验。)我不会把它美化为“模式”,因为它没有形式化或结构化,我不会称它为“直觉”,因为一个确实要考虑这些事情。这种情况下的技巧(如果你可以这么称呼它)是首先决定逐行处理矩阵,然后识别输出哪些行元素的条件在对角线交叉的位置发生变化。您自己的图表实际上显示了大部分已经完成的工作。【参考方案2】:

这是一种只使用双 for 循环的方法:

void printHemisphere(int matrix[N][M], int n, int m)

    for(int i = 1; i < n - 1 ; i++)
    
        for (j = max(i, n - i) ; j < m ; j++)
        
            std::cout << matrix[i][k] << " ";
        
        std::cout << std::endl;
    
    std::cout << std::endl;

【讨论】:

总的来说,我喜欢这个答案,但有几点可以改进:1)您正在打印matrix[i][k],您的意思是matrix[i][j] 2)i 从 1 开始并停止在n-2,但在矩阵中索引从 0 到 n-1。这意味着您正在优化代码,知道可以跳过第一行和最后一行。很好,但我会把它写成评论 3) jmax(i, n-i) 开始的原因可以在评论中解释。我知道i 是主对角线在i 和另一条的n-i 处的坐标,max 基本上是最右边的,但你可以解释一下。 代码为4 x 4 矩阵输出错误结果:ideone.com/N9ElqS。它应该只打印812 内循环应该从max(i, n - i) + 1开始,而不是max(i, n - i)。 OP 不想要对角线元素。 @TedHopp 你是对的,这种方法还包括对角线元素。但实际上它仍然是错误的。正确的公式是(int j = std::max(i, n - 1 - i) + 1;。我之前的评论也错了:在i 行,次对角线的元素在n-1-i,而不是n-i。因此,虽然这种方法背后的总体思路是正确的,但代码需要一些调整。【参考方案3】:

在伪代码中...:

for row in 1 -> height - 2 // Indices between 0 -> height - 1
   distance = min(row, height - 1 - row)
   for cell in (width - distance) -> width - 1
      print matrix[row][cell]

【讨论】:

你能解释一下distance = min(row, height - 1 - row)的含义吗?我不确定我是否得到它。看起来distance 等于应该打印的元素数,对吗? @cristid9 - 它“测量”与最近的“边缘行”(第一行,顶行 - 或最后一个,底行)的距离。对于远离边缘的每一行,您需要再打印 1 个水平单元格...【参考方案4】:

这是我的看法。我来晚了,因为您已经接受了解决方案;不过,我想向您展示一些东西。例如,如果您将这些矩阵视为一维数组,您可以只用一个函数测试所有大小的矩阵,因为大小不必“内置”到函数定义中的数据类型中。并且我已经评论了很多,希望尽可能的说清楚。

#include <iostream>
#include <algorithm>


// I store matrices as a monodimensional array, so that it is easier to deal
// with matrices of different sizes in the same program, because you can do
// everything with one function. Moreover, I use only one argument here, to make
// it clear that we are dealing with square matrices.
void printHemisphere(int* matrix, int last_row)

    int last_column = last_row; // It's a square matrix, so they are the same.
                                // Still, distinguishing between last_column
                                // and last_row can make the algorithm clearer,
                                // so I have kept both

    // In general I prefer to use "row" and "column" as variable names, instead
    // of "i" and "j"

    // Our rows go from 0 to last_row-1, but since the first and last one can
    // certainly not be used, we can skip them: we start at row = 1, and we stop
    // at last_row - 2 (that is, the last one for which row < last_row - 1)
    for(int row = 1; row < last_row - 1 ; row++)
    
        // We want to start from the cell to the right of the rightmost diagonal.
        // The main diagonal has column = row;
        // The secondary diagonal has column = last_row - 1 - row
        // The rightmost one is the maximum of these 2.
        // Then, we want to take the cell to the right of the diagonal, so we
        // have to add 1 more.
        // All in all we have:
        for (int column = std::max(row, last_row - 1 - row) + 1;
             column < last_column;
             column++)
        
            // since this is a 1-D array we have to access it this way
            std::cout << matrix[row*last_row+column] << " ";
        
        std::cout << std::endl;
    
    std::cout << std::endl;


int main(int argc, char const *argv[])

    // Since I am working with monodimensional arrays, I don't store them as
    // int matrix3[3][3], but rather as int matrix3[9], which I have expressed as
    // int matrix3[3*3] for clarity.
    //For each one I have indicated the expected output.

    // Expected output:
    // 6
    int matrix3[3*3] = 
    
        1, 2, 3,
        4, 5, 6,
        7, 8, 9
    ;

    // Expected output:
    // 8
    // 12
    int matrix4[4*4] = 
    
        1, 2, 3, 4,
        5, 6, 7, 8,
        9, 10, 11, 12,
        13, 14, 15, 16
    ;

    // Expected output:
    //    10
    // 14 15
    //    20
    int matrix5[5*5] = 
         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
    ;

    // Expected output:
    //    12
    // 17 18
    // 23 24
    //    30 
    int matrix6[6*6] = 
         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, 26, 27, 28, 29, 30,
        31, 32, 33, 34, 35, 36
    ;

    // Expected output:
    //       14
    //    20 21
    // 26 27 28
    //    34 35
    //       42
    int matrix7[7*7] = 
         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, 26, 27, 28,
        29, 30, 31, 32, 33, 34, 35,
        36, 37, 38, 39, 40, 41, 42,
        43, 44, 45, 46, 47, 48, 49
    ;


    printHemisphere(matrix3, 3);
    printHemisphere(matrix4, 4);
    printHemisphere(matrix5, 5);
    printHemisphere(matrix6, 6);
    printHemisphere(matrix7, 7);

    return 0;

我已经在 ideone 上验证了它,它可以工作。我唯一想补充的是:为确保代码正常工作,请确保使用奇数大小和偶数大小的矩阵对其进行测试。

【讨论】:

以上是关于如何打印方阵的右半球的主要内容,如果未能解决你的问题,请参考以下文章

如何在Python中获得半球的坐标

用java打印趣味方阵

openGL如何在改变窗口大小时,使自己的图形不被拉伸

模板小程序循环方阵构造(仿《剑指offer》循环矩阵打印)

如何有效地转置非方阵?

CUDA如何获取网格、块、线程大小和并行化非方阵计算