文章目录
- 一 数据结构介绍
- 1 数据结构和算法的重要性
- 2 数据结构和算法的关系
- 3 线性结构和非线性结构
- (1)线性结构
- (2)非线性结构
- 二 稀疏数组
- 1 应用场景
- 2 基本概念
- (1)基本介绍
- (2)压缩策略
- a 压缩存储
- b 链式存储
- 3 需求实现
- (1)需求分析
- (2)思路分析
- a 二维数组转稀疏数组的思路
- b 稀疏数组转原始的二维数组的思路
- (3)代码实现
- a 普通数组 --> 稀疏数组
- b 稀疏数组 --> 普通数组
- 4 完整代码
一 数据结构介绍
1 数据结构和算法的重要性
- 算法是程序的灵魂,优秀的程序可以在海量数据计算时,依然保持高速计算。
- 一般来讲程序会使用了内存计算框架 ( 比如Spark ) 和缓存技术 ( 比如Redis等 ) 来优化程序,再深入的思考一下,这些计算框架和缓存技术, 它的核心功能是哪个部分呢?
- 拿实际工作经历来说, 在Unix下开发服务器程序,功能是要支持上千万人同时在线, 在上线前,做内测,一切OK。可上线后,服务器就支撑不住了,公司的CTO对代码进行优化,再次上线,坚如磐石。就能感受到程序是有灵魂的,就是算法。
- 目前程序员面试的门槛越来越高,很多一线IT公司(大厂),都会有数据结构和算法面试题。
- 如果不想永远都是代码工人,那就花时间来研究下数据结构和算法。
2 数据结构和算法的关系
- 数据结构(data structure)是一门研究组织数据方式的学科,有了编程语言也就有了数据结构.学好数据结构可以编写出更加漂亮,更加有效率的代码。
- 要学习好数据结构就要多多考虑如何将生活中遇到的问题,用程序去实现解决.
- 程序 = 数据结构 + 算法
- 数据结构是算法的基础, 换言之,想要学好算法,需要把数据结构学到位。
3 线性结构和非线性结构
数据结构包括:线性结构和非线性结构。
(1)线性结构
- 线性结构作为最常用的数据结构,其特点是数据元素之间存在一对一的线性关系。
- 线性结构有两种不同的存储结构,即顺序存储结构和链式存储结构。
- 顺序存储的线性表称为顺序表,顺序表中的存储元素是连续的。
- 链式存储的线性表称为链表,链表中的存储元素不一定是连续的,元素节点中存放数据元素以及相邻元素的地址信息。
- 线性结构常见的有:数组、队列、链表和栈。
(2)非线性结构
- 其特点是数据元素之间存在一对多的非线性关系。
- 非线性结构包括:二维数组,多维数组,广义表,树结构,图结构。
二 稀疏数组
1 应用场景
假如想要开发一个五子棋游戏,如果使用二维数组记录棋盘,将黑棋置为1,白棋置为2,会发现这样一个数组存在很多没有意义的默认值0,浪费很多空间,这时就可以使用稀疏数组。
- 使用稀疏数组,来保留类似棋盘,地图等二维数组。
- 把稀疏数组存盘,并且可以从新恢复原来的二维数组数。
2 基本概念
(1)基本介绍
当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。
非零元素远远少于矩阵元素的个数。
(2)压缩策略
稀疏数组的处理方法(压缩策略)是:
- 压缩存储:记录数组一共有几行几列,有多少个不同的值。
- 链式存储:把具有不同值的元素的行列及值记录在一个小规模的数组中,从而缩小程序的规模。
如下图是一个稀疏矩阵的示例:
a 压缩存储
针对上图稀疏数组,使用压缩存储策略:顺序存储——三元组 <行,列,值>。
存储形式如下图:
注意存储的行列值与数组的下标相差一。
b 链式存储
使用链式存储策略存储上图稀疏数组,存储成下图:其中行列值的下面分别存在两个指针,左指针和右指针,具体含义如图:
3 需求实现
(1)需求分析
使用普通数组实现上图中的数组,再将普通数组转化成上图的稀疏数组,最后从稀疏数组恢复成普通数组。
(2)思路分析
如果使用二维数组存储棋盘会浪费很多空间,所以采用稀疏数组进行优化。
a 二维数组转稀疏数组的思路
- 遍历原始的二维数组,得到有效数据的个数
sum
。 - 根据
sum
可以创建稀疏数组``sparseArr,数组大小为
int[sum] [3]`(三列分别为压缩存储中对应的【行row、列col、值val】。 - 将二维数组的有效数据数据存入到稀疏数组。
b 稀疏数组转原始的二维数组的思路
- 先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组。
- 在读取稀疏数组后几行的数据时,赋给原始的二维数组。
(3)代码实现
a 普通数组 --> 稀疏数组
// 创建原始的二维数据
int orginalArr[][] = new int[5][6];
orginalArr[0][2] = 4;
orginalArr[0][5] = 5;
orginalArr[1][1] = 3;
orginalArr[1][3] = 9;
orginalArr[2][4] = 7;
orginalArr[3][1] = 2;
// 输出原始二维数组
System.out.println("==================输出原始二维数组==================");
for(int[] row : orginalArr){
for(int date : row){
System.out.print(date + " ");
}
System.out.println();
}
// 将二维数组转化成稀疏数组
// 遍历二维数组,得到非0数据的个数
int sum = 0;
for(int[] row : orginalArr){
for(int date : row){
if(date != 0){
sum++;
}
}
}
// 创建对应的稀疏数组
int sparseArray[][] = new int[sum][3];
// 记录当前是第几个非0数据
int count = 0;
for(int i = 0; i < orginalArr.length; i++){
for (int j = 0; j < orginalArr[0].length; j++){
if(orginalArr[i][j] != 0){
sparseArray[count][0] = i + 1;
sparseArray[count][1] = j + 1;
sparseArray[count][2] = orginalArr[i][j];
count++;
}
}
}
// 输出稀疏数组
System.out.println("==================输出对应的稀疏数组==================");
System.out.println("i" + " " + "j" + " " + "v");
for(int i = 0; i < sparseArray.length; i++){
System.out.print(sparseArray[i][0] + " ");
System.out.print(sparseArray[i][1] + " ");
System.out.print(sparseArray[i][2] + " ");
System.out.println();
}
结果如下:
b 稀疏数组 --> 普通数组
// 将稀疏数组恢复成原始数组
System.out.println("==================输出恢复后的数组==================");
int row = 0;
int col = 0;
int maxRowIndex = 0;
int maxColIndex = 0;
for(int i = 0; i < sparseArray.length;i++){
if(sparseArray[i][0] >= maxRowIndex){
maxRowIndex = sparseArray[i][0];
row = maxRowIndex;
}
if(sparseArray[i][1] >= maxColIndex){
maxColIndex = sparseArray[i][1];
col = maxColIndex;
}
}
// 创建数组
int newOriginArr[][] = new int[row][col];
// 为新数组赋值
for(int i = 0; i < sparseArray.length; i++){
newOriginArr[sparseArray[i][0] - 1][sparseArray[i][1] - 1] = sparseArray[i][2];
}
// 遍历输出
for(int i = 0; i < newOriginArr.length; i++){
for(int j = 0; j < newOriginArr[0].length; j++){
System.out.print(newOriginArr[i][j] + " ");
}
System.out.println();
}
结果如下:
注意:最后一行全为0的行没有被恢复。
4 完整代码
public class SparseArray {
public static void main(String[] args) {
// 创建原始的二维数据
int orginalArr[][] = new int[5][6];
orginalArr[0][2] = 4;
orginalArr[0][5] = 5;
orginalArr[1][1] = 3;
orginalArr[1][3] = 9;
orginalArr[2][4] = 7;
orginalArr[3][1] = 2;
// 输出原始二维数组
System.out.println("==================输出原始二维数组==================");
for(int[] row : orginalArr){
for(int date : row){
System.out.print(date + " ");
}
System.out.println();
}
// 将二维数组转化成稀疏数组
// 遍历二维数组,得到非0数据的个数
int sum = 0;
for(int[] row : orginalArr){
for(int date : row){
if(date != 0){
sum++;
}
}
}
// 创建对应的稀疏数组
int sparseArray[][] = new int[sum][3];
// 记录当前是第几个非0数据
int count = 0;
for(int i = 0; i < orginalArr.length; i++){
for (int j = 0; j < orginalArr[0].length; j++){
if(orginalArr[i][j] != 0){
sparseArray[count][0] = i + 1;
sparseArray[count][1] = j + 1;
sparseArray[count][2] = orginalArr[i][j];
count++;
}
}
}
// 输出稀疏数组
System.out.println("==================输出对应的稀疏数组==================");
System.out.println("i" + " " + "j" + " " + "v");
for(int i = 0; i < sparseArray.length; i++){
System.out.print(sparseArray[i][0] + " ");
System.out.print(sparseArray[i][1] + " ");
System.out.print(sparseArray[i][2] + " ");
System.out.println();
}
// 将稀疏数组恢复成原始数组
System.out.println("==================输出恢复后的数组==================");
int row = 0;
int col = 0;
int maxRowIndex = 0;
int maxColIndex = 0;
for(int i = 0; i < sparseArray.length;i++){
if(sparseArray[i][0] >= maxRowIndex){
maxRowIndex = sparseArray[i][0];
row = maxRowIndex;
}
if(sparseArray[i][1] >= maxColIndex){
maxColIndex = sparseArray[i][1];
col = maxColIndex;
}
}
// 创建数组
int newOriginArr[][] = new int[row][col];
// 为新数组赋值
for(int i = 0; i < sparseArray.length; i++){
if(sparseArray[i][2] != 0){
newOriginArr[sparseArray[i][0] - 1][sparseArray[i][1] - 1] = sparseArray[i][2];
}
}
// 遍历输出
for(int i = 0; i < newOriginArr.length; i++){
for(int j = 0; j < newOriginArr[0].length; j++){
System.out.print(newOriginArr[i][j] + " ");
}
System.out.println();
}
}
}