数据结构的知识回顾
数据结构包括:线性数据结构+非线性数据结构
线性数据结构
1.线性结构是最常用的数据结构,特点:数据元素之间存在一对一的关系。
2.线性数据结构有两种不同的存储结构
1)顺序存储结构(顺序表)——存储元素(地址)是连续的
2)链式存储结构(链表)——链表的存储元素不一定连续,元素节点存放数据元素以及相邻元素的地址信息。
3.常见的线性结构包括
1)数组
2)队列
3)栈
4)链表
非线性数据结构
非线性结构包括
1)二维数组
2)多维数组
3)广义表
4)树结构
5)图
稀疏数组(二维)
介绍
当一个二维数组大部分元素为0或者是同一个元素时就可以用稀疏数组进行压缩
处理方式
1.稀疏数组的第一行记录原来的二维数组有几行几列,已经有效值的总数
2.其余行记录各个有效值的在原来二维数组的位置
举例:
原始的二维数组如下,可以看到很多0只有
第2行第3列是2
第3行第5列是1
这两个非0的元素
转化为稀疏数组如下
解释:
稀疏数组的第一行第一列记录原二维数组总共有多少行
稀疏数组的第一行第二列记录原二维数组总共有多少列
稀疏数组的第一行第三列记录原二维数组总共多少非0元素(有效值)
其余的行列都用于记录有效值在原二维数组的位置,比如有效值2在原来二维数组的表示为a[1][2],因此稀疏数组的第二行就表示为 1 (第2行) 2(第3列)2(值为2)
注意:数组是[0][0]表示第一行第一列,是从0开始数的,而我们平时说的第几行第几列都是从1开始数的,因此在程序数组中都要表示都要减1,即稀疏数组记录的位置为二维数组在程序中的位置
可以看到经过转换为稀疏数组的转换从原来的11x11=121个元素变成了3x3=9个元素。
应用实例
使用稀疏数组,保留类似棋盘地图等二维数组,用于保留上一局的棋盘情况
package sparseArr;
/*
目的:使用稀疏数组,保留类似棋盘地图等二维数组,用于保留上一局的棋盘情况
思路:
一、二维转稀疏
1.遍历原始的二维数组,得到有效的数值并记录为sum
2.根据sum就可以创建稀疏数组sparseArr[sum+1][3]
3.将二维数组有效的值传入稀疏数组中
二、稀疏转二维:
1.读取稀疏数组的第一行数据,创建一个新的二维数组
2.再读取后几行数据赋值给新的二维数组
*/
public class SparseArr {
public static void main(String[] args) {
//先创建一个二维数组(棋盘)规格为11*11
int chessArr[][] = new int[11][11];
chessArr[1][2] = 2;
chessArr[2][4] = 1;
//有效值的总数
int sum = 0;
//输出原始的二维数组
System.out.println("输出原始的二维数组");
for (int[] row : chessArr) {
for (int data : row) {
//定义输出格式从左到右
System.out.printf("%d\t", data);
if (data != 0) sum++;//计算有效数据的总数
}
//换行
System.out.println();
}
//输出有效值的总数
System.out.println("有效值的总数为" + sum);
//创建对应的稀疏数组
int sparseArr[][] = new int[sum + 1][3];
//给稀疏数组第一行赋值
sparseArr[0][0] = 11;
sparseArr[0][1] = 11;
sparseArr[0][2] = sum;
//把有效值的数据传入到稀疏数组中
int count = 1;//,因为稀疏数组的行是不固定的,所以要定义一个count用作于稀疏数组的行,每有一个不同的数就多一行。
//通过遍历把原来二维数组的有效值数据记录到稀疏数组中
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 11; j++) {
if (chessArr[i][j] != 0) {
//第一列记录原二维数组的行
sparseArr[count][0] = i;
//第二列记录原二维数组的列
sparseArr[count][1] = j;
//第三列记录原二维数组的值
sparseArr[count][2] = chessArr[i][j];
//记录完毕后行数加一
count++;
}
}
}
//输出生成的稀疏数组
System.out.println("稀疏数组如下:");
for (int[] row : sparseArr) {
for (int data : row) {
System.out.printf("%d\t", data);
}
//换行
System.out.println();
}
//把稀疏数组转换成对应的二维数组
int row = sparseArr[0][0];//根据稀疏数组第一行第一列的数据定义新二维数组的行
int line = sparseArr[0][1];//根据稀疏数组第一行第二列的数据定义新二维数组的列
int chessArr2[][] = new int[row][line];//创建新的二维数组
int length = sparseArr.length;//获取稀疏数组的总行数
//通过遍历行数给二维数组对应的位置组赋值
for (int i = 1; i < length; i++) {
chessArr2[sparseArr[i][0]][sparseArr[i][1]]=sparseArr[i][2];
}
//输出稀疏数组转化的二维数组
System.out.println("稀疏数组转化的二维数组:");
for (int[] rows : chessArr2) {
for (int data : rows) {
//定义输出格式从左到右
System.out.printf("%d\t", data);
if (data != 0) sum++;//计算有效数据的总数
}
//换行
System.out.println();
}
}
}
运行结果
上述只是简单的对稀疏数组与二维数组进行转换,其实我们可以用文件流通过读写文件来完成。这就更符合我们日常的应用。
JAVA知识点补充
增强for——foreach
首先先介绍一下增强for,foreach 是用来对数组或者集合进行遍历的语法。具体语法如下:
for(元素类型 ele : 数组名/Iterable 实例){
}
下面我们用 foreach 来对数组和一个集合进行遍历:
int [] array = {1,2,3};
for(int i : array){
System.out.println(i);
}
然后我们可以通过反编译工具,查看 class 文件内容:
int array[] = {1,2,3};
int [] array$ = array;
for(int len$ = array$.length, i$ = 0; i$<len$; ++i$ )
{
int i = array$[i$];
{
System.out.println(i);
}
}
通过上述反编译,我们可以类似的拆解我们实现稀疏数组程序的代码,例如
for (int[] row : chessArr) {
for (int data : row) {
//定义输出格式从左到右
System.out.printf("%d\t", data);
if (data != 0) sum++;//计算有效数据的总数
}
拆解如下:
int[] chessArr$ = chessArr;
for(int len$=chessArr$.length,i$=0;i$<len$; ++i$)
{
int[]row=chessArr$[i$];
for(int len$=row$.length,i$=0;i$<len$; ++i$)
{
int data=row$[i$];
System.out.printf("%d\t",data);
}
}
注意:1.一维数组与当二维数组的.length意思不一样。
1.二维数组的length表示的不是一共有多少个元素而是表示有多少行,比如chessArr.length的值是11(一共11行)不是121(行乘列–11*11=121)。
2.chessArr[0].length表示这个二维数组的第一行有多少列的意思。