五子棋与稀疏数组

简介: 五子棋与稀疏数组

前言

稀疏数组是我们一开始学数据结构的时候第一次有点味道的小算法了,大部分的人第一次是交代在这里。这是因为,这个需求来自于我们比较喜欢的五子棋小游戏。这个游戏主要是当年有个东西叫做电子词典,也不知道是啥规则,清一色都有这个游戏。

稀疏数组在应用在五子棋上面的一个原因是,落子不多的话格子是很少,但是我们定义全局的时候其实是一个二维数组

说正事

棋盘中的代码其实是一个数组,但是里面会附带很多0元素,这样子保存起来其实是很划不来的,我们要实现的就是按照压缩策略去进行存储。

首先我们的数组长这个样子:

  |0| |1| |2| |3| |4| |5| |6| |7| |8| 
|0|  0   0   0   0   0   1   1   0   0  
|1|  0   0   0   0   0   0   0   0   0  
|2|  0   0   0   0   0   0   0   0   0  
|3|  0   0   0   0   0   0   0   0   0  
|4|  0   0   0   0   0   0   0   0   0  
|5|  0   0   0   0   0   0   0   0   0  
|6|  0   0   0   0   0   0   0   2   2  
|7|  0   0   0   0   0   0   0   0   0  
|8|  0   0   0   0   0   0   0   0   0  

我们的有效数据其实只有4个,我们定义稀疏数组的规则如下:

1.首行保存数组多少行多少列

2.剩下的行按照行号+列号+原数值来保存

具体的保存效果如下:

  [9][9][4] 首行表示原数组有多少行多少列
  [0][5][1] 剩下的行数存储信息为行号|列号|原数值
  [6][7][2]
  [6][8][1]

一旦这样子去做,我们的数组一下子就减少很多,至少肉眼看过去盘面也小很多。

稀疏数组生成

稀疏数组的转换,核心部分我加了详细注释

 public void sparseArr(){
        int count=0; 
        //因为需要知道稀疏数组的大小,除了首行之外我们需要有多少个有效的元素
        for(int i = 0; i< chessArry.length; i++){
            for (int j = 0; j < chessArry[i].length; j++) {
                if(chessArry[i][j]!=0){
                    count++;
                }
            }
        }
        //0行用来保存原数组的大小信息
        sparseArray=new int[count+1][3];
        //首行赋值
        sparseArray[0][0]=chessArrySize;
        sparseArray[0][1]=chessArrySize;
        sparseArray[0][2]=count;
        //保存有效元素按照 行号|列号|值的格式去存储
        int offset=1;
        for (int i = 0; i < chessArry.length; i++) {
            for (int  j = 0; j < chessArry[i].length; j++) {
                if(chessArry[i][j]!=0){
                   sparseArray[offset][0]=i;
                   sparseArray[offset][1]=j;
                   sparseArray[offset][2]=chessArry[i][j];
                    offset++;
                }
            }
        }
    }

稀疏数组存盘与恢复

存盘操作就是一个写文件操作,但是文件需要我们约定一下格式,以便读取的时候按照格式恢复,我这边直接用竖线分割就好了。

  public void storeChess(){
        if(sparseArray==null){
            sparseArr();
        }
        //把稀疏数组保存到磁盘
        File file=new File(storePath);
        PrintWriter printWriter=null;
        try {
             printWriter=new PrintWriter(new FileOutputStream(file));
            for (int i = 0; i < sparseArray.length; i++) {
                for (int j = 0; j < sparseArray[i].length; j++) {
                    printWriter.print(sparseArray[i][j]+"|");
                }
                printWriter.println();
            }
            System.out.printf("sparse data save to %s successful!\n",storePath);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            if(printWriter!=null){
                printWriter.close();
            }
        }
    }

数据恢复

数据恢复包含两个方面,一个是从磁盘读取,另外是我们需要恢复成正常的数组,这个是数据解压的操作。

  public void restoreChess(){
        if(chessArry!=null){
            clearChess();
        }
        System.out.println("准备恢复棋盘...");
        //从文件中恢复数据
        File file=new File(storePath);
        try {
            BufferedReader br=new BufferedReader(new FileReader(file));
            String firstLine= br.readLine();//首行记录了棋盘的信息
            String[] headSplits= firstLine.split("\\|");
            int lineSize=Integer.valueOf(headSplits[0]);
            int cloumnSize=Integer.valueOf(headSplits[1]);
            int elCount=Integer.valueOf(headSplits[2]);
            System.out.printf("棋盘行数:%d,棋盘列数%d,有效元素个数%d\n",lineSize,cloumnSize,elCount);
            chessArry=new int[lineSize][cloumnSize];
            for(int i=1;i<elCount+1;i++){ //第一行开始才有元素
                String line= br.readLine();//数组信息
                String[] lineSplit= line.split("\\|");
                int xIndex=Integer.valueOf(lineSplit[0]);
                int yIndex=Integer.valueOf(lineSplit[1]);
                int value=Integer.valueOf(lineSplit[2]);
                chessArry[xIndex][yIndex]=value;
            }
            System.out.println("恢复棋盘完成...");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

整个连起来跑一通

略去原数组

压缩后的数组
9 9 4 
0 5 1 
0 6 1 
6 7 2 
6 8 2 
准备恢复棋盘...
棋盘行数:9,棋盘列数9,有效元素个数4
恢复棋盘完成...
  |0| |1| |2| |3| |4| |5| |6| |7| |8| 
|0|  0   0   0   0   0   1   1   0   0  
|1|  0   0   0   0   0   0   0   0   0  
|2|  0   0   0   0   0   0   0   0   0  
|3|  0   0   0   0   0   0   0   0   0  
|4|  0   0   0   0   0   0   0   0   0  
|5|  0   0   0   0   0   0   0   0   0  
|6|  0   0   0   0   0   0   0   2   2  
|7|  0   0   0   0   0   0   0   0   0  
|8|  0   0   0   0   0   0   0   0   0  

后记

博客上面展示代码其实比较长,但是还没想到好点的办法,最后附上源码:

稀疏数组源码

目录
相关文章
|
2天前
|
云安全 人工智能 算法
以“AI对抗AI”,阿里云验证码进入2.0时代
三层立体防护,用大模型打赢人机攻防战
1294 3
|
3天前
|
机器学习/深度学习 安全 API
MAI-UI 开源:通用 GUI 智能体基座登顶 SOTA!
MAI-UI是通义实验室推出的全尺寸GUI智能体基座模型,原生集成用户交互、MCP工具调用与端云协同能力。支持跨App操作、模糊语义理解与主动提问澄清,通过大规模在线强化学习实现复杂任务自动化,在出行、办公等高频场景中表现卓越,已登顶ScreenSpot-Pro、MobileWorld等多项SOTA评测。
587 3
|
3天前
|
人工智能 Rust 运维
这个神器让你白嫖ClaudeOpus 4.5,Gemini 3!还能接Claude Code等任意平台
加我进AI讨论学习群,公众号右下角“联系方式”文末有老金的 开源知识库地址·全免费
|
10天前
|
编解码 人工智能 自然语言处理
⚽阿里云百炼通义万相 2.6 视频生成玩法手册
通义万相Wan 2.6是全球首个支持角色扮演的AI视频生成模型,可基于参考视频形象与音色生成多角色合拍、多镜头叙事的15秒长视频,实现声画同步、智能分镜,适用于影视创作、营销展示等场景。
716 4
|
3天前
|
存储 弹性计算 安全
阿里云服务器4核8G收费标准和活动价格参考:u2a实例898.20元起,计算型c9a3459.05元起
现在租用阿里云服务器4核8G价格是多少?具体价格及配置详情如下:云服务器ECS通用算力型u2a实例,配备4核8G配置、1M带宽及40G ESSD云盘(作为系统盘),其活动价格为898.20元/1年起;此外,ECS计算型c9a实例4核8G配置搭配20G ESSD云盘,活动价格为3459.05元/1年起。在阿里云的当前活动中,4核8G云服务器提供了多种实例规格供用户选择,不同实例规格及带宽的组合将带来不同的优惠价格。本文为大家解析阿里云服务器4核8G配置的实例规格收费标准与最新活动价格情况,以供参考。
245 150
|
3天前
|
人工智能 自然语言处理 安全
阿里云万小智AI建站:基础版、标准版、企业版主要功能及价格对比和选择参考
阿里云万小智 AI 建站是一款基于 AI 驱动的自助建站产品,无需代码基础,通过可视化拖拽与 AI 对话即可快速构建高性能、多语言、安全合规的网站。系统深度集成阿里云 ECS、RDS、OSS、CDN、SLB 与 Web 应用防火墙,保障高可用性、数据安全与全球访问速度。其提供多个版本,精准匹配从个人工作室到中大型企业的差异化需求。
238 167