最近對矩陣的研究比較多一點,一來,因為加的幾個QQ群裡一直有人在討論這個問題,而且討論者甚眾,看來大家對這個問題還是挺有興趣的;二來,去年自己去有道的一次面試中就遇到了這樣一個問題,很遺憾的是當時並沒有答出來,於是與有道失之交臂,感到挺遺憾的。但這還不是全部,因為一年前我曾做過這樣一道題,而且還考慮了很久,是一個公司的面試題,到真正需要用的時候反而寫不出來了,足見自己學習的不連貫,孔夫子幾千年前就說的道溫故而知新,自己到現在都不會用。面試回去花了很長時間終於找到了自己曾做過的這個題,令我不能淡定的是,那個程式在一個叫做“有道筆試”的檔案夾下,真的有瞬間石化的感覺,真是應了一句當今的網路熱門語“出來混遲早是要還的”,於是痛定思痛,要把這個矩陣問題好好搞明白。
首先是,順時針矩陣。
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
通過我們的觀察,可以知道該矩陣首先沿著最大圈逆時針逐漸增大,當圍成一個圈後然後再進入第二個圈同樣做逆時針遞增。規律找到了,如何輸出這樣一個矩陣呢?當然就要我們找到語言的規律。首先我先用一種比較簡單,比較好理解的方法來做。首先我們定義四個變數,top,bottom,left,right,分別來對應矩陣的上、下、左、右四個方向。在矩陣的最上面一行,我們發現橫座標始終不變,改變的只是縱座標,而矩陣的最右列,改變的也只是橫座標,而縱座標不發生改變,剩下的依次類推,這樣我們就能得到下面的代碼。
void clockwise()
{
int top = -1, bottom = N, left = -1, right = N;
int i, j;
int n = 1;
i = top + 1, j = left + 1;
while(top <= bottom && left <= right)
{
top++; bottom--; left++; right--;
while(j <= right)
{
A[i][j] = n++;
j++;
}
j--; i++;
while(i <= bottom)
{
A[i][j] = n++;
i++;
}
i--; j--;
while(j >= left)
{
A[i][j] = n++;
j--;
}
j++; i--;
while(i > top)
{
A[i][j] = n++;
i--;
}
i++; j++;
}
}
這種方法思路比較簡單,容易理解,因為不涉及到比較複雜的歸納推理。下面的方法則比較晦澀,這個方法是建立在對這個圖有深入理解的基礎上的,剛開始可能會覺得不好理解,但是多看幾遍應該就能明白其中的奧妙。
void clockwise(int A[][N])
{
int i, j, k = 1;
for(i = 0; i < N/2; i++)
{
for(j = i; j < N - i - 1; j++)
A[i][j] = k++;
for(j = i; j < N - i - 1; j++)
A[j][N - i - 1] = k++;
for(j = N - i - 1; j > i; j--)
A[N-i-1][j] = k++;
for(j = N - i - 1; j > i; j--)
A[j][i] = k++;
}
if(N%2 == 1)
A[N/2][N/2] = k;
}
}
在順時針方向的遞增明白之後,逆時針方向的矩陣程式便能很好地寫出了,這裡不再寫出,留給讀者自己編程練習。
下面我著重介紹zigzag矩陣的產生,zigzag矩陣,就是我們俗稱的“之字形”矩陣。熟悉影像處理的同學們應該對zigzag數組很熟悉了,在JPEG圖形演算法中首先對映像進行分塊處理,一般分成互不重疊且大小一致的塊,量化的結果保留了低頻部分的係數,去掉了高頻部分的係數。量化後的係數按zigzag掃描重新組織,然後進行哈夫曼編碼。
1 2 6 7 15
3 5 8 14 16
4 9 13 17 22
10 12 18 21 23
11 19 20 24 25
仔細分析上面的矩陣,首先從左上方出發,向右遞增一位,然後沿著右上到左下的對角線遞增,但遇到邊界遍向下走,然後再沿著從左下到右上的方向繼續遞增。映像很好理解。
void zigzag(int A[][N])
{
int i, j, min = 1, max = N * N;
for(i = 0; i < N / 2; i++)
{
if(i%2 == 0)
{
for(j = i; j >= 0; j--)
{
A[j][i] = min++;
A[N-1-j][N-1-i+j]=max--;
}
}
if(i%2 != 0)
{
for(j = 0; i < =i; i++)
{
A[j][i-j] = min++;
A[N-1-j][N-1-i+j]=max--;
}
}
}
}