【再临数据结构】Day1. 稀疏数组

news2024/9/21 22:35:14

前言

  这不单单是稀疏数组的开始,也是我重学数据结构的开始。因此,在开始说稀疏数组的具体内容之前,我想先说一下作为一个有着十余年“学龄”的学生,所一直沿用的一个学习方法:3W法。我认为,只有掌握了正确的学习方法,才能真正的达到“事半功倍”的境界。

  何为3W?其实就是3问:What?Why?How?

简单解释一下:

 1.What:界定问题,首先要搞清楚这个问题是什么。
    若连题都读不懂,就不必说如何解题了。

 2.Why:分析问题,要分析问题的本质和原因。
    在读懂题意的前提下,知道它考察的方向是什么,这样后续才能顺着这个方向去解题。

 3.How:解决问题,通过目标导向思维解决问题。
    经过前两问的思考,想必你已经透过题目明白了这道题真正考察的是什么,那么就要考虑如何去处理、解决掉它。

1.What?

  好,我们开始稀疏数组的具体内容。在了解为什么要学习它和怎样使用之前,我们要先了解稀疏数组是什么。
  我们通过具体的应用场景来了解它,比如说,你用编程语言需要写一个简单的五子棋小游戏,它需要能够正常玩,并且有存盘和读取功能。
此时你能想到的问题就是:

  1. 如何绘制棋盘并存储棋盘上落子的坐标信息。
  2. 如何实现存盘和读盘的功能。

  首先来思考第一个问题:总所周知,棋盘由行和列组成。那么,你很自然的想到了数学中的坐标系,将其落子点看做一组横纵坐标。因此你打算使用二维数组这一数据结构来模拟棋盘。用0代表没有落子,1代表落黑子,2代表落白字。
  好,问题轻松写意地解决了。你开始写代码,作为一个有着程序员精神的人,你很快地通过百度解决了第二个问题。但你的程序员灵魂并不甘于止步于此,又想琢磨如何优化,此时迎来了一个新的问题:若一个11*11大小的棋盘,只落了两个子。此时需要存盘,如何才能尽可能多的节省存储空间?
  很显然,若使用0来代表未落子的交点,那么这个二维数组中就有着许许多多的“无效数据”。只有当黑子 / 白子落在这个交点上,它才是“有效数据”。此时,稀疏数组就出现在你的面前了。

2.Why?

  为什么要使用稀疏数组而不是别的数据结构?为什么它能实现对二维数组的压缩?
  别急,一图以蔽之。
在这里插入图片描述

稀疏数组的处理方式:

1、分别记录原数组的行个数、列个数、有多少个“有效数据”。【第一行】
2、将不同有效数据的元素的行、列、值信息记录在一个小规模的数组中,从而缩小程序的规模。【其余行】

稀疏数组很简单,上面两点足以概括。

具体思路

在这里插入图片描述

二维数组转稀疏数组

1.遍历原始的二维数组,得到有效数据的个数 sum
2根据sum就可以创建稀疏数组 sparseArr int[sum+1][3]
注:此处之所以为[sum+1]的原因是第一列要存储原数组的大小及有效数的个数(sum)
3.将二维数组的有效数据数据存入到稀疏数组

稀疏数组转二维数组

1.先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组,比如上面的chessArr2= int[11][11]
⒉.在读取稀疏数组后几行的数据,并赋给原始的二维数组即可.
  以上过程再配合Java的IO操作(写入磁盘文件,文件读入内存)就可以实现类似下棋游戏过程中的“存盘”,“读取” 的操作。

3.How?

