Go语言实现稀疏数组:存储优化与五子棋存盘还原
针对包含大量无效数据的二维数组(如五子棋棋盘),通过构建稀疏数组结构记录有效坐标与数值,结合Go语言代码实现从原始数组到稀疏数组的转换及文件存盘后的还原过程,从而有效降低内存占用。
五子棋存盘需求分析
在五子棋程序开发中,通常需要实现“存盘退出”和“续上盘”功能。传统的做法是将整个二维棋盘数组存入文件或数据库中。由于棋盘大部分格子为空(值为默认值0),直接保存原始数组会导致大量的冗余数据,浪费存储空间并增加I/O负担。
为了优化存储,需要引入稀疏数组(Sparse Array)的概念。当一个数组中大部分元素为0,或者为同一个值的数组时,稀疏数组可以有效缩小程序规模。
稀疏数组的基本原理
稀疏数组的核心思想是只记录有实际意义的非零(或特定值)元素的行列位置及其具体数值。其处理步骤如下:
- 记录维度信息:首先保存原二维数组的行数、列数以及所有非默认值的元素总个数。
- 记录有效数据:遍历原数组,将所有非默认值的元素的行号、列号和值依次存入一个新的小规模数组中。
通过这种方式,原本巨大的二维数组被压缩为一个仅包含必要信息的紧凑数组。
应用实例:使用Go语言实现
第1步:创建原始棋盘数组并输出
首先创建一个11×11的二维数组模拟五子棋盘,并在特定位置放置黑子(值为1)和蓝子(值为2),其余位置默认为0。随后打印出原始数组以确认数据状态。
第2步:将二维数组转换为稀疏数组
这一步是核心逻辑。我们需要遍历棋盘,统计有效数据量并构建稀疏数组的结构。
- 定义节点结构体:使用
ValNode结构体记录行的索引(row)、列的索引(col)以及该位置的值(val)。 - 初始化第一行:稀疏数组的第一行通常用于记录原数组的整体规格。在Go中,我们将行数(11)、列数(11)和有效元素总数(初始设为0,稍后更新或单独记录)存入切片头部。注意:在实际简化示例中,有时会将有效数量单独计算后放入第一行的第三列,或者在第一行固定存储行数和列数,后续数据行存储具体坐标。
- 遍历填充:嵌套循环遍历
chessMap,当发现v2 != 0时,创建一个新的ValNode并追加到稀疏数组切片中。
package main
import (
"fmt"
)
// ValNode 用于存储稀疏数组中的每一行数据
type ValNode struct {
row int
col int
val int
}
func main() {
// 1. 创建一个原始数组 (11x11 棋盘)
var chessMap [11][11]int
chessMap[1][2] = 1 // 1表示黑子
chessMap[2][3] = 2 // 2表示蓝子
// 2. 输出看看原始的数组
fmt.Println("原始数组:")
for _, v1 := range chessMap {
for _, v2 := range v1 {
fmt.Printf("%d\t", v2)
}
fmt.Println()
}
// 3. 转成稀疏数组
var sparseArr []ValNode
// 标准的一个稀疏数组应该还有一个记录元素的二维数组的规模(行和列)
// 这里我们约定:sparseArr[0] 存放原始数组的总行数、总列数 和 有效元素个数
// 但在本例简化逻辑中,我们先存放行和列,有效个数可以在遍历时统计,
// 或者按照图示逻辑,先占位。这里采用更通用的做法:
// 第一行记录: 行, 列, 有效值总数(稍后填入,此处先放0或临时计算)
// 为了简单演示,我们假设已知有效个数为2,或者动态扩展。
// 下面代码采用动态append的方式,最后再调整第一行或直接利用len()-1作为有效数
valNode := ValNode{
row: 11,
col: 11,
val: 0, // 暂存有效个数,实际应在遍历后修正,或放在独立变量
}
sparseArr = append(sparseArr, valNode)
for i1, v1 := range chessMap {
for i2, v2 := range v1 {
if v2 != 0 {
// 创建一个ValNode 值结点
valNode = ValNode{
row: i1,
col: i2,
val: v2,
}
sparseArr = append(sparseArr, valNode)
}
}
}
// 更新第一行,使其正确反映有效元素的数量
// 此时 sparseArr 的长度减去头部的一个元素,即为有效元素个数
if len(sparseArr) > 0 {
sparseArr[0].val = len(sparseArr) - 1
}
// 输出稀疏数组
fmt.Println("当前的稀疏数组是:::::")
for i, node := range sparseArr {
fmt.Printf("%d:%d %d %d \n", i, node.row, node.col, node.val)
}
// 4. 恢复原始数组
// 思路:根据稀疏数组重建二维数组
var chessMap2 [11][11]int
// 跳过稀疏数组的第一行(元数据),从第二行开始读取有效数据
for index, node := range sparseArr {
if index == 0 {
continue
}
chessMap2[node.row][node.col] = node.val
}
// 验证恢复结果
fmt.Println("恢复后的数组:")
for _, value1 := range chessMap2 {
for _, value2 := range value1 {
fmt.Printf("%d \t", value2)
}
fmt.Println()
}
}
第3步:解析与还原逻辑说明
当需要将数据从文件中读取并还原时,流程相反:
- 读取元数据:从稀疏数组第一行获取原始数组的行数、列数和有效元素总数。
- 初始化原数组:根据行数和列数创建一个全新的二维数组(默认值均为0)。
- 写入有效值:遍历稀疏数组的剩余部分,对于每一行,将其记录的行号(row)和列号(col)作为索引,将该位置的值(val)写入到新创建的二维数组中。
总结
稀疏数组通过对大量重复或默认数据进行压缩,显著减少了存储需求。在本例中,Go语言通过结构体和切片灵活地实现了这一数据结构。这种技术不仅适用于五子棋存档,也广泛应用于地图数据、图像透明层处理等场景。以上就是Go稀疏数组的详细解析与实战演示,更多关于Go数据结构优化的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









