数据结构之稀疏数组

111 阅读7分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第21天,点击查看活动详情

介绍

当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。

稀疏数组的处理方法是:

1)记录数组一共有几行几列,有多少个不同的值

2)把具有不同值的元素的行列及值记录在一个小规模的数组中,从而缩小程序的规模

二维数组

索引0123456
0000220015
1011000170
2000-6000
300000390
491000000
500280000

稀疏数组

行(row)列(col)值(value)
[0]678
[1]0322
[2]0615
[3]1111
[4]11517
[5]23-6
[6]3539
[7]4091
[8]5228

第一行记录原二维数组的大小,和拥有值的个数

应用实例

使用稀疏数组,来保留类似前面的二维数组(棋盘、地图等等),把稀疏数组存盘,并且可以从新恢复原来的二维数组数。(棋盘保存复盘)

image-20200823211041879

创建二维数组

根据上图所示创建二维数组11*11

image-20200823211554494

//原始二维数组11*11
int chessArr1[][] = new int[11][11];
//1代表黑子,2代表蓝子
chessArr1[1][2] = 1;
chessArr1[2][3] = 2;
//遍历二维数组
System.out.println("原始二维数组");
for (int[] ints : chessArr1) {
    for (int anInt : ints) {
        System.out.print(anInt + "\t");
    }
    System.out.println();
}

image-20200823211712137

二维数组存放原始棋盘成功!

获取稀疏数组

遍历原始数组

遍历原始数组得到二维数组也就是棋盘中当前的棋子个数有多少(值不为0的个数),用变量count表示

image-20200823212111079

//将二维数组转换为稀疏数组
//1.先遍历二维数组,得到非0的数据个数。
int count = 0;
for (int i = 0; i < chessArr1.length; i++) {
    for (int j = 0; j < chessArr1.length; j++) {
        //不为零代表有棋子
        if (chessArr1[i][j] != 0) count++;
    }
}

创建稀疏数组

根据遍历原始二维数组获取到当前棋子的个数count,创建稀疏数组,行为count+1(有一行记录原始二维数组的行,列数,值数),列为3(行,列,值)。

image-20200823212528267

//2.创建对应的稀疏数组,存放的数据个数+1行,列为固定3列即可,分别记录row,column,value
int[][] sparseArr = new int[count + 1][3];
//给稀疏数组赋值
sparseArr[0][0] = chessArr1.length;
sparseArr[0][1] = chessArr1[0].length;
sparseArr[0][2] = count;

第一行记录原始二维数组的行,列数,值数

  • sparseArr[0][0] = chessArr1.length;行数
  • sparseArr[0][1] = chessArr1[0].length;列数
  • sparseArr[0][2] = count;值数

稀疏数组赋值

遍历原始二维数组给稀疏数组赋值,当原始二维数组值不为0时,代表此位置有值,将其行列数和值存放到稀疏数组中。

image-20200823213521559

//2.给稀疏数组赋值
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++;
            sparseArr[sum][0] = i;//存放原数组中row
            sparseArr[sum][1] = j;//存放原数组中column
            sparseArr[sum][2] = chessArr1[i][j];//存放原数组中该位置的value值
        }
    }
}

//遍历稀疏数组
System.out.println();
System.out.println("稀疏数组");
for (int i = 0; i < sparseArr.length; i++) {
    for (int j = 0; j < sparseArr.length; j++) {
        System.out.print(sparseArr[i][j] + "\t");
    }
    System.out.println();
}

sum++放在最前头,是初始值为0,而我们稀疏数组0行中的值已经存放了原始数组的信息,从1行中开始存放棋子

sparseArr[sum][0] = i;//存放原数组中row sparseArr[sum][1] = j;//存放原数组中column sparseArr[sum][2] = chessArr1[i][j];//存放原数组中该位置的value值

image-20200823213907811

还原原始数组

创建二维数组

得到稀疏数组中第0行中存放有关原始二维数组的数据,row,column,value。通过rowcolumn创建出还原的二维数组。(这里的value值可以为0,我没用到这个存放值)

image-20200823214845530

//将稀疏数组转换为二维数组
//1.得到稀疏数组中的第一行存放有关二维数组的值
int row = sparseArr[0][0];//原二维数组的行
int column = sparseArr[0][1];//原二维数组的列
int value = sparseArr[0][2];//原二维数组的存放的值个数

遍历稀疏数组

从(0开始)第1行开始遍历稀疏数组,得到每行中存放的row,column,value。再根据row和column即可代入新的二维数组中定位到位置,将value赋值给该点即可。

image-20200823215106565

row = sparseArr[i][0]; column = sparseArr[i][1]; value = sparseArr[i][2]; chessArr2[row][column] = value;

//还原而成的二维数组
int[][] chessArr2 = new int[row][column];
//遍历稀疏数组存放的值,将其按对应顺序存放到二维数组中。没赋值的初始化默认为0
for (int i = 1; i <sparseArr.length ; i++) {
    for (int j = 1; j <sparseArr[i].length ; j++) {
        //遍历稀疏数组存放的值,将其按对应顺序存放到二维数组中
        row = sparseArr[i][0];
        column = sparseArr[i][1];
        value = sparseArr[i][2];
        chessArr2[row][column] = value;
    }
}