二维数组转稀疏数组

    //将二维数组压缩为稀疏数组
    public static int[][] toSparseArray(int[][] arr){
        //1.遍历二维数组,获取到二维数组中有效元素的个数
        int sum = 0;                    //有效元素个数

        //增强版双重for循环,实现遍历二维数组的操作
        for (int[] ints : arr) {
            for (int anInt : ints) {
                if (anInt != 0) {
                    sum++;
                }
            }
        }

        //2.根据sum的个数及稀疏数组的设定来建立一个原数组所对应的稀疏数组
        int[][] sparseArray = new int[sum+1][3];

        //3.根据原数组的情况为稀疏数组赋值
        //3.1第一行存储原二维数组的信息,首先填写它的数据
        sparseArray[0][0] = arr.length;     //原二维数组行长度
        sparseArray[0][1] = arr[0].length;  //原二维数组列长度
        sparseArray[0][2] = sum;            //有效数的个数

        //3.2其余行存储有效数在原二维数组中的行、列及数值
        int index = 0;

        for(int i=0; i<arr.length; i++){
            for (int j=0; j<arr[0].length; j++){
                if (arr[i][j] != 0){
                    index++;
                    sparseArray[index][0] = i;
                    sparseArray[index][1] = j;
                    sparseArray[index][2] = arr[i][j];
                }
            }
        }
        return sparseArray;
    }

稀疏数组还原为二维数组

    //将稀疏数组转换为原二维数组
    public static int[][] toErWei(int[][] arr){
        //1.新建一个二维数组,读取稀疏数组的第一行,根据第一行数据初始化二维数组
        int[][] erWei = new int[arr[0][0]][arr[0][1]];  //此时二维数组大小确定,内容全是0

        //2,读取稀疏数组后几行数据,并赋给初始化好的二维数组
        for (int i=1;i<arr.length;i++){  //i=1表示从稀疏数组的第二行开始读取
            //0存储行信息,1存储列信息,2存储值信息
            erWei[arr[i][0]][arr[i][1]]=arr[i][2];  //认真理解
        }
        return erWei;
    }

源码

public class sparseArray {
    public static void main(String[] args) {
        int[][] erWei = new int[11][11];
        for (int i=0; i<erWei.length-1; i++){
            for (int j=0; j<erWei[0].length-1; j++){
                erWei[i][j] = 0;
            }
        }
        //设定有效元素
        erWei[2][5] = 16;
        erWei[1][6] = 14;
        erWei[7][9] = 28;
        erWei[4][5] = 20;
        erWei[1][3] = 17;
        erWei[6][4] = 79;

        //输出原二维数组
        printArr(erWei);
        //转化为稀疏数组
        int[][] sparseArray = toSparseArray(erWei);
        printArr(sparseArray);

        //转化为二维数组
        int[][] ErWei = toErWei(sparseArray);
        printArr(ErWei);
    }
    //将二维数组压缩为稀疏数组
    public static int[][] toSparseArray(int[][] arr){
        //1.遍历二维数组,获取到二维数组中有效元素的个数
        int sum = 0;                    //有效元素个数

        //增强版双重for循环,实现遍历二维数组的操作
        for (int[] ints : arr) {
            for (int anInt : ints) {
                if (anInt != 0) {
                    sum++;
                }
            }
        }

        //2.根据sum的个数及稀疏数组的设定来建立一个原数组所对应的稀疏数组
        int[][] sparseArray = new int[sum+1][3];

        //3.根据原数组的情况为稀疏数组赋值
        //3.1第一行存储原二维数组的信息,首先填写它的数据
        sparseArray[0][0] = arr.length;     //原二维数组行长度
        sparseArray[0][1] = arr[0].length;  //原二维数组列长度
        sparseArray[0][2] = sum;            //有效数的个数

        //3.2其余行存储有效数在原二维数组中的行、列及数值
        int index = 0;

        for(int i=0; i<arr.length; i++){
            for (int j=0; j<arr[0].length; j++){
                if (arr[i][j] != 0){
                    index++;
                    sparseArray[index][0] = i;
                    sparseArray[index][1] = j;
                    sparseArray[index][2] = arr[i][j];
                }
            }
        }
        return sparseArray;
    }

    //将稀疏数组转换为原二维数组
    public static int[][] toErWei(int[][] arr){
        //1.新建一个二维数组,读取稀疏数组的第一行,根据第一行数据初始化二维数组
        int[][] erWei = new int[arr[0][0]][arr[0][1]];  //此时二维数组大小确定,内容全是0

        //2,读取稀疏数组后几行数据,并赋给初始化好的二维数组
        for (int i=1;i<arr.length;i++){  //i=1表示从稀疏数组的第二行开始读取
            //0存储行信息,1存储列信息,2存储值信息
            erWei[arr[i][0]][arr[i][1]]=arr[i][2];  //认真理解
        }
        return erWei;
    }
    
