'稀疏數組的應用與實踐,別再說學不好數據結構了'

數據結構 五子棋 黑子 Java 算法 Java聖鬥士 2019-08-11
"

文 | Java聖鬥士

"

文 | Java聖鬥士

稀疏數組的應用與實踐,別再說學不好數據結構了

Hello 各位熱愛學習的小夥伴們大家好,今天來給大家聊聊五子棋遊戲的後臺實現

相信大家都玩過五子棋遊戲,規則就是率先連成 5 顆棋子的一方獲勝。小編小的時候也非常喜歡玩五子棋,覺得自己天下無敵了,對手再怎麼努力都不會逃脫自己的圍追堵截,堵著堵著就贏了,哈哈。

"

文 | Java聖鬥士

稀疏數組的應用與實踐,別再說學不好數據結構了

Hello 各位熱愛學習的小夥伴們大家好,今天來給大家聊聊五子棋遊戲的後臺實現

相信大家都玩過五子棋遊戲,規則就是率先連成 5 顆棋子的一方獲勝。小編小的時候也非常喜歡玩五子棋,覺得自己天下無敵了,對手再怎麼努力都不會逃脫自己的圍追堵截,堵著堵著就贏了,哈哈。

稀疏數組的應用與實踐,別再說學不好數據結構了

可是你有想過五子棋的“保存棋局”和“續上局”是如何實現的嗎?

五子棋的數據結構描述

我們知道,五子棋有一個正方形棋盤,分別設有白子和黑子:

"

文 | Java聖鬥士

稀疏數組的應用與實踐,別再說學不好數據結構了

Hello 各位熱愛學習的小夥伴們大家好,今天來給大家聊聊五子棋遊戲的後臺實現

相信大家都玩過五子棋遊戲,規則就是率先連成 5 顆棋子的一方獲勝。小編小的時候也非常喜歡玩五子棋,覺得自己天下無敵了,對手再怎麼努力都不會逃脫自己的圍追堵截,堵著堵著就贏了,哈哈。

稀疏數組的應用與實踐,別再說學不好數據結構了

可是你有想過五子棋的“保存棋局”和“續上局”是如何實現的嗎?

五子棋的數據結構描述

我們知道,五子棋有一個正方形棋盤,分別設有白子和黑子:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼這個五子棋盤就可以使用二維數組來描述,假設是一個 11 × 11 的二維數組:

int[][] chessArr = new int[11][11];

然後我們輸出一下:

for (int[] row : chessArr) {
\tfor (int data : row) {
\t\tSystem.out.printf("%d ", data);
\t}
\tSystem.out.println();
}
"

文 | Java聖鬥士

稀疏數組的應用與實踐,別再說學不好數據結構了

Hello 各位熱愛學習的小夥伴們大家好,今天來給大家聊聊五子棋遊戲的後臺實現

相信大家都玩過五子棋遊戲,規則就是率先連成 5 顆棋子的一方獲勝。小編小的時候也非常喜歡玩五子棋,覺得自己天下無敵了,對手再怎麼努力都不會逃脫自己的圍追堵截,堵著堵著就贏了,哈哈。

稀疏數組的應用與實踐,別再說學不好數據結構了

可是你有想過五子棋的“保存棋局”和“續上局”是如何實現的嗎?

五子棋的數據結構描述

我們知道,五子棋有一個正方形棋盤,分別設有白子和黑子:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼這個五子棋盤就可以使用二維數組來描述,假設是一個 11 × 11 的二維數組:

int[][] chessArr = new int[11][11];

然後我們輸出一下:

for (int[] row : chessArr) {
\tfor (int data : row) {
\t\tSystem.out.printf("%d ", data);
\t}
\tSystem.out.println();
}
稀疏數組的應用與實踐,別再說學不好數據結構了

然後我們先來填幾顆棋子,模擬一個五子棋局,在代碼中,由於初始的二維數組中默認都是 0 ,那我們就可以考慮用 1 代表 黑子,用 2 代表白子:

chessArr[1][2] = 1; // 黑子先行
chessArr[2][3] = 2; // 白子緊隨其後
chessArr[1][4] = 1; // 黑子欲形成橫向三連之勢
chessArr[1][3] = 2; // 白子“挺進大別山”斷了黑子的陰謀

再輸出,就可以看到黑子白子形成的“圍追堵截”之勢了,有沒有點懷念小時候的感覺?

"

文 | Java聖鬥士

稀疏數組的應用與實踐,別再說學不好數據結構了

Hello 各位熱愛學習的小夥伴們大家好,今天來給大家聊聊五子棋遊戲的後臺實現

相信大家都玩過五子棋遊戲,規則就是率先連成 5 顆棋子的一方獲勝。小編小的時候也非常喜歡玩五子棋,覺得自己天下無敵了,對手再怎麼努力都不會逃脫自己的圍追堵截,堵著堵著就贏了,哈哈。

稀疏數組的應用與實踐,別再說學不好數據結構了

可是你有想過五子棋的“保存棋局”和“續上局”是如何實現的嗎?

五子棋的數據結構描述

我們知道,五子棋有一個正方形棋盤,分別設有白子和黑子:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼這個五子棋盤就可以使用二維數組來描述,假設是一個 11 × 11 的二維數組:

