• 数据结构与算法稀疏数组详解


    1.背景

    1.1.假设让你开发一个五子棋,你会如何存储棋盘

    1.2.数组保存棋盘

    假设:

    0-白表示空白位置(即没有走过的位置)

    1-表示白棋

    2-表示黑棋

    如果是数组保存棋盘,你会发现很多数据都是零,如下图:

     

    上面,我们通过二维数组的方法,将棋盘数据保存在了一个二维数组中,整个数组我们用了 16 × 16(共 256)个点来保存数据,其中有 254 个点都是空的。

    实际来说,我们只需要将有价值的黑白子保存起来即可,因为只要我们知道黑白子数据,以及棋盘的大小,那么这 254 个空点是可以不用进行保存的。

    把这样没有价值的数据起来,不但会浪费存储空间的大小,如果写入到磁盘中,还会增大 IO 的读写量,影响性能,这就是用普通二维数组来表示棋盘数据的不足之处。

    那么,针对以上情况,我们该如何将我们的数据格式进行优化呢?于是就引出了我们接下来的稀疏数组的概念。

    1.3.稀疏数组

    稀疏数组本质上也是数组,只是存储数据时只存在元数据的规模和数据两部分

    稀疏数组

    列是固定的3列,分别为原数组的(行,列,值)

    行,第一行表示数据规模,即表示原来的数组(有多少行,有多少列,有多少个值)

    如下图所示:

    2.普通数组与稀疏数组互转

    package com.ldp.course.structure.demo02sparsearray;
    
    import com.ldp.course.common.MyArrayUtil;
    import org.junit.Test;
    
    import java.util.LinkedList;
    
    /**
     * @create 06/29 7:23
     * @description <P>
     * 数据结构之稀疏数组
     * 课件:https://www.cnblogs.com/newAndHui/p/16421898.html
     * </P>
     */
    public class Test01 {
        /**
         * 二维数组保存棋盘演示
         */
        @Test
        public void test01() {
            // 建立一个16*16的棋盘
            int[][] array = new int[16][16];
            // 设置2个棋子的位置
            array[8][7] = 1;
            array[9][8] = 2;
            System.out.println("显示棋盘");
            MyArrayUtil.showArray(array);
            System.out.println("二维数组转为稀疏数组");
            int[][] sparse = arrayToSparse(array);
            MyArrayUtil.showArray(sparse);
            System.out.println("稀疏数组转二维数组");
            int[][] array2 = sparseToArray(sparse);
            MyArrayUtil.showArray(array2);
        }
    
        /**
         * 1.确定稀疏数组的行:遍历数组得到数组的值个数n,n+1作为稀疏数组的行
         * 2.稀疏数组的列为固定值3
         * 二维数组转为稀疏数组
         *
         * @param array 二维数组
         * @return 稀疏数组
         */
        public int[][] arrayToSparse(int[][] array) {
            // 确定数组有效值个数
            int row = 0, col = 0, n = 0;
            // 记录二维数组每个值的行列值,格式(行,列,值)
            LinkedList<String> arrayStrList = new LinkedList<>();
            for (int[] ints : array) {
                row++;
                col = 0;
                for (int anInt : ints) {
                    col++;
                    if (anInt != 0) {
                        n++;
                        // 行,列,值
                        String str = "" + (row - 1) + "," + (col - 1) + "," + anInt;
                        arrayStrList.addLast(str);
                    }
                }
            }
            // 第一行是 行,列,个数
            String strFirst = "" + row + "," + col + "," + n;
            arrayStrList.addFirst(strFirst);
            // 创建稀疏数组对象
            int[][] sparseArray = new int[n + 1][3];
            for (int i = 0; i < (n + 1); i++) {
                String s = arrayStrList.get(i);
                // System.out.println(s);
                String[] rowStr = s.split(",");
                sparseArray[i][0] = Integer.valueOf(rowStr[0]);
                sparseArray[i][1] = Integer.valueOf(rowStr[1]);
                sparseArray[i][2] = Integer.valueOf(rowStr[2]);
            }
            return sparseArray;
        }
    
        /**
         * 稀疏数组转二维数组
         *
         * @param sparseArray 稀疏数组
         * @return 二维数组
         */
        public int[][] sparseToArray(int[][] sparseArray) {
            int row = sparseArray[0][0];
            int col = sparseArray[0][1];
            int n = sparseArray[0][2];
            int[][] array = new int[row][col];
            // 注意这里循环i<n+1,原因是第一行是数据规模,顺然只有2个值,但是实际是3行,如下
            // [16, 16, 2]
            // [8, 7, 1]
            //[9, 8, 2]
            for (int i = 1; i < n + 1; i++) {
                int row_ = sparseArray[i][0];
                int col_ = sparseArray[i][1];
                int value_ = sparseArray[i][2];
                array[row_][col_] = value_;
            }
            return array;
        }
    }

    4.总结

    在存储数组数据的时候,如果存在许多默认值的数据,可以考虑使用稀疏数组来进行存储,

    这样数据相对来说就会瘦小很多,不但可以节省磁盘空间,还可以优化磁盘读写时性能。

    完美

  • 相关阅读:
    Catalyst揭秘 Day6 Physical plan解析
    Spark小课堂Week6 启动日志详解
    Spark小课堂Week5 Scala初探
    java并发再次积累
    java 2017/6/26杂记
    comparator接口与Comparable接口的区别
    ArrayList、Vector、HashMap、HashSet的默认初始容量、加载因子、扩容增量
    Java的快速失败和安全失败
    关于URL和http协议,http消息格式
    java中hashSet原理
  • 原文地址:https://www.cnblogs.com/newAndHui/p/16421898.html
Copyright © 2020-2023  润新知