《演算法之美》的一處錯誤
今天開始拿到《演算法之美》一本書,翻看起來,前陣子在看Charles Petzold大神的《編碼-隱匿在計算機軟硬體背後的語言》,百看不厭,真的是一本非常有趣的書,覺得左飛哥翻譯的不錯,瞭解到他還寫了《演算法之美》一書,特地買來看看。看到Z字形編碼,對其產生了興趣,於是開始敲程式碼。
-
Z字形編碼是幹什麼的?
首先了解一下 JPEG ,它的英文名是 Joint Photographic Experts Group 是一種常見的影象檔案格式,也是目前靜態影象中壓縮比最高的一種影象檔案格式,它綜合運用了多種壓縮技術而達到一種極高的壓縮比例。
關於 JPEG 更多詳情 請見 維基百科
在 JPEF 編碼過程中,有一個非常重要的步驟,即Z字形編排過程。
借用一下本書的一副圖,簡單說明一下Z字形編碼。
下面看一個例子,相信大家就明白了。
上面是 8 × 8 的一個矩陣,將其經過 Z 字形編碼得到的結果如果上圖。在 《演算法之美》這本書中,給的矩陣大小為 8 ,矩陣大小定義為 SIZE ,在本小節末尾,有這麼一句話 --- 此外,這個演算法不僅對 8 × 8 的矩陣有效,對於 SIZE 取其他值的情況仍然有效,讀者不妨試試看。
於是,我就試了將 SIZE 改為其它值,但是 SIZE為偶數時是沒有錯誤的,但是 SIZE 一旦為奇數時就發生了錯誤。
錯誤情況如圖所示:
也就是說沒有完成 Z 字形編碼,所以我就想把 SIZE 為奇數的情況,也能夠進行正確的 Z 字形編碼。
經過一番在草稿紙上的演算,只需將書中的兩行程式碼做下小小的改動再加上兩個判斷即可。
程式碼如下:
- SIZE 為奇數的情況:
if(SIZE%2 == 1) { if(i == 0 && j%2 == 0 && j !=SIZE-1 || i == SIZE -1 && j%2 == 1) { j++; continue; } if(j == 0 && i%2 == 1 || j == SIZE - 1 && i%2 == 0) { i++; continue; } }
- SIZE 為偶數的情況:
else if(SIZE%2 == 0)
{
if((i == 0 || i == SIZE-1) && j%2 == 0)
{
j++;
continue;
}
if((j == 0 || j == SIZE-1) && i%2 == 1)
{
i++;
continue;
}
}
完整的判斷程式碼為:
for(x = 0;x< SIZE;x++)
{
for(y = 0;y< SIZE;y++)
{
//賦值
*(*(a + i) + j) = *(*(matrix + x) +y);
if(SIZE%2 == 1)
{
if(i == 0 && j%2 == 0 && j !=SIZE-1 || i == SIZE -1 && j%2 == 1)
{
j++;
continue;
}
if(j == 0 && i%2 == 1 || j == SIZE - 1 && i%2 == 0)
{
i++;
continue;
}
}
else if(SIZE%2 == 0)
{
if((i == 0 || i == SIZE-1) && j%2 == 0)
{
j++;
continue;
}
if((j == 0 || j == SIZE-1) && i%2 == 1)
{
i++;
continue;
}
}
if((i+j)%2 == 0)
{
i--;
j++;
}
else if((i+j)%2 == 1)
{
i++;
j--;
}
}
}
SIZE 為7時 :
下面來分別解釋一下 SIZE 為偶數 和 奇數的情況:(也就是程式碼怎麼來的)
上圖其實也有一處錯誤,只不過這個錯誤沒有什麼太大的影響所以就權當沒看到了。
以7 × 7 的矩陣為例:
- 當 SIZE 為偶數時:
- 當 SIZE 為奇數時:
可以發現:
- 當 matrix[i][j] 列數 j 是偶數時,並且只有當 i = 0 時,那麼遍歷路徑在矩陣中的走向就是水平向右移動一格。
- 當 matrix[i][j] 列數 j 是奇數時,並且只有當 i == SIZE -1 時,那麼遍歷路徑在矩陣中的走向就是水平向右移動一格。
- 當 matrix[i][j] 行數 i 是奇數時,並且只有當 j = 0 時,那麼遍歷路徑在矩陣中的走向就是垂直向下移動一格。
- 當 matrix[i][j] 行數 i 是偶數時,並且只有當 j == SIZE -1 時,那麼遍歷路徑在矩陣中的走向就是垂直向下移動一格。
以上就是 完整的 Z字形編碼 過程。
附完整程式碼:
#include <iostream>
#include <iomanip>
using namespace std;
#define SIZE 3
int main(int arc,char** argv)
{
int matrix[SIZE][SIZE] = {0};
int a[SIZE][SIZE] = {0};
int i,j,x,y,value = 0;
int *p;
p = &matrix[0][0];
//初始化矩陣
for(i = 0;i<SIZE * SIZE;i++)
*p++ = i;
//列印原始矩陣
cout << "原始矩陣如下:" << endl;
for(i = 0; i< SIZE ; i++)
{
for(j = 0;j<SIZE;j++)
//setw(int n) 用來控制輸出間隔
cout << setw(4) << *(*(matrix + i) + j);
cout << endl;
}
i = 0; j = 0;
//進行Z字形編排
for(x = 0;x< SIZE;x++)
{
for(y = 0;y< SIZE;y++)
{
//賦值
*(*(a + i) + j) = *(*(matrix + x) +y);
if(SIZE%2 == 1)
{
if(i == 0 && j%2 == 0 && j !=SIZE-1 || i == SIZE -1 && j%2 == 1)
{
j++;
continue;
}
if(j == 0 && i%2 == 1 || j == SIZE - 1 && i%2 == 0)
{
i++;
continue;
}
}
else if(SIZE%2 == 0)
{
if((i == 0 || i == SIZE-1) && j%2 == 0)
{
j++;
continue;
}
if((j == 0 || j == SIZE-1) && i%2 == 1)
{
i++;
continue;
}
}
if((i+j)%2 == 0)
{
i--;
j++;
}
else if((i+j)%2 == 1)
{
i++;
j--;
}
}
}
cout << endl << "經過Z字形編碼後的矩陣如下:" << endl;
for(i = 0;i< SIZE;i++)
{
for(j = 0;j<SIZE;j++)
cout << setw(4)<<*(*(a+i)+j);
cout<<endl;
}
return 0;
}