图解Java数据结构之稀疏数组

简介: 图解Java数据结构之稀疏数组

在编程中,算法的重要性不言而喻,没有算法的程序是没有灵魂的。可见算法的重要性。
然而,在学习算法之前我们需要掌握数据结构,数据结构是算法的基础。
我在大学的时候,学校里的数据结构是用C语言教的,因为对C语言也不是很了解,所以掌握得不是特别好,在网上找的一些学习资料里也基本都是用C语言来进行数据结构的教学。
那么,从本篇文章开始,我将用Java语言来介绍数据结构,当然,数据结构过后就是算法。

线性结构和非线性结构
  1. 线性结构
    线性结构作为最常用的数据结构,其特点是数据元素之间存在一对一的线性关系;
    线性结构有两种不同的存储结构,即顺序存储结构和链式存储结构。顺序存储的线性表称为顺序表,顺序表中存储的元素是连续的;
    链式存储的线性表称为链表,链表中存储的元素不一定是连续的,元素节点中存放数据元素以及相邻元素的地址信息;
    线性结构常见的有:数组、队列、链表和栈
  2. 非线性结构
    非线性结构包括:二维数组、多维数组、广义表、树结构、图结构
稀疏数组

对数据结构有了一个初步的认识之后,我们开始对一些具体的数据结构进行详细的分析。
我们来看一个实际的需求:
这是一个五子棋的程序,有存盘退出和续上盘的功能,如下图,如何将下图的棋局进行保存呢?
在这里插入图片描述
那这个问题很简单,很多人可能会想到用二维数组来进行存储。
在这里插入图片描述
如上图,我们用0表示无子,1表示黑子,2表示蓝子,但是这个程序问题很大,因为该二维数组的很多值都是默认值0,因此记录了很多没有意义的数据,那么这个时候我们就可以使用稀疏数组来对该二维数组进行一个压缩。
那么稀疏数组到底是什么呢?
当一个数组中大部分元素是0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。
稀疏数组的处理方法是:

  1. 记录数组一共有几行几列,有多少个不同的值
  2. 把具有不同值的元素的行列以及值记录在一个小规模的数组中,从而缩小程序的规模

那么了解了稀疏数组的概念后,我们通过稀疏数组来改进一下五子棋程序。
在这里插入图片描述
经过稀疏数组的压缩之后,原数组从原来的11行11列变为了三行三列。
该稀疏数组的第一行记录的是原数组的行数和列数以及元素个数。
接下来的每一行记录的是有效元素的位置和值,例如第二行记录的是原数组中位于1,2位置上的元素1;第三行记录的是原数组中位于2,3位置上的元素2。
综上所述,二维数组转稀疏数组的思路:

  1. 遍历原始的二维数组,得到要保存的有效元素个数
  2. 根据有效元素个数创建稀疏数组sparseArr
  3. 将二维数组的有效数据存入稀疏数组即可

稀疏数组转原始二维数组的思路:

  1. 先读取稀疏数组的第一行,根据第一行的数据创建原始二维数组
  2. 读取稀疏数组后几行的数据,并赋给原始的二维数组即可

关于实现思路已经分析完毕,接下来用代码实现。
将二维数组转稀疏数组用代码实现如下:

public static void main(String[] args) {
   
        // 创建一个原始的二维数组(11行11列)
        // 0:表示没有棋子
        // 1:表示黑子
        // 2:表示蓝子
        int chessArr1[][] = new int[11][11];
        chessArr1[1][2] = 1;
        chessArr1[2][3] = 2;

        System.out.println("原始的二维数组:");

        for (int[] row : chessArr1) {
   
            for (Integer value : row) {
   
                System.out.printf("%d\t", value);
            }
            System.out.println();
        }

        // 将二维数组转稀疏数组
        // 先遍历二维数组,得到非0的元素个数
        int sum = 0;
        for (int i = 0; i < chessArr1.length; i++) {
   
            for (int j = 0; j < chessArr1[i].length; j++) {
   
                if (chessArr1[i][j] != 0) {
   
                    sum++;
                }
            }
        }

        // 创建对应的稀疏数组
        int sparseArr[][] = new int[sum + 1][3];
        // 给稀疏数组赋值
        // 稀疏数组第一行存的是原始数组的行数、列数和有效元素个数
        sparseArr[0][0] = chessArr1.length;
        sparseArr[0][1] = chessArr1[0].length;
        sparseArr[0][2] = sum;

        // 遍历二维数组,将非0的值存入到稀疏数组中
        int count = 0; // 用于记录是第几个非0数据
        for (int i = 0; i < chessArr1.length; i++) {
   
            for (int j = 0; j < chessArr1[i].length; j++) {
   
                if (chessArr1[i][j] != 0) {
   
                    count++;
                    sparseArr[count][0] = i; // 存放元素位置
                    sparseArr[count][1] = j; // 存放元素位置
                    sparseArr[count][2] = chessArr1[i][j];// 存放元素值
                }
            }
        }

        //遍历稀疏数组
        System.out.println();
        System.out.println("稀疏数组:");
        for (int[] row : sparseArr) {
   
            for (Integer value : row) {
   
                System.out.printf("%d\t", value);
            }
            System.out.println();
        }
    }

运行结果如下:

原始的二维数组:
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    2    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    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    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    0    0    0    0    0    

稀疏数组:
11    11    2    
1    2    1    
2    3    2

这样,我们就成功地将二维数组转为了稀疏数组。

那么用代码如何将稀疏数组转为二维数组呢?

        // 将稀疏数组转为二维数组
        // 先读取稀疏数组的第一行,根据第一行的数据创建原始数组
        int chessArr2[][] = new int[sparseArr[0][0]][sparseArr[0][1]];

        // 读取稀疏数组后几行数据(从第二行开始读取),并赋给原始数组
        for (int i = 1; i < sparseArr.length; i++) {
   
            // 第一列和第二列组成元素位置,第三列为元素值
            chessArr2[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
        }

        // 遍历恢复后的二维数组
        System.out.println();
        System.out.println("恢复后的二维数组:");
        for (int[] row : chessArr2) {
   
            for (Integer value : row) {
   
                System.out.printf("%d\t", value);
            }
            System.out.println();
        }

思路缕清除之后,代码非常简单,看运行效果:

原始的二维数组:
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    2    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    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    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    0    0    0    0    0    

稀疏数组:
11    11    2    
1    2    1    
2    3    2    

恢复后的二维数组:
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    2    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    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    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    0    0    0    0    0

整体代码如下:

public static void main(String[] args) {
   
        // 创建一个原始的二维数组(11行11列)
        // 0:表示没有棋子
        // 1:表示黑子
        // 2:表示蓝子
        int chessArr1[][] = new int[11][11];
        chessArr1[1][2] = 1;
        chessArr1[2][3] = 2;

        System.out.println("原始的二维数组:");

        for (int[] row : chessArr1) {
   
            for (Integer value : row) {
   
                System.out.printf("%d\t", value);
            }
            System.out.println();
        }

        // 将二维数组转稀疏数组
        // 先遍历二维数组,得到非0的元素个数
        int sum = 0;
        for (int i = 0; i < chessArr1.length; i++) {
   
            for (int j = 0; j < chessArr1[i].length; j++) {
   
                if (chessArr1[i][j] != 0) {
   
                    sum++;
                }
            }
        }

        // 创建对应的稀疏数组
        int sparseArr[][] = new int[sum + 1][3];
        // 给稀疏数组赋值
        // 稀疏数组第一行存的是原始数组的行数、列数和有效元素个数
        sparseArr[0][0] = chessArr1.length;
        sparseArr[0][1] = chessArr1[0].length;
        sparseArr[0][2] = sum;

        // 遍历二维数组,将非0的值存入到稀疏数组中
        int count = 0; // 用于记录是第几个非0数据
        for (int i = 0; i < chessArr1.length; i++) {
   
            for (int j = 0; j < chessArr1[i].length; j++) {
   
                if (chessArr1[i][j] != 0) {
   
                    count++;
                    sparseArr[count][0] = i; // 存放元素位置
                    sparseArr[count][1] = j; // 存放元素位置
                    sparseArr[count][2] = chessArr1[i][j];// 存放元素值
                }
            }
        }

        // 遍历稀疏数组
        System.out.println();
        System.out.println("稀疏数组:");
        for (int[] row : sparseArr) {
   
            for (Integer value : row) {
   
                System.out.printf("%d\t", value);
            }
            System.out.println();
        }

        // 将稀疏数组转为二维数组
        // 先读取稀疏数组的第一行,根据第一行的数据创建原始数组
        int chessArr2[][] = new int[sparseArr[0][0]][sparseArr[0][1]];

        // 读取稀疏数组后几行数据(从第二行开始读取),并赋给原始数组
        for (int i = 1; i < sparseArr.length; i++) {
   
            // 第一列和第二列组成元素位置,第三列为元素值
            chessArr2[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
        }

        // 遍历恢复后的二维数组
        System.out.println();
        System.out.println("恢复后的二维数组:");
        for (int[] row : chessArr2) {
   
            for (Integer value : row) {
   
                System.out.printf("%d\t", value);
            }
            System.out.println();
        }
    }
相关文章
|
8天前
|
Java
java数据结构,双向链表的实现
文章介绍了双向链表的实现,包括数据结构定义、插入和删除操作的代码实现,以及双向链表的其他操作方法,并提供了完整的Java代码实现。
java数据结构,双向链表的实现
|
8天前
|
存储 Java
java数据结构,线性表链式存储(单链表)的实现
文章讲解了单链表的基本概念和Java实现,包括头指针、尾节点和节点结构。提供了实现代码,包括数据结构、接口定义和具体实现类。通过测试代码演示了单链表的基本操作,如添加、删除、更新和查找元素,并总结了操作的时间复杂度。
java数据结构,线性表链式存储(单链表)的实现
|
3天前
|
存储 安全 Java
Java数组(Arrays)详解
Java 中的数组是一种用于存储固定数量同类型数据的高效数据结构,支持连续内存存储和随机访问。数组可以声明并初始化,通过索引访问和修改元素,获取长度,使用循环遍历,支持多维形式,并可通过 `Arrays` 类的方法进行复制和排序。数组具有固定大小和类型安全的特点,但需注意越界等问题。灵活运用数组能显著提升编程效率。
|
3天前
|
存储 安全 Java
Java 数据结构类型总结
在 Java 中,常用的数据结构包括基础数据结构(如数组和字符串)、集合框架(如 Set、List 和 Map 接口的多种实现)、特殊数据结构(如栈、队列和双端队列)、链表(单链表、双链表和循环链表)以及图和树等。这些数据结构各有特点和适用场景,选择时需考虑性能、内存和操作需求。集合框架提供了丰富的接口和类,便于处理对象集合。
|
16天前
|
存储 Java 数据处理
Java 数组的高级用法
在 Java 中,数组不仅可以存储同类型的数据,还支持多种高级用法,如多维数组(常用于矩阵)、动态创建数组、克隆数组、使用 `java.util.Arrays` 进行排序和搜索、与集合相互转换、增强 for 循环遍历、匿名数组传递以及利用 `Arrays.equals()` 比较数组内容。这些技巧能提升代码的灵活性和可读性,适用于更复杂的数据处理场景。
|
17天前
|
存储 Java
java的Excel导出,数组与业务字典匹配并去掉最后一个逗号
java的Excel导出,数组与业务字典匹配并去掉最后一个逗号
35 2
|
8天前
|
存储 Java
java数据结构,线性表顺序存储(数组)的实现
文章介绍了Java中线性表顺序存储(数组)的实现。线性表是数据结构的一种,它使用数组来实现。文章详细描述了线性表的基本操作,如增加、查找、删除、修改元素,以及其他操作如遍历、清空、求长度等。同时,提供了完整的Java代码实现,包括MyList接口和MyLinearList实现类。通过main函数的测试代码,展示了如何使用这些方法操作线性表。
|
2月前
|
Java
Java数组的应用场景
Java数组的应用场景
29 1
|
2月前
|
存储 机器学习/深度学习 Java
Java数组
Java数组
27 1
|
2月前
|
存储 开发者 C#
WPF与邮件发送:教你如何在Windows Presentation Foundation应用中无缝集成电子邮件功能——从界面设计到代码实现,全面解析邮件发送的每一个细节密武器!
【8月更文挑战第31天】本文探讨了如何在Windows Presentation Foundation(WPF)应用中集成电子邮件发送功能,详细介绍了从创建WPF项目到设计用户界面的全过程,并通过具体示例代码展示了如何使用`System.Net.Mail`命名空间中的`SmtpClient`和`MailMessage`类来实现邮件发送逻辑。文章还强调了安全性和错误处理的重要性,提供了实用的异常捕获代码片段,旨在帮助WPF开发者更好地掌握邮件发送技术,提升应用程序的功能性与用户体验。
36 0
下一篇
无影云桌面