int[][] chessArr = new int[11][11];

然後我們輸出一下:

for (int[] row : chessArr) {
\tfor (int data : row) {
\t\tSystem.out.printf("%d ", data);
\t}
\tSystem.out.println();
}
稀疏數組的應用與實踐,別再說學不好數據結構了

然後我們先來填幾顆棋子,模擬一個五子棋局,在代碼中,由於初始的二維數組中默認都是 0 ,那我們就可以考慮用 1 代表 黑子,用 2 代表白子:

chessArr[1][2] = 1; // 黑子先行
chessArr[2][3] = 2; // 白子緊隨其後
chessArr[1][4] = 1; // 黑子欲形成橫向三連之勢
chessArr[1][3] = 2; // 白子“挺進大別山”斷了黑子的陰謀

再輸出,就可以看到黑子白子形成的“圍追堵截”之勢了,有沒有點懷念小時候的感覺?

稀疏數組的應用與實踐,別再說學不好數據結構了

棋盤的壓縮保存

接下來就是今天的正題!如果你已經看到這裡,一定要堅持!

五子棋的保存實際上並不是保存整個棋盤,而是通過一個叫做“稀疏數組”的結構來完成的。

稀疏數組,顧名思義是一個很稀疏的數組......

"

文 | Java聖鬥士

稀疏數組的應用與實踐,別再說學不好數據結構了

Hello 各位熱愛學習的小夥伴們大家好,今天來給大家聊聊五子棋遊戲的後臺實現

相信大家都玩過五子棋遊戲,規則就是率先連成 5 顆棋子的一方獲勝。小編小的時候也非常喜歡玩五子棋,覺得自己天下無敵了,對手再怎麼努力都不會逃脫自己的圍追堵截,堵著堵著就贏了,哈哈。

稀疏數組的應用與實踐,別再說學不好數據結構了

可是你有想過五子棋的“保存棋局”和“續上局”是如何實現的嗎?

五子棋的數據結構描述

我們知道,五子棋有一個正方形棋盤,分別設有白子和黑子:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼這個五子棋盤就可以使用二維數組來描述,假設是一個 11 × 11 的二維數組:

int[][] chessArr = new int[11][11];

然後我們輸出一下:

for (int[] row : chessArr) {
\tfor (int data : row) {
\t\tSystem.out.printf("%d ", data);
\t}
\tSystem.out.println();
}
稀疏數組的應用與實踐,別再說學不好數據結構了

然後我們先來填幾顆棋子,模擬一個五子棋局,在代碼中,由於初始的二維數組中默認都是 0 ,那我們就可以考慮用 1 代表 黑子,用 2 代表白子:

chessArr[1][2] = 1; // 黑子先行
chessArr[2][3] = 2; // 白子緊隨其後
chessArr[1][4] = 1; // 黑子欲形成橫向三連之勢
chessArr[1][3] = 2; // 白子“挺進大別山”斷了黑子的陰謀

再輸出,就可以看到黑子白子形成的“圍追堵截”之勢了,有沒有點懷念小時候的感覺?

稀疏數組的應用與實踐,別再說學不好數據結構了

棋盤的壓縮保存

接下來就是今天的正題!如果你已經看到這裡,一定要堅持!

五子棋的保存實際上並不是保存整個棋盤,而是通過一個叫做“稀疏數組”的結構來完成的。

稀疏數組,顧名思義是一個很稀疏的數組......

稀疏數組的應用與實踐,別再說學不好數據結構了

咳咳,稀疏數組實際上是一個只保存原始二維數組有效數據,去掉無效數據的一個二維數組。

當一個數組中大部分元素是0,或為同一個值的時候,可以使用稀疏數組來保存數組。它是一個十分有效的壓縮存儲結構,而且還不涉及任何複雜的算法,簡單又實用!

"

文 | Java聖鬥士

稀疏數組的應用與實踐,別再說學不好數據結構了

Hello 各位熱愛學習的小夥伴們大家好,今天來給大家聊聊五子棋遊戲的後臺實現

相信大家都玩過五子棋遊戲,規則就是率先連成 5 顆棋子的一方獲勝。小編小的時候也非常喜歡玩五子棋,覺得自己天下無敵了,對手再怎麼努力都不會逃脫自己的圍追堵截,堵著堵著就贏了,哈哈。

稀疏數組的應用與實踐,別再說學不好數據結構了

可是你有想過五子棋的“保存棋局”和“續上局”是如何實現的嗎?

五子棋的數據結構描述

我們知道,五子棋有一個正方形棋盤,分別設有白子和黑子:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼這個五子棋盤就可以使用二維數組來描述,假設是一個 11 × 11 的二維數組:

int[][] chessArr = new int[11][11];

然後我們輸出一下:

for (int[] row : chessArr) {
\tfor (int data : row) {
\t\tSystem.out.printf("%d ", data);
\t}
\tSystem.out.println();
}
稀疏數組的應用與實踐,別再說學不好數據結構了

然後我們先來填幾顆棋子,模擬一個五子棋局,在代碼中,由於初始的二維數組中默認都是 0 ,那我們就可以考慮用 1 代表 黑子,用 2 代表白子:

chessArr[1][2] = 1; // 黑子先行
chessArr[2][3] = 2; // 白子緊隨其後
chessArr[1][4] = 1; // 黑子欲形成橫向三連之勢
chessArr[1][3] = 2; // 白子“挺進大別山”斷了黑子的陰謀

再輸出,就可以看到黑子白子形成的“圍追堵截”之勢了,有沒有點懷念小時候的感覺?

稀疏數組的應用與實踐,別再說學不好數據結構了

棋盤的壓縮保存

接下來就是今天的正題!如果你已經看到這裡,一定要堅持!

五子棋的保存實際上並不是保存整個棋盤,而是通過一個叫做“稀疏數組”的結構來完成的。

稀疏數組,顧名思義是一個很稀疏的數組......

稀疏數組的應用與實踐,別再說學不好數據結構了

咳咳,稀疏數組實際上是一個只保存原始二維數組有效數據,去掉無效數據的一個二維數組。

當一個數組中大部分元素是0,或為同一個值的時候,可以使用稀疏數組來保存數組。它是一個十分有效的壓縮存儲結構,而且還不涉及任何複雜的算法,簡單又實用!

稀疏數組的應用與實踐,別再說學不好數據結構了

它的處理方式是:

1、記錄數組一共有幾行幾列有多少有效值

2、把具有有效值的元素的行、列及值記錄在一個小規模二維數組中(稀疏數組),從而降低存儲數據的規模。

如果一個二維數組長這樣:

"

文 | Java聖鬥士

稀疏數組的應用與實踐,別再說學不好數據結構了

Hello 各位熱愛學習的小夥伴們大家好,今天來給大家聊聊五子棋遊戲的後臺實現

相信大家都玩過五子棋遊戲,規則就是率先連成 5 顆棋子的一方獲勝。小編小的時候也非常喜歡玩五子棋,覺得自己天下無敵了,對手再怎麼努力都不會逃脫自己的圍追堵截,堵著堵著就贏了,哈哈。

稀疏數組的應用與實踐,別再說學不好數據結構了

可是你有想過五子棋的“保存棋局”和“續上局”是如何實現的嗎?

五子棋的數據結構描述

我們知道,五子棋有一個正方形棋盤,分別設有白子和黑子:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼這個五子棋盤就可以使用二維數組來描述,假設是一個 11 × 11 的二維數組:

int[][] chessArr = new int[11][11];

然後我們輸出一下:

for (int[] row : chessArr) {
\tfor (int data : row) {
\t\tSystem.out.printf("%d ", data);
\t}
\tSystem.out.println();
}
稀疏數組的應用與實踐,別再說學不好數據結構了

然後我們先來填幾顆棋子,模擬一個五子棋局,在代碼中,由於初始的二維數組中默認都是 0 ,那我們就可以考慮用 1 代表 黑子,用 2 代表白子:

chessArr[1][2] = 1; // 黑子先行
chessArr[2][3] = 2; // 白子緊隨其後
chessArr[1][4] = 1; // 黑子欲形成橫向三連之勢
chessArr[1][3] = 2; // 白子“挺進大別山”斷了黑子的陰謀

再輸出,就可以看到黑子白子形成的“圍追堵截”之勢了,有沒有點懷念小時候的感覺?

稀疏數組的應用與實踐,別再說學不好數據結構了

棋盤的壓縮保存

接下來就是今天的正題!如果你已經看到這裡,一定要堅持!

五子棋的保存實際上並不是保存整個棋盤,而是通過一個叫做“稀疏數組”的結構來完成的。

稀疏數組,顧名思義是一個很稀疏的數組......

稀疏數組的應用與實踐,別再說學不好數據結構了

咳咳,稀疏數組實際上是一個只保存原始二維數組有效數據,去掉無效數據的一個二維數組。

當一個數組中大部分元素是0,或為同一個值的時候,可以使用稀疏數組來保存數組。它是一個十分有效的壓縮存儲結構,而且還不涉及任何複雜的算法,簡單又實用!

稀疏數組的應用與實踐,別再說學不好數據結構了

它的處理方式是:

1、記錄數組一共有幾行幾列有多少有效值

2、把具有有效值的元素的行、列及值記錄在一個小規模二維數組中(稀疏數組),從而降低存儲數據的規模。

如果一個二維數組長這樣:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼用於保存它的稀疏數組就可以是這樣:

"

文 | Java聖鬥士

稀疏數組的應用與實踐,別再說學不好數據結構了

Hello 各位熱愛學習的小夥伴們大家好,今天來給大家聊聊五子棋遊戲的後臺實現

相信大家都玩過五子棋遊戲,規則就是率先連成 5 顆棋子的一方獲勝。小編小的時候也非常喜歡玩五子棋,覺得自己天下無敵了,對手再怎麼努力都不會逃脫自己的圍追堵截,堵著堵著就贏了,哈哈。

稀疏數組的應用與實踐,別再說學不好數據結構了

可是你有想過五子棋的“保存棋局”和“續上局”是如何實現的嗎?

五子棋的數據結構描述