//遍历根据稀疏数组转换的二维数组
System.out.println();
System.out.println("新二维数组");
for (int[] ints : chessArr2) {
    for (int anInt : ints) {
        System.out.print(anInt+"\t");
    }
    System.out.println();
}

image-20200823215643900

存放稀疏数组

写入文件

在通过遍历原始二维数组创建稀疏数组之后,通过io流将稀疏数组写到chess.data文件

image-20200824095214889

FileOutputStream fileOutputStream = null;

try {
    fileOutputStream = new FileOutputStream(new File("chess.data"));
    //遍历稀疏数组
    System.out.println();
    System.out.println("稀疏数组");
    for (int i = 0; i < sparseArr.length; i++) {
        for (int j = 0; j < sparseArr[i].length; j++) {
            fileOutputStream.write(sparseArr[i][j]);
            System.out.print(sparseArr[i][j] + "\t");
        }
        System.out.println();
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (fileOutputStream != null) {
        try {
            fileOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

读取文件

通过读取先前写入到硬盘中chess.data文件,创建出稀疏数组,从而通过稀疏数组还原原始二维数组。

image-20200824095600549

FileInputStream fileInputStream = null;
int sparseArr2[][] = null;
try {
    //将稀疏数组从磁盘的文件中读取出来
    fileInputStream = new FileInputStream(new File("chess.data"));
    sparseArr2 = new int[count + 1][3];
    for (int i = 0; i < sparseArr2.length; i++) {
        for (int j = 0; j < sparseArr2[i].length; j++) {
            sparseArr2[i][j] = fileInputStream.read();
        }

    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (fileInputStream != null) {
        try {
            fileInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

image-20200824095659616

import java.io.*;

public class sparseArrayIO {

    public static void main(String[] args) {
        //原始二维数组11*11
        int chessArr1[][] = new int[11][11];
        //1代表黑子,2代表蓝子
        chessArr1[1][2] = 1;
        chessArr1[2][3] = 2;
        //遍历二维数组
        System.out.println("原始二维数组");
        for (int[] ints : chessArr1) {
            for (int anInt : ints) {
                System.out.print(anInt + "\t");
            }
            System.out.println();
        }

        //将二维数组转换为稀疏数组
        //1.先遍历二维数组,得到非0的数据个数。
        int count = 0;
        for (int i = 0; i < chessArr1.length; i++) {
            for (int j = 0; j < chessArr1.length; j++) {
                //不为零代表有棋子
                if (chessArr1[i][j] != 0) count++;
            }
        }
        //2.创建对应的稀疏数组,存放的数据个数+1行,列为固定3列即可,分别记录row,column,value
        int[][] sparseArr = new int[count + 1][3];
        //给稀疏数组赋值
        sparseArr[0][0] = chessArr1.length;
        sparseArr[0][1] = chessArr1[0].length;
        sparseArr[0][2] = count;

        //2.给稀疏数组赋值
        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++;
                    sparseArr[sum][0] = i;//存放原数组中row
                    sparseArr[sum][1] = j;//存放原数组中column
                    sparseArr[sum][2] = chessArr1[i][j];//存放原数组中该位置的value值
                }
            }
        }

        FileOutputStream fileOutputStream = null;

        try {
            fileOutputStream = new FileOutputStream(new File("chess.data"));
            //遍历稀疏数组
            System.out.println();
            System.out.println("稀疏数组");
            for (int i = 0; i < sparseArr.length; i++) {
                for (int j = 0; j < sparseArr[i].length; j++) {
                    fileOutputStream.write(sparseArr[i][j]);
                    System.out.print(sparseArr[i][j] + "\t");
                }
                System.out.println();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        FileInputStream fileInputStream = null;
        int sparseArr2[][] = null;
        try {
            //将稀疏数组从磁盘的文件中读取出来
            fileInputStream = new FileInputStream(new File("chess.data"));
            sparseArr2 = new int[count + 1][3];
            for (int i = 0; i < sparseArr2.length; i++) {
                for (int j = 0; j < sparseArr2[i].length; j++) {
                    sparseArr2[i][j] = fileInputStream.read();
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        System.out.println();
        System.out.println("从磁盘中读取的稀疏数组");
        for (int[] is : sparseArr2) {
            for (int i : is) {
                System.out.print(i + "\t");

            }
            System.out.println();
        }
        System.out.println();


        //将稀疏数组转换为二维数组
        //1.得到稀疏数组中的第一行存放有关二维数组的值
        int row = sparseArr[0][0];//原二维数组的行
        int column = sparseArr[0][1];//原二维数组的列
        int value = sparseArr[0][2];//原二维数组的存放的值个数

        int[][] chessArr2 = new int[row][column];
        //遍历稀疏数组存放的值,将其按对应顺序存放到二维数组中。没赋值的初始化默认为0
        for (int i = 1; i < sparseArr.length; i++) {
            for (int j = 1; j < sparseArr[i].length; j++) {
                //遍历稀疏数组存放的值,将其按对应顺序存放到二维数组中
                row = sparseArr[i][0];
                column = sparseArr[i][1];
                value = sparseArr[i][2];
                chessArr2[row][column] = value;
            }
        }

        //遍历根据稀疏数组转换的二维数组
        System.out.println();
        System.out.println("新二维数组");
        for (int[] ints : chessArr2) {
            for (int anInt : ints) {
                System.out.print(anInt + "\t");
            }
            System.out.println();
        }
    }
}