【原創】生成n*n蛇形矩陣的演算法

銀河使者發表於2009-07-27
本文為原創,如需轉載,請註明作者和出處,謝謝!

在描述演算法之前,先看看下面的5*5的表格:

 1  3  4  10  11
 2  5  9  12
 19
 6  8  13  18  20
 7  14  17  21  24
 15  16  22  23  25

    上面的表格很容易看出規律。就是從左上角第一個格開始(起始為1),然後延右上角到左下角的斜線。先從下到上,再從上到下。開始按數字遞增排列。也就是說每一個斜線上分別有如下幾組數字:

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

    由於是先從上到下(1可以看做是從上到下),再從下到上,很象一條蛇,因此,該數字表格也可稱為蛇形矩陣。現在要與一個方法(或函式),方法的引數是一個int型別,表示n,方法返回一個二維陣列,表示要獲得的往返接力數字表格。
    實際上,這個演算法並不複雜,只需要從分別獲得1至n^2中每個數字對應的二維陣列的座標就可以了。先拿這個5行5列的表格來說,求出上面每組陣列對應的座標(起始位置為0)。

第0組
第1組
第2組
第3組
第4組
第5組
第6組
第7組
第8組
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
(0,0)
(1,0)   (0,1)
(0,2)   (1,1)   (2,0)
(3,0)   (2,1)   (1,2)   (0,3)
(0,4)   (1,3)   (2,2)   (3,1)   (4,0)
(4,1)   (3,2)   (2,3)   (1,4)
(2,4)   (3,3)   (4,2)
(4,3)   (3,4)
(4,4)
                                
    從上面的從標可以看出一個規律。  左上角的半個表格(以對角線分界)的橫座標和縱座標從0開始,每一組增1,直到增至表格的邊界(n - 1),而且是交替的,也就是說,偶數行是列增,行減小,行+列=組的索引。而右下角的4組數字雖然行、列也是交替增長的,但遞減的行或列總是從(n - 1)開始(對於本例,是從4開始),而遞增的行或列總是從index - n + 1開始,其中index表示組的索引。這就可以得出一個演算法。實現程式碼如下:
<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gtpublic static int[][] getGrid(int n)
{
    
int[][] array = new int[n][n];
    
int row = 0, col = 0, m = 1;
    
//  用於控制奇偶組,false表示偶組,true表示奇組
    boolean isRow = false;
    
//  i表示當前組的索引,從0開始
    for (int i = 0; i < (2 * n - 1); i++)
    {
        row 
= i;
        
while (row >= ((i < n) ? 0 : i - n + 1))
        {
            
//  如果處理的是右下角表格中的數字,行或列最大不能超過n-1
            if (row > (n - 1))
                row 
= n - 1;
            col 
= i - row;
            
if (isRow)
                array[row][col] 
= m;
            
else  //  將row變成列,將col變成行
                array[col][row] = m;
            m
++;
            row
--;
        }
        
//  切換奇偶組
        isRow = !isRow;
    }
    
return array;
}

   另一種演算法

   上面實現的演算法需要迴圈N*N次才可以生成蛇形矩陣。但仔細分析一下,還可以稍微變換一下這個演算法,使迴圈次數減小至N*N/2。我們上學時曾學過用高斯的方法計算1+2+3+...+100,   1 + 100 = 101,2 + 99 = 101,...,50+51 = 101,因此,結果是101 * 50 = 5050。很方便。我們這個演算法也可採用類似的方法。仔細觀察上面5*5的數字表格發現,算出左上角的矩陣中每一個數字後,都可以直接獲得右下角度某個位置的數字。例如在(0,0)位置的1,可以向到(4,4)位置的25,(1,2)位置的9可以得到(3,2)位置的17。我們發現,每一對數之和都為26。而且它們座標的關係是(row,col),(n - row - 1, n - col - 1)。因此,只要得到左上角的半個矩陣,就可以得出右下角的另外半個矩陣。如果n為奇數,對角線中間的一個數(在5*5的矩陣中是13)與之對應的數是其自身。好,我們看看改進的演算法的實現:

<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gtpublic static int[][] getGrid1(int n)
{
    
int[][] array = new int[n][n];
    
int row = 0, col = 0, m = 1;
    
int number1 =  (n * n / 2 + n * n % 2);
    
int number2 = n * n + 1;        
    
boolean isRow = false;
    
//  number1表示要計算的蛇形矩陣中最大的數字,對於5*5矩陣來說該數是13
    for (int i = 0; m < number1; i++)
    {
        row 
= i;
        
while (row >= 0)
        {
            col 
= i - row;
            
if (isRow)
            {
                array[row][col] 
= m;
                
//  填充與m對應的另外一個數
                array[n - row - 1][n - col - 1= number2 - m;
            }
            
else
            {
                array[col][row] 
= m;
                
//  填充與m對應的另外一個數
                array[n - col - 1][n - row - 1= number2 - m;

            }
            m
++;
            if(m >= number1) break;
            row--;
        }
        isRow 
= !isRow;
    }
    
return array;
}
   
   上面的演算法雖然將迴圈次數減少了一半,但每次迴圈的計算量增加了,因此,演算法總體效率並沒有提高。至於使用哪個演算法,可根據實際情況決定。
   如果想輸出n=10的數字表格,可以使用int[][] grid = getGrid(10)或int[][] grid1 = getGrid1(10),會得到同樣的結果。輸出grid和grid1,看看是不是下面的結果:

1 3 4 10 11 21 22 36 37 55
2 5 9 12 20 23 35 38 54 56
6 8 13 19 24 34 39 53 57 72
7 14 18 25 33 40 52 58 71 73
15 17 26 32 41 51 59 70 74 85
16 27 31 42 50 60 69 75 84 86
28 30 43 49 61 68 76 83 87 94
29 44 48 62 67 77 82 88 93 95
45 47 63 66 78 81 89 92 96 99
46 64 65 79 80 90 91 97 98 100

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12921506/viewspace-610503/,如需轉載,請註明出處,否則將追究法律責任。

相關文章