我們知道,五子棋有一個正方形棋盤,分別設有白子和黑子:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼這個五子棋盤就可以使用二維數組來描述,假設是一個 11 × 11 的二維數組:

int[][] chessArr = new int[11][11];

然後我們輸出一下:

for (int[] row : chessArr) {
\tfor (int data : row) {
\t\tSystem.out.printf("%d ", data);
\t}
\tSystem.out.println();
}
稀疏數組的應用與實踐,別再說學不好數據結構了

然後我們先來填幾顆棋子,模擬一個五子棋局,在代碼中,由於初始的二維數組中默認都是 0 ,那我們就可以考慮用 1 代表 黑子,用 2 代表白子:

chessArr[1][2] = 1; // 黑子先行
chessArr[2][3] = 2; // 白子緊隨其後
chessArr[1][4] = 1; // 黑子欲形成橫向三連之勢
chessArr[1][3] = 2; // 白子“挺進大別山”斷了黑子的陰謀

再輸出,就可以看到黑子白子形成的“圍追堵截”之勢了,有沒有點懷念小時候的感覺?

稀疏數組的應用與實踐,別再說學不好數據結構了

棋盤的壓縮保存

接下來就是今天的正題!如果你已經看到這裡,一定要堅持!

五子棋的保存實際上並不是保存整個棋盤,而是通過一個叫做“稀疏數組”的結構來完成的。

稀疏數組,顧名思義是一個很稀疏的數組......

稀疏數組的應用與實踐,別再說學不好數據結構了

咳咳,稀疏數組實際上是一個只保存原始二維數組有效數據,去掉無效數據的一個二維數組。

當一個數組中大部分元素是0,或為同一個值的時候,可以使用稀疏數組來保存數組。它是一個十分有效的壓縮存儲結構,而且還不涉及任何複雜的算法,簡單又實用!

稀疏數組的應用與實踐,別再說學不好數據結構了

它的處理方式是:

1、記錄數組一共有幾行幾列有多少有效值

2、把具有有效值的元素的行、列及值記錄在一個小規模二維數組中(稀疏數組),從而降低存儲數據的規模。

如果一個二維數組長這樣:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼用於保存它的稀疏數組就可以是這樣:

稀疏數組的應用與實踐,別再說學不好數據結構了

如上圖所示:稀疏數組有固定的三列,分別代表原始二維數組的行、列和值,但是第一行具有特殊的含義:稀疏數組的第一行存儲原始數組的行數、列數和有效數據個數,這三個信息。而從第二行(也就是[1]行)開始,才是真正的原始二維數組的有效數據。

是不是非常簡單?

稀疏數組保存五子棋的代碼實現

分析完了稀疏數組的數據結構,那麼我們就來通過代碼實現上面五子棋局的保存。

剛才的五子棋局是這樣的:

"

文 | Java聖鬥士

稀疏數組的應用與實踐,別再說學不好數據結構了

Hello 各位熱愛學習的小夥伴們大家好,今天來給大家聊聊五子棋遊戲的後臺實現

相信大家都玩過五子棋遊戲,規則就是率先連成 5 顆棋子的一方獲勝。小編小的時候也非常喜歡玩五子棋,覺得自己天下無敵了,對手再怎麼努力都不會逃脫自己的圍追堵截,堵著堵著就贏了,哈哈。

稀疏數組的應用與實踐,別再說學不好數據結構了

可是你有想過五子棋的“保存棋局”和“續上局”是如何實現的嗎?

五子棋的數據結構描述

我們知道,五子棋有一個正方形棋盤,分別設有白子和黑子:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼這個五子棋盤就可以使用二維數組來描述,假設是一個 11 × 11 的二維數組:

int[][] chessArr = new int[11][11];

然後我們輸出一下:

for (int[] row : chessArr) {
\tfor (int data : row) {
\t\tSystem.out.printf("%d ", data);
\t}
\tSystem.out.println();
}
稀疏數組的應用與實踐,別再說學不好數據結構了

然後我們先來填幾顆棋子,模擬一個五子棋局,在代碼中,由於初始的二維數組中默認都是 0 ,那我們就可以考慮用 1 代表 黑子,用 2 代表白子:

chessArr[1][2] = 1; // 黑子先行
chessArr[2][3] = 2; // 白子緊隨其後
chessArr[1][4] = 1; // 黑子欲形成橫向三連之勢
chessArr[1][3] = 2; // 白子“挺進大別山”斷了黑子的陰謀

再輸出,就可以看到黑子白子形成的“圍追堵截”之勢了,有沒有點懷念小時候的感覺?

稀疏數組的應用與實踐,別再說學不好數據結構了

棋盤的壓縮保存

接下來就是今天的正題!如果你已經看到這裡,一定要堅持!

五子棋的保存實際上並不是保存整個棋盤,而是通過一個叫做“稀疏數組”的結構來完成的。

稀疏數組,顧名思義是一個很稀疏的數組......

稀疏數組的應用與實踐,別再說學不好數據結構了

咳咳,稀疏數組實際上是一個只保存原始二維數組有效數據,去掉無效數據的一個二維數組。

當一個數組中大部分元素是0,或為同一個值的時候,可以使用稀疏數組來保存數組。它是一個十分有效的壓縮存儲結構,而且還不涉及任何複雜的算法,簡單又實用!

稀疏數組的應用與實踐,別再說學不好數據結構了

它的處理方式是:

1、記錄數組一共有幾行幾列有多少有效值

2、把具有有效值的元素的行、列及值記錄在一個小規模二維數組中(稀疏數組),從而降低存儲數據的規模。

如果一個二維數組長這樣:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼用於保存它的稀疏數組就可以是這樣:

稀疏數組的應用與實踐,別再說學不好數據結構了

如上圖所示:稀疏數組有固定的三列,分別代表原始二維數組的行、列和值,但是第一行具有特殊的含義:稀疏數組的第一行存儲原始數組的行數、列數和有效數據個數,這三個信息。而從第二行(也就是[1]行)開始,才是真正的原始二維數組的有效數據。

是不是非常簡單?

稀疏數組保存五子棋的代碼實現

分析完了稀疏數組的數據結構,那麼我們就來通過代碼實現上面五子棋局的保存。

剛才的五子棋局是這樣的:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼如何生成對應的稀疏數組呢?當然是先循環了......

首先要確定有多少個有效數據,這個是非常關鍵的:

int sum = 0;
for (int i = 0; i < chessArr.length; i++) {
\tfor (int j = 0; j < chessArr[0].length; j++) {
\t\tif (chessArr[i][j] != 0) {
\t\t\tsum++;
\t\t}
\t}
}

得到 sum 的原始二維數組有效數據有,我們就可以聲明這個稀疏數組了:

int[][] sparseArr = new int[sum + 1][3];

然後是將原始數組行數列數有效數據個數 放入稀疏數組的第一行:

sparseArr[0][0] = chessArr.length;
sparseArr[0][1] = chessArr[0].length;
sparseArr[0][2] = sum;

最後就是將原始數組中的非 0 數據存放到稀疏數組

int sparseArrRow = 1;
for (int i = 0; i < chessArr.length; i++) {
\tfor (int j = 0; j < chessArr[0].length; j++) {
\t\tif (chessArr[i][j] != 0) {
\t\t\tsparseArr[sparseArrRow][0] = i;
\t\t\tsparseArr[sparseArrRow][1] = j;
\t\t\tsparseArr[sparseArrRow][2] = chessArr[i][j];
\t\t\tsparseArrRow++;
\t\t}
\t}
}

到這裡為止,就完成了對稀疏數組的創建和賦值,我們的二維數組也已經放入到了這個 “壓縮”了的二維數組——稀疏數組之中。那我們來輸出一下這個稀疏數組,看看是不是我們想要的內容:

"

文 | Java聖鬥士

稀疏數組的應用與實踐,別再說學不好數據結構了

Hello 各位熱愛學習的小夥伴們大家好,今天來給大家聊聊五子棋遊戲的後臺實現

相信大家都玩過五子棋遊戲,規則就是率先連成 5 顆棋子的一方獲勝。小編小的時候也非常喜歡玩五子棋,覺得自己天下無敵了,對手再怎麼努力都不會逃脫自己的圍追堵截,堵著堵著就贏了,哈哈。

稀疏數組的應用與實踐,別再說學不好數據結構了

可是你有想過五子棋的“保存棋局”和“續上局”是如何實現的嗎?

五子棋的數據結構描述

我們知道,五子棋有一個正方形棋盤,分別設有白子和黑子:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼這個五子棋盤就可以使用二維數組來描述,假設是一個 11 × 11 的二維數組:

int[][] chessArr = new int[11][11];

然後我們輸出一下:

for (int[] row : chessArr) {
\tfor (int data : row) {
\t\tSystem.out.printf("%d ", data);
\t}
\tSystem.out.println();
}
稀疏數組的應用與實踐,別再說學不好數據結構了

然後我們先來填幾顆棋子,模擬一個五子棋局,在代碼中,由於初始的二維數組中默認都是 0 ,那我們就可以考慮用 1 代表 黑子,用 2 代表白子:

chessArr[1][2] = 1; // 黑子先行
chessArr[2][3] = 2; // 白子緊隨其後
chessArr[1][4] = 1; // 黑子欲形成橫向三連之勢
chessArr[1][3] = 2; // 白子“挺進大別山”斷了黑子的陰謀

再輸出,就可以看到黑子白子形成的“圍追堵截”之勢了,有沒有點懷念小時候的感覺?

稀疏數組的應用與實踐,別再說學不好數據結構了

棋盤的壓縮保存

接下來就是今天的正題!如果你已經看到這裡,一定要堅持!

五子棋的保存實際上並不是保存整個棋盤,而是通過一個叫做“稀疏數組”的結構來完成的。

稀疏數組,顧名思義是一個很稀疏的數組......

稀疏數組的應用與實踐,別再說學不好數據結構了

咳咳,稀疏數組實際上是一個只保存原始二維數組有效數據,去掉無效數據的一個二維數組。

當一個數組中大部分元素是0,或為同一個值的時候,可以使用稀疏數組來保存數組。它是一個十分有效的壓縮存儲結構,而且還不涉及任何複雜的算法,簡單又實用!

稀疏數組的應用與實踐,別再說學不好數據結構了

它的處理方式是:

1、記錄數組一共有幾行幾列有多少有效值

2、把具有有效值的元素的行、列及值記錄在一個小規模二維數組中(稀疏數組),從而降低存儲數據的規模。

如果一個二維數組長這樣:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼用於保存它的稀疏數組就可以是這樣:

稀疏數組的應用與實踐,別再說學不好數據結構了

如上圖所示:稀疏數組有固定的三列,分別代表原始二維數組的行、列和值,但是第一行具有特殊的含義:稀疏數組的第一行存儲原始數組的行數、列數和有效數據個數,這三個信息。而從第二行(也就是[1]行)開始,才是真正的原始二維數組的有效數據。

是不是非常簡單?

稀疏數組保存五子棋的代碼實現

分析完了稀疏數組的數據結構,那麼我們就來通過代碼實現上面五子棋局的保存。

剛才的五子棋局是這樣的:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼如何生成對應的稀疏數組呢?當然是先循環了......

首先要確定有多少個有效數據,這個是非常關鍵的:

int sum = 0;
for (int i = 0; i < chessArr.length; i++) {
\tfor (int j = 0; j < chessArr[0].length; j++) {
\t\tif (chessArr[i][j] != 0) {
\t\t\tsum++;
\t\t}
\t}
}

得到 sum 的原始二維數組有效數據有,我們就可以聲明這個稀疏數組了:

int[][] sparseArr = new int[sum + 1][3];

然後是將原始數組行數列數有效數據個數 放入稀疏數組的第一行:

sparseArr[0][0] = chessArr.length;
sparseArr[0][1] = chessArr[0].length;
sparseArr[0][2] = sum;

最後就是將原始數組中的非 0 數據存放到稀疏數組

int sparseArrRow = 1;
for (int i = 0; i < chessArr.length; i++) {
\tfor (int j = 0; j < chessArr[0].length; j++) {
\t\tif (chessArr[i][j] != 0) {
\t\t\tsparseArr[sparseArrRow][0] = i;
\t\t\tsparseArr[sparseArrRow][1] = j;
\t\t\tsparseArr[sparseArrRow][2] = chessArr[i][j];
\t\t\tsparseArrRow++;
\t\t}
\t}
}

到這裡為止,就完成了對稀疏數組的創建和賦值,我們的二維數組也已經放入到了這個 “壓縮”了的二維數組——稀疏數組之中。那我們來輸出一下這個稀疏數組,看看是不是我們想要的內容:

稀疏數組的應用與實踐,別再說學不好數據結構了

完美!

五子棋的覆盤——稀疏數組還原原始二維數組

有了上面的經驗,下面的“小怪獸”就基本上不需要怎麼打了。

"

文 | Java聖鬥士

稀疏數組的應用與實踐,別再說學不好數據結構了

Hello 各位熱愛學習的小夥伴們大家好,今天來給大家聊聊五子棋遊戲的後臺實現

相信大家都玩過五子棋遊戲,規則就是率先連成 5 顆棋子的一方獲勝。小編小的時候也非常喜歡玩五子棋,覺得自己天下無敵了,對手再怎麼努力都不會逃脫自己的圍追堵截,堵著堵著就贏了,哈哈。

稀疏數組的應用與實踐,別再說學不好數據結構了

可是你有想過五子棋的“保存棋局”和“續上局”是如何實現的嗎?

五子棋的數據結構描述

我們知道,五子棋有一個正方形棋盤,分別設有白子和黑子:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼這個五子棋盤就可以使用二維數組來描述,假設是一個 11 × 11 的二維數組:

int[][] chessArr = new int[11][11];

然後我們輸出一下:

for (int[] row : chessArr) {
\tfor (int data : row) {
\t\tSystem.out.printf("%d ", data);
\t}
\tSystem.out.println();
}
稀疏數組的應用與實踐,別再說學不好數據結構了

然後我們先來填幾顆棋子,模擬一個五子棋局,在代碼中,由於初始的二維數組中默認都是 0 ,那我們就可以考慮用 1 代表 黑子,用 2 代表白子:

chessArr[1][2] = 1; // 黑子先行
chessArr[2][3] = 2; // 白子緊隨其後
chessArr[1][4] = 1; // 黑子欲形成橫向三連之勢
chessArr[1][3] = 2; // 白子“挺進大別山”斷了黑子的陰謀

再輸出,就可以看到黑子白子形成的“圍追堵截”之勢了,有沒有點懷念小時候的感覺?

稀疏數組的應用與實踐,別再說學不好數據結構了

棋盤的壓縮保存

接下來就是今天的正題!如果你已經看到這裡,一定要堅持!

五子棋的保存實際上並不是保存整個棋盤,而是通過一個叫做“稀疏數組”的結構來完成的。

稀疏數組,顧名思義是一個很稀疏的數組......

稀疏數組的應用與實踐,別再說學不好數據結構了

咳咳,稀疏數組實際上是一個只保存原始二維數組有效數據,去掉無效數據的一個二維數組。

當一個數組中大部分元素是0,或為同一個值的時候,可以使用稀疏數組來保存數組。它是一個十分有效的壓縮存儲結構,而且還不涉及任何複雜的算法,簡單又實用!

稀疏數組的應用與實踐,別再說學不好數據結構了

它的處理方式是:

1、記錄數組一共有幾行幾列有多少有效值

2、把具有有效值的元素的行、列及值記錄在一個小規模二維數組中(稀疏數組),從而降低存儲數據的規模。

如果一個二維數組長這樣:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼用於保存它的稀疏數組就可以是這樣:

稀疏數組的應用與實踐,別再說學不好數據結構了

如上圖所示:稀疏數組有固定的三列,分別代表原始二維數組的行、列和值,但是第一行具有特殊的含義:稀疏數組的第一行存儲原始數組的行數、列數和有效數據個數,這三個信息。而從第二行(也就是[1]行)開始,才是真正的原始二維數組的有效數據。

是不是非常簡單?

稀疏數組保存五子棋的代碼實現

分析完了稀疏數組的數據結構,那麼我們就來通過代碼實現上面五子棋局的保存。

剛才的五子棋局是這樣的:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼如何生成對應的稀疏數組呢?當然是先循環了......

首先要確定有多少個有效數據,這個是非常關鍵的:

int sum = 0;
for (int i = 0; i < chessArr.length; i++) {
\tfor (int j = 0; j < chessArr[0].length; j++) {
\t\tif (chessArr[i][j] != 0) {
\t\t\tsum++;
\t\t}
\t}
}

得到 sum 的原始二維數組有效數據有,我們就可以聲明這個稀疏數組了:

int[][] sparseArr = new int[sum + 1][3];

然後是將原始數組行數列數有效數據個數 放入稀疏數組的第一行:

sparseArr[0][0] = chessArr.length;
sparseArr[0][1] = chessArr[0].length;
sparseArr[0][2] = sum;

最後就是將原始數組中的非 0 數據存放到稀疏數組

int sparseArrRow = 1;
for (int i = 0; i < chessArr.length; i++) {
\tfor (int j = 0; j < chessArr[0].length; j++) {
\t\tif (chessArr[i][j] != 0) {
\t\t\tsparseArr[sparseArrRow][0] = i;
\t\t\tsparseArr[sparseArrRow][1] = j;
\t\t\tsparseArr[sparseArrRow][2] = chessArr[i][j];
\t\t\tsparseArrRow++;
\t\t}
\t}
}

到這裡為止,就完成了對稀疏數組的創建和賦值,我們的二維數組也已經放入到了這個 “壓縮”了的二維數組——稀疏數組之中。那我們來輸出一下這個稀疏數組,看看是不是我們想要的內容:

稀疏數組的應用與實踐,別再說學不好數據結構了

完美!

五子棋的覆盤——稀疏數組還原原始二維數組

有了上面的經驗,下面的“小怪獸”就基本上不需要怎麼打了。

稀疏數組的應用與實踐,別再說學不好數據結構了

廢話不多說,直接上代碼:

int[][] chessArr1 = new int[sparseArr[0][0]][sparseArr[0][1]];
for (int i = 1; i < sparseArr.length; i++) {
\tchessArr1[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
}

然後輸出:

"

文 | Java聖鬥士

稀疏數組的應用與實踐,別再說學不好數據結構了

Hello 各位熱愛學習的小夥伴們大家好,今天來給大家聊聊五子棋遊戲的後臺實現

相信大家都玩過五子棋遊戲,規則就是率先連成 5 顆棋子的一方獲勝。小編小的時候也非常喜歡玩五子棋,覺得自己天下無敵了,對手再怎麼努力都不會逃脫自己的圍追堵截,堵著堵著就贏了,哈哈。

稀疏數組的應用與實踐,別再說學不好數據結構了

可是你有想過五子棋的“保存棋局”和“續上局”是如何實現的嗎?

五子棋的數據結構描述

我們知道,五子棋有一個正方形棋盤,分別設有白子和黑子:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼這個五子棋盤就可以使用二維數組來描述,假設是一個 11 × 11 的二維數組:

int[][] chessArr = new int[11][11];

然後我們輸出一下:

for (int[] row : chessArr) {
\tfor (int data : row) {
\t\tSystem.out.printf("%d ", data);
\t}
\tSystem.out.println();
}
稀疏數組的應用與實踐,別再說學不好數據結構了

然後我們先來填幾顆棋子,模擬一個五子棋局,在代碼中,由於初始的二維數組中默認都是 0 ,那我們就可以考慮用 1 代表 黑子,用 2 代表白子:

chessArr[1][2] = 1; // 黑子先行
chessArr[2][3] = 2; // 白子緊隨其後
chessArr[1][4] = 1; // 黑子欲形成橫向三連之勢
chessArr[1][3] = 2; // 白子“挺進大別山”斷了黑子的陰謀

再輸出,就可以看到黑子白子形成的“圍追堵截”之勢了,有沒有點懷念小時候的感覺?

稀疏數組的應用與實踐,別再說學不好數據結構了

棋盤的壓縮保存

接下來就是今天的正題!如果你已經看到這裡,一定要堅持!

五子棋的保存實際上並不是保存整個棋盤,而是通過一個叫做“稀疏數組”的結構來完成的。

稀疏數組,顧名思義是一個很稀疏的數組......

稀疏數組的應用與實踐,別再說學不好數據結構了

咳咳,稀疏數組實際上是一個只保存原始二維數組有效數據,去掉無效數據的一個二維數組。

當一個數組中大部分元素是0,或為同一個值的時候,可以使用稀疏數組來保存數組。它是一個十分有效的壓縮存儲結構,而且還不涉及任何複雜的算法,簡單又實用!

稀疏數組的應用與實踐,別再說學不好數據結構了

它的處理方式是:

1、記錄數組一共有幾行幾列有多少有效值

2、把具有有效值的元素的行、列及值記錄在一個小規模二維數組中(稀疏數組),從而降低存儲數據的規模。

如果一個二維數組長這樣:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼用於保存它的稀疏數組就可以是這樣:

稀疏數組的應用與實踐,別再說學不好數據結構了

如上圖所示:稀疏數組有固定的三列,分別代表原始二維數組的行、列和值,但是第一行具有特殊的含義:稀疏數組的第一行存儲原始數組的行數、列數和有效數據個數,這三個信息。而從第二行(也就是[1]行)開始,才是真正的原始二維數組的有效數據。

是不是非常簡單?

稀疏數組保存五子棋的代碼實現

分析完了稀疏數組的數據結構,那麼我們就來通過代碼實現上面五子棋局的保存。

剛才的五子棋局是這樣的:

稀疏數組的應用與實踐,別再說學不好數據結構了

那麼如何生成對應的稀疏數組呢?當然是先循環了......

首先要確定有多少個有效數據,這個是非常關鍵的:

int sum = 0;
for (int i = 0; i < chessArr.length; i++) {
\tfor (int j = 0; j < chessArr[0].length; j++) {
\t\tif (chessArr[i][j] != 0) {
\t\t\tsum++;
\t\t}
\t}
}

得到 sum 的原始二維數組有效數據有,我們就可以聲明這個稀疏數組了:

int[][] sparseArr = new int[sum + 1][3];

然後是將原始數組行數列數有效數據個數 放入稀疏數組的第一行:

sparseArr[0][0] = chessArr.length;
sparseArr[0][1] = chessArr[0].length;
sparseArr[0][2] = sum;

最後就是將原始數組中的非 0 數據存放到稀疏數組

int sparseArrRow = 1;
for (int i = 0; i < chessArr.length; i++) {
\tfor (int j = 0; j < chessArr[0].length; j++) {
\t\tif (chessArr[i][j] != 0) {
\t\t\tsparseArr[sparseArrRow][0] = i;
\t\t\tsparseArr[sparseArrRow][1] = j;
\t\t\tsparseArr[sparseArrRow][2] = chessArr[i][j];
\t\t\tsparseArrRow++;
\t\t}
\t}
}

到這裡為止,就完成了對稀疏數組的創建和賦值,我們的二維數組也已經放入到了這個 “壓縮”了的二維數組——稀疏數組之中。那我們來輸出一下這個稀疏數組,看看是不是我們想要的內容:

稀疏數組的應用與實踐,別再說學不好數據結構了

完美!

五子棋的覆盤——稀疏數組還原原始二維數組

有了上面的經驗,下面的“小怪獸”就基本上不需要怎麼打了。

稀疏數組的應用與實踐,別再說學不好數據結構了

廢話不多說,直接上代碼:

int[][] chessArr1 = new int[sparseArr[0][0]][sparseArr[0][1]];
for (int i = 1; i < sparseArr.length; i++) {
\tchessArr1[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
}

然後輸出:

稀疏數組的應用與實踐,別再說學不好數據結構了

完美!

稀疏數組總結

其實呢,稀疏數組主要就是用於壓縮存儲,將原來的二維數組中大量的無效數據捨棄掉通過記錄行數、列數、有效值個數,以及有效值的 “座標”和值,來實現一個節省空間的存儲結構。

稀疏數組主要的特點就是體現在其獨特的數據結構上,其中不涉及任何算法,完全就是憑著結構完成了數據壓縮的功能。有點像憑顏值搞定一切的趕腳......

甚至我們也可以將稀疏數組進行改裝,在不是五子棋這種應用場景下,依然可以利用“結構化有效數據”的思路來實現數據壓縮,節省更多的存儲空間。

數據結構和算法都是需要平時慢慢積累的知識,所以,如果大家在地鐵或者公交上看了這篇文章,因為沒有靜心,讀不懂,可以收藏後,通過代碼一步一步代入式學習,相信你一定會有所收穫的。

怎麼樣?聰明的你學會了嗎?!

往期精彩:

對話式情景剖析,String被final修飾的真正原因!一篇足矣

Java如何處理JSON數據?一篇Jackson教你快速入門

教你如何優雅地用Java8 實現日期時間的操作

大話Java 8 Lambda 表達式(一)

束縛程序員工資的,從來不是什麼算法和設計模式

關注Java聖鬥士,帶你輕鬆暢談程序內外的人與事,做一個快樂的 IT 技術精英,升職加薪、迎娶白富美、走上人生巔峰!你還在等啥呢?快上車!

"

相關推薦

推薦中...