Java数据结构:稀疏数组的实现与应用

简介: 文章目录1 稀疏数组引入1.1 使用场景1.2 稀疏数组简介2 稀疏数组的实现2.1 案例概述2.2 思路分析2.3 代码实现

1 稀疏数组引入

1.1 使用场景

笔者在课程设计中曾写过一个扫雷小游戏,为了便于讲解,我们来做个简化(实际比这个复杂),只考虑当前位置有雷与无雷两种状况:雷用1表示,非雷用0表示。则将当前状态用二维数组表示如下:

在右侧的二维数组中,很多都是0,即记录了很多没有意义的数据,因此,我们考虑使用稀疏数组进行存储结构的优化。


1.2 稀疏数组简介

当一个数组中的大部分元素都是0(或者为相同的某一值),可以考虑使用稀疏数组来优化保存。

而稀疏数组的基本处理方式为:


记录数组有几行几列,有几个有效值;

把有效值的元素的行、列及值记录在一个小规模的数组中,从而缩小程序的规模。

例如上述的二维数组用稀疏数组表示,可以创建一个n*3列的稀疏数组。其中,n为有效值个数加1,第一行用于存储二维数组的行数、列数及有效值的个数,便于恢复二维数组时使用。

而从第二行开始后的每一行,都记录某个有效值的所在行、列索引与值。

上述二维数组用稀疏数组表示如下:

稀疏数组的第n行 row col val
0 10 10 8
1 0 4 1
2 0 8 1
3 1 5 1
4 1 7 1
5 4 8 1
6 5 5 1
7 7 2 1
8 8 7 1


以索引0那行,10 10 8为例:表示原二维数组有10行10列,共有8个有效值。

以索引1那行,0 4 1为例:即第一个有效值在原数组的第0行第4列(索引为0和4),值为1,以此类推…

2 稀疏数组的实现

2.1 案例概述

1.使用稀疏数组来保存前面1.1样例中的二维数组(见下图);

2.可以由稀疏数组恢复成二维数组。


2.2 思路分析


二维数组转稀疏数组:


  1. 遍历原始的二维数组,得到有效数据的个数 amount;
  2. 根据 amount 可以创建稀疏数组 sparseArray[amount+1][3];
  3. 将二维数组中的有效值存入稀疏数组中。

稀疏数组恢复二维数组:


先读取稀疏数组的第一行,根据第一行的数据,创建原始二维数组;

读取第二行及以后行的数据,按照每行的行、列、值恢复有效值,录入二维数组中。

2.3 代码实现

根据如上思路,逐步实现稀疏数组,详情可见代码注释


参考代码:

/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 * 二维数组转稀疏数组、稀疏数组还原二维数组的实现
 */
public class SparseArray {
    public static void main(String[] args) {
        //先创建原始二维数组
        int[][] originalArray = new int[10][10];
        originalArray[0][4] = 1;
        originalArray[0][8] = 1;
        originalArray[1][5] = 1;
        originalArray[1][7] = 1;
        originalArray[4][8] = 1;
        originalArray[5][5] = 1;
        originalArray[7][2] = 1;
        originalArray[8][7] = 1;
        //输出原始的二维数组
        System.out.println("原始的二维数组:");
        for (int[] row: originalArray) {
            for (int data : row) {
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }
        //将二维数组转成稀疏数组
        //1.遍历二维数组,得到非0的有效数据的个数
        int amount = 0;
        for (int i = 0; i < originalArray.length; i++) {
            for (int j = 0; j < originalArray[i].length; j++) {
                if (originalArray[i][j] != 0){
                    amount++;
                }
            }
        }
        System.out.println("amount = " + amount);
        //2.创建对应的稀疏数组 sparseArray[amount+1][3], 并初始化稀疏数组第一行的数据
        //第一行第一列: 原数组的行数   第一行第二列: 原数组的列数  第一行第三列: 原数组的有效数据个数
        int[][] sparseArray = new int[amount + 1][3];
        sparseArray[0][0] = 10;
        sparseArray[0][1] = 10;
        sparseArray[0][2] = amount;
        //3.遍历二维数组,将非0值存储进稀疏数组
        int count = 0; //用于记录是第几个非零数据
        for (int i = 0; i < originalArray.length; i++) {
            for (int j = 0; j < originalArray[i].length; j++) {
                if (originalArray[i][j] != 0){
                    count++;
                    sparseArray[count][0] = i; //记录所在行
                    sparseArray[count][1] = j; //记录所在列
                    sparseArray[count][2] = originalArray[i][j]; //记录值
                }
            }
        }
        //输出稀疏数组
        System.out.println("稀疏数组:");
        for (int i = 0; i < sparseArray.length; i++) {
                System.out.printf("%d\t%d\t%d\n", sparseArray[i][0], sparseArray[i][1], sparseArray[i][2]);
        }
        //将稀疏数组恢复成为二维数组
        //1.根据稀疏数组的第一行初始化二维数组
        int[][] recoveredArray = new int[sparseArray[0][0]][sparseArray[0][1]];
        //2.读取稀疏数组的后面行数据,赋值给原始二维数组
        for (int i = 1; i < sparseArray.length; i++) {
            recoveredArray[sparseArray[i][0]][sparseArray[i][1]] = sparseArray[i][2];
        }
        //输出二维数组
        System.out.println("恢复后的二维数组:");
        for (int[] row: recoveredArray) {
            for (int data : row) {
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }
    }
}

运行结果

原始的二维数组:
0 0 0 0 1 0 0 0 1 0 
0 0 0 0 0 1 0 1 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 1 0 
0 0 0 0 0 1 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 1 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 1 0 0 
0 0 0 0 0 0 0 0 0 0 
amount = 8
稀疏数组:
10  10  8
0 4 1
0 8 1
1 5 1
1 7 1
4 8 1
5 5 1
7 2 1
8 7 1
恢复后的二维数组:
0 0 0 0 1 0 0 0 1 0 
0 0 0 0 0 1 0 1 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 1 0 
0 0 0 0 0 1 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 1 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 1 0 0 
0 0 0 0 0 0 0 0 0 0 

比对结果如下:


经过比较,恢复后的二维数组与原二维数组保持一致!

分析可知:原二维数组需要的空间为:10 * 10 *(int),而稀疏数组只需要 9 * 3 * (int),相对节省了73(int)的空间!

相关文章
|
6月前
|
人工智能 算法 Java
Java与AI驱动区块链:构建智能合约与去中心化AI应用
区块链技术和人工智能的融合正在开创去中心化智能应用的新纪元。本文深入探讨如何使用Java构建AI驱动的区块链应用,涵盖智能合约开发、去中心化AI模型训练与推理、数据隐私保护以及通证经济激励等核心主题。我们将完整展示从区块链基础集成、智能合约编写、AI模型上链到去中心化应用(DApp)开发的全流程,为构建下一代可信、透明的智能去中心化系统提供完整技术方案。
427 3
|
8月前
|
存储 数据采集 搜索推荐
Java 大视界 -- Java 大数据在智慧文旅旅游景区游客情感分析与服务改进中的应用实践(226)
本篇文章探讨了 Java 大数据在智慧文旅景区中的创新应用,重点分析了如何通过数据采集、情感分析与可视化等技术,挖掘游客情感需求,进而优化景区服务。文章结合实际案例,展示了 Java 在数据处理与智能推荐等方面的强大能力,为文旅行业的智慧化升级提供了可行路径。
Java 大视界 -- Java 大数据在智慧文旅旅游景区游客情感分析与服务改进中的应用实践(226)
|
8月前
|
机器学习/深度学习 数据采集 数据可视化
Java 大视界 -- 基于 Java 的大数据可视化在城市空气质量监测与污染溯源中的应用(216)
本文探讨Java大数据可视化在城市空气质量监测与污染溯源中的创新应用,结合多源数据采集、实时分析与GIS技术,助力环保决策,提升城市空气质量管理水平。
Java 大视界 -- 基于 Java 的大数据可视化在城市空气质量监测与污染溯源中的应用(216)
|
8月前
|
存储 缓存 Java
Java数组全解析:一维、多维与内存模型
本文深入解析Java数组的内存布局与操作技巧,涵盖一维及多维数组的声明、初始化、内存模型,以及数组常见陷阱和性能优化。通过图文结合的方式帮助开发者彻底理解数组本质,并提供Arrays工具类的实用方法与面试高频问题解析,助你掌握数组核心知识,避免常见错误。
|
8月前
|
存储 监控 数据可视化
Java 大视界 -- 基于 Java 的大数据可视化在企业生产运营监控与决策支持中的应用(228)
本文探讨了基于 Java 的大数据可视化技术在企业生产运营监控与决策支持中的关键应用。面对数据爆炸、信息孤岛和实时性不足等挑战,Java 通过高效数据采集、清洗与可视化引擎,助力企业构建实时监控与智能决策系统,显著提升运营效率与竞争力。
|
8月前
|
Java 大数据 数据处理
Java 大视界 -- 基于 Java 的大数据实时数据处理在工业互联网设备协同制造中的应用与挑战(222)
本文探讨了基于 Java 的大数据实时数据处理在工业互联网设备协同制造中的应用与挑战。文章分析了传统制造模式的局限性,介绍了工业互联网带来的机遇,并结合实际案例展示了 Java 在多源数据采集、实时处理及设备协同优化中的关键技术应用。同时,也深入讨论了数据安全、技术架构等挑战及应对策略。
|
8月前
|
数据采集 搜索推荐 Java
Java 大视界 -- Java 大数据在智能教育虚拟学习环境构建与用户体验优化中的应用(221)
本文探讨 Java 大数据在智能教育虚拟学习环境中的应用,涵盖多源数据采集、个性化推荐、实时互动优化等核心技术,结合实际案例分析其在提升学习体验与教学质量中的成效,并展望未来发展方向与技术挑战。
|
7月前
|
消息中间件 缓存 NoSQL
Redis各类数据结构详细介绍及其在Go语言Gin框架下实践应用
这只是利用Go语言和Gin框架与Redis交互最基础部分展示;根据具体业务需求可能需要更复杂查询、事务处理或订阅发布功能实现更多高级特性应用场景。
417 86
|
6月前
|
消息中间件 缓存 Java
Spring框架优化:提高Java应用的性能与适应性
以上方法均旨在综合考虑Java Spring 应该程序设计原则, 数据库交互, 编码实践和系统架构布局等多角度因素, 旨在达到高效稳定运转目标同时也易于未来扩展.
472 8
|
7月前
|
人工智能 Java API
Java与大模型集成实战:构建智能Java应用的新范式
随着大型语言模型(LLM)的API化,将其强大的自然语言处理能力集成到现有Java应用中已成为提升应用智能水平的关键路径。本文旨在为Java开发者提供一份实用的集成指南。我们将深入探讨如何使用Spring Boot 3框架,通过HTTP客户端与OpenAI GPT(或兼容API)进行高效、安全的交互。内容涵盖项目依赖配置、异步非阻塞的API调用、请求与响应的结构化处理、异常管理以及一些面向生产环境的最佳实践,并附带完整的代码示例,助您快速将AI能力融入Java生态。
1177 12
下一篇
开通oss服务