    //输出数组信息
    public static void printArr(int[][] arr){
        for (int[] ints : arr){
            for (int anInt : ints) {
                System.out.print(anInt + " ");
            }
            System.out.println();
        }
        System.out.println("---------------------");
    }
}

运行结果如下:
在这里插入图片描述

在这里插入图片描述
  如上图所示,二维数组压缩为稀疏数组确实极大地节省了存储空间。同样可以通过稀疏数组在读盘时将其进行复原,达到预期需求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/377704.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

react的严格模式 和 解决react useEffect执行两次

useEffect执行两次 这个问题&#xff0c;主要是刚接触react的时候发的问题&#xff0c;当时也没总结。现在回过头来再总结一次&#xff01;&#xff01;&#xff01; 文章目录useEffect执行两次前言一、为什么useEffect执行两次1.React的严格模式&#xff08;模版创建项目&…

Hadoop综合案例 - 聊天软件数据

目录1、聊天软件数据分析案例需求2、基于Hive数仓实现需求开发2.1 建库2.2 建表2.3 加载数据2.4 ETL数据清洗2.5 需求指标统计---都很简单3、FineBI实现可视化报表3.1 FineBI介绍3.2 FineBI配置数据3.3 构建可视化报表1、聊天软件数据分析案例需求 MR速度慢—引入hive 背景&a…

深度剖析指针(中)——“C”

各位CSDN的uu们你们好呀&#xff0c;今天小雅兰的内容仍旧是深度剖析指针噢&#xff0c;在上一篇博客中&#xff0c;我已经写过了字符指针、数组指针、指针数组、数组传参和指针传参的知识点&#xff0c;那么这篇博客小雅兰会讲解一下函数指针、函数指针数组 、指向函数指针数组…

【Spark分布式内存计算框架——Spark Streaming】8. Direct 方式集成底层原理 集成Kafka 0.10.x

Direct 方式集成底层原理 SparkStreaming集成Kafka采用Direct方式消费数据&#xff0c;如下三个方面优势&#xff1a; 第一、简单的并行度&#xff08;Simplified Parallelism&#xff09; 读取topics的总的分区数目 每批次RDD中分区数目&#xff1b;topic中每个分区数据 被…

布局三八女王节,巧借小红书数据分析工具成功引爆618

对于小红书“她”经济来说&#xff0c;没有比三八节更好的阵地了。伴随三八女王节逐渐临近&#xff0c;各大品牌蓄势待发&#xff0c;这场开春后第一个S级大促活动&#xff0c;看看品牌方们可以做什么&#xff1f; 洞察流量&#xff0c;把握节点营销时机 搜索小红书2023年的三…

学员作品|微博“绿洲”APP产品分析

一产品架构1. 产品功能架构图绿洲的主要功能模块可以拆分为六部分&#xff1a;首页、发现、发布动态、个人中心、水滴、消息。整体功能架构图如下&#xff1a;2. 用户使用路径图用于浏览动态&#xff1a;用于发布动态&#xff1a;新用户引导路径&#xff1a;二市场分析1. 产品定…

【Linux】Linux中gcc/g++的使用

本期主题&#xff1a;程序的编译过程和gcc/g的使用博客主页&#xff1a;小峰同学分享小编的在Linux中学习到的知识和遇到的问题小编的能力有限&#xff0c;出现错误希望大家不吝赐&#x1f341; 1.背景知识 预处理&#xff08;进行宏替换&#xff0c;去注释&#xff0c;头文件的…

索引、索引失效、索引的存储

文章目录1.索引种类2.创建索引注意点3.索引失效的情况4.为什么索引使用B树存储&#xff08;1&#xff09;如果使用数组来存储索引&#xff08;2&#xff09;如果使用二叉查找树来存储索引&#xff08;3&#xff09;如果使用平衡二叉查找树来存储索引&#xff08;4&#xff09;如…

同为(TOWE)防雷产品助力福建移动南平分公司防雷改造

01 公司简介中国移动通信集团福建有限公司南平分公司属于福建移动地级分公司&#xff0c;所属行业为电信、广播电视和卫星传输服务。现已建成覆盖范围广、业务品种多、通信质量高的综合通信网络&#xff0c;具备行业领先的经营管理制度。移动通信大楼的综合防雷及地接系统&…

第八节 构造器和this关键字、封装

构造器的作用 定义在类中的&#xff0c;可以用于初始化一个类的对象&#xff0c;并返回对象的地址。 构造器的注意事项 1.任何类定义出来&#xff0c;默认就自带了无参数构造器&#xff0c;写不写都有。 2.一旦定义了有参数构造器&#xff0c;那么无参数构造器就没有了&#xf…

互联网人看一看,这些神器你用过哪些?

很多小伙伴在剪辑视频的过程中经常可以看到一些语音素材&#xff0c;经常刷视频的小伙伴也可以看到很多视频中经常出现一些AI合成的声音或者音效&#xff0c;这些配音可以给视频增添很多亮点&#xff01;那么大家都是怎么将文字转语音的呢&#xff1f;今天给大家分享5款非常专业…

【Git】Git常用命令及练习—Git环境配置

目录 一、Git环境配置 1.1基本配置 1.2为常用指令配置别名&#xff08;可选&#xff09; 1.3 解决GitBash乱码问题 二、Git命令详细操作 1.获取本地仓库 2.基础操作命令及练习 基础操作练习 3.分支命令及练习 开发中分支使用原则与流程 分支练习 &#x1f49f; 创作不…

Ubuntu20.04安装Cuckoo

参考链接&#xff1a; &#xff08;1&#xff09;【主要参考】http://www.wityx.com/post/134851_1_1.html &#xff08;2&#xff09;【主要参考】在Ubuntu18.04上搭建Cuckoo Sandbox2.0.7 https://www.jianshu.com/p/4dd6373fa206 &#xff08;3&#xff09;与Cuckoo的斗智斗…

Kafka入门(五)

下面聊聊Kafka常用命令 1、Topic管理命令 以topic&#xff1a;test_1为例 1.1、创建topic ./bin/kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 3 --partitions 3 --topic test_1参数说明&#xff1a; –bootstrap-server&#xff1a;…

【论文笔记】Decoupling Representation and Classifier for Long-Tailed Recognition

这一篇其实并不是提出什么新的东西&#xff0c;而且是做了点类似综述的技术调用实验。省流&#xff1a;T-normalization最好用 摘要 现状&#xff1a;Existing solutions usually involve class-balancing strategies, e.g. by loss re-weighting, data re-sampling, or tran…

【操作方法】windows防火墙添加出入站规则方法

【操作方法】windows防火墙添加出入站规则方法说明一、入站规则1.打开防火墙&#xff0c;点击“高级设置”2.点击“入站规则”后点击“新建规则”3.例3.1选择“端口”3.2添加需要放通的端口3.3选择操作动作为“允许连接”3.4选择应用区域&#xff0c;此处我选择所有区域二、出站…

Linux: malloc()的指向指针发生指向偏移后,释放前需要将指针指向复原。

Linux: malloc()的指向指针发生指向偏移后&#xff0c;释放前需要将指针指向复原。 #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <time…

A Contextual-Bandit Approach to Personalized News Article Recommendation-论文学习

A Contextual-Bandit Approach to Personalized News Article Recommendation-论文学习 github地址&#xff1a;bandit-learning 摘要 该算法根据用户和文章的上下文信息依次选择文章为用户服务&#xff0c;同时根据用户点击反馈调整其文章选择策略&#xff0c;以最大化用户…

不是,到底有多少种图片懒加载方式?

一、也是我最开始了解到的 js方法&#xff0c;利用滚动事件&#xff0c;判断当时的图片位置是否在可视框内&#xff0c;然后进行渲染。 弊端&#xff1a;代码冗杂&#xff0c;你还要去监听页面的滚动事件&#xff0c;这本身就是一个不建议监听的事件&#xff0c;即便是我们做了…

Qt音视频开发18-不同视频打开无缝切换

一、前言 在轮询视频的时候&#xff0c;通常都是需要将之前的视频全部关闭&#xff0c;然后打开下一组视频&#xff0c;在这个切换的过程中&#xff0c;如果是按照常规的做法&#xff0c;比如先关闭再打开新的视频&#xff0c;肯定会出现空白黑屏之类的过度空白区间&#xff0…