稀疏数组
基本介绍: 当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。
稀疏数组的处理方法是:
1)记录数组一共有几行几列,有多少个不同的值
2)把具有不同值的元素的行列及值记录在一个小规模的数组中,从而缩小程序的规模
看到这里,小白们是不是看的有点懵啊(大神请飘过哈~~)? 没关系,刚开始学,不要着急
稀疏数组分为三列:第一列为: 行(原数组某行);第二列为:列(原数组某列);第三列为:值(原数组某一坐标的数据)
稀疏数组第一行固定为说明原数组的属性:行 -》 表示原数组有多少行 ; 列 -》 表示原数组有多少列 ; 值-》 表示原数组有几个有效值
如上图中: 举个例子哈,原数组为二维数组,姑且我们令为 int[] [] array_new= new int[6][7] .二维数组不懂的,去首页搜一下先了解了解就懂了。 我们来看第一行,有数据22 和15。在代码中我们会这样表示: array_new[0][3]=22 array_new[0][6]=15 ,那如何把这两个输转为稀疏数组呢? 好,我们来转一个(请对着上图右边的稀疏数组)。
首先,写上: 行 列 值
然后对应写下第一行: 6 7 8 (第一行固定写原数组的属性信息)
我们再把22写到里面: 0 3 22
我们再把15写到里面: 0 6 15
参数说明:第一行中:6,表示原数组是6行;7,表示原数组是7行;8,表示原数组有8个有效值(我这里是指非零的值有8个);
第一行中:0,表示数字22在原数组的第一行;3,表示数字22在原数组的第一列;22,就是原数组的array_new[0][3]=22
....
以此类推,小白们,会了吗?
应用实例
使用稀疏数组,来保留类似前面的二维数组(棋盘、地图等等) 把稀疏数组存盘,并且可以从新恢复原来的二维数组数 整体思路分析
下面我们来实现这个实例的代码:
代码构思: 原数组为11列11行的二维数组,有数据1,2。
那么我们构造一个二维数组:
int[][] array_new= new int[11][11];
array_new[1][2] =1;
array_new[2][3] =2;
循环遍历打印一下:
for (int[] is : array_new) {
for (int i : is) {
System.out.print(i+"\t");
}
System.out.println("");
}
下面我们来写稀疏函数:
列 行 值
11 11 2 (第一行固定为原数组属性信息)
1 2 1
2 3 2
第一步,我们要动态获取原数组的行和列:
int row_oldArray =array_new.length;
System.out.println("原数组行数:"+row_oldArray);
int column_oldArray =array_new[0].length;
System.out.println("原数组列数:"+column_oldArray);
我们再来获取原数组有效值(我们这指非0的值):
int nums=0;
for (int[] is : array_new) {
for (int i : is) {
if(i!=0)
nums++;
}
}
System.out.println("原数组有效值个数:"+nums);
稀疏函数的列数是3,行数是有效值的个数+第一行,所以为nums+1行:int sparse_array[][]=new int[nums+1][3];
而且稀疏函数第一行的三列是固定的原数组属性值,所以我们可以给第一行直接赋值:
int row=0;//从第一行开始
sparse_array[0][0]=row_oldArray; //稀疏函数第一行第一列为原数组的行数
sparse_array[0][1]=row_oldArray; //稀疏函数第一行第二列为原数组的列数
sparse_array[0][2]=nums; //稀疏函数第一行第三列为原数组的有效值个数
接下来,我们要for循环遍历原数组获取有效值所在的行数和列数,所以这里嵌套两个for循环(你品,细细品)
我们要获取有效值,所以要判断是否为0,不为0时我们先把row数加一,因为我们每获取一个有效值时稀疏数组行数要加一((你再品,再细细品))
for(int j=0;j<array_new.length;j++){
for(int k=0;k<array_new[0].length;k++){
if(array_new[j][k]!=0){
row++; //每获得一个有效值,行数要加一,你品品看
sparse_array[row][0]=j; //稀疏函数第n行第一列为某有效值在原数组的行数
sparse_array[row][1]=k; //稀疏函数第n行第二列为某有效值在原数组的列数
sparse_array[row][2]=array_new[j][k]; //稀疏函数第n行第三列为某有效值
}
}
}
接下来我们再通过循环打印一下构造好后的稀疏数组:
for (int[] is : sparse_array) {
for (int i : is) {
System.out.print(i+"\t");
}
System.out.println("");
}
好了,到了这一步,我们已经构造好稀疏数组了;下面是原数组转为稀疏数组的源码:
package com.study.array_tosparse;
import org.junit.Test;
public class ArrayToSparse {
@Test
public void Array_ToSparse(){
int[][] array_new= new int[11][11];
array_new[1][2] =1;
array_new[2][3] =2;
array_new[7][8] =55;
//输出原数组
System.out.println("原数组为:");
for (int[] is : array_new) {
for (int i : is) {
System.out.print(i+"\t");
}
System.out.println("");
}
//1.获取原数组的行数和列数
int row_oldArray =array_new.length;
System.out.println("原数组行数:"+row_oldArray);
int column_oldArray =array_new[0].length;
System.out.println("原数组列数:"+column_oldArray);
//2.获取原数组有效值的个数
int nums=0;
for (int[] is : array_new) {
for (int i : is) {
if(i!=0)
nums++;
}
}
System.out.println("原数组有效值个数:"+nums);
//3.正式构建稀疏数组
int sparse_array[][]=new int[nums+1][3]; //nums表示原数组有效值个数,而稀疏数组第一行固定为原数组的属性信息,所以我们要加1;3表示3列(因为稀疏函数固定为3列)
int row=0;//从第一行开始
sparse_array[0][0]=row_oldArray; //稀疏函数第一行第一列为原数组的行数
sparse_array[0][1]=row_oldArray; //稀疏函数第一行第二列为原数组的列数
sparse_array[0][2]=nums; //稀疏函数第一行第三列为原数组的有效值个数
for(int j=0;j<array_new.length;j++){
for(int k=0;k<array_new[0].length;k++){
if(array_new[j][k]!=0){
row++; //每获得一个有效值,行数要加一,你品品看
sparse_array[row][0]=j; //稀疏函数第n行第一列为某有效值在原数组的行数
sparse_array[row][1]=k; //稀疏函数第n行第二列为某有效值在原数组的列数
sparse_array[row][2]=array_new[j][k]; //稀疏函数第n行第三列为某有效值
}
}
}
for (int[] is : sparse_array) {
for (int i : is) {
System.out.print(i+"\t");
}
System.out.println("");
}
}
}
目录
我们还是以上面的原数组和稀疏数组为例子,
1.自定义构造稀疏数组,我们假设原数组为11行11列,有效值有2个
int sparse_array[][]=new int[3][3];
sparse_array[0][0]=11; //稀疏函数第一行第一列为原数组的行数
sparse_array[0][1]=11; //稀疏函数第一行第二列为原数组的列数
sparse_array[0][2]=2;
sparse_array[1][0]=1;
sparse_array[1][1]=2;
sparse_array[1][2]=1;
sparse_array[2][0]=2;
sparse_array[2][1]=3;
sparse_array[2][2]=2;
2.构造原数组
int[][] array_new =new int[sparse_array[0][0]][sparse_array[0][1]];
for(int i =1;i<sparse_array.length;i++){
array_new[sparse_array[i][0]][sparse_array[i][1]]=sparse_array[i][2];
}
sparse_array[i][0]为有效值在原数组的行数,[sparse_array[i][1]为有效值在原数组的列数,[sparse_array[i][2]为某有效值
3.遍历输出原数组
for (int[] is : array_new) {
for (int i : is) {
System.out.print(i+"\t");
}
System.out.println("");
}
下面为稀疏数组转原数组的源代码:
package com.study.array_tosparse;
import org.junit.Test;
public class SparseToArray {
@Test
public void sparseToArray()
{
//1.自定义构造稀疏数组,我们假设原数组为11行11列,有效值有2个
int sparse_array[][]=new int[3][3];
sparse_array[0][0]=11; //稀疏函数第一行第一列为原数组的行数
sparse_array[0][1]=11; //稀疏函数第一行第二列为原数组的列数
sparse_array[0][2]=2;
sparse_array[1][0]=1;
sparse_array[1][1]=2;
sparse_array[1][2]=1;
sparse_array[2][0]=2;
sparse_array[2][1]=3;
sparse_array[2][2]=2;
//2.构造原数组
int[][] array_new =new int[sparse_array[0][0]][sparse_array[0][1]];
for(int i =1;i<sparse_array.length;i++){
array_new[sparse_array[i][0]][sparse_array[i][1]]=sparse_array[i][2];
}
for (int[] is : array_new) {
for (int i : is) {
System.out.print(i+"\t");
}
System.out.println("");
}
}
}
目录
队列是一个有序列表,可以用数组或是链表来实现。 遵循先入先出的原则。即:先存入队列的数据,要先取出。后存入的要后取出 示意图:(使用数组模拟队列示意图)
注: 队列是先进先出(相当于排队办业务,先排的先办业务),栈是先进后出(相当于往盒子里面放东西,往外拿总是先拿上面后放进去的)
数组模拟队列
队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下图, 其中 maxSize 是该队列的最大容量。 因为队列的输出、输入是分别从前后端来处理,因此需要两个变量 front及 rear分别记录队列前后端的下标,front 会随着数据输出而改变,而 rear则是随着数据输入而改变。
当我们将数据存入队列时称为”addQueue”,addQueue 的处理需要有两个步骤:
思路分析 1) 尾索引的下一个为头索引时表示队列满,即将队 列容量空出一个作为约定,这个在做判断队列满的 时候需要注意 (rear + 1) % maxSize == front 满]
2) rear == front 时队列为[空]
3)初始值:front =0,指向第一个元素 ; rear=0, rear表示指向队列最后一个元素的后一个位置
4)队列有效数据个数 = (rear -front + maxSize) % maxSize //如:rear=1 fron=0时 maxSize任意
5)poll出数据时,使用临时变量,int value = arr[front]; front = (front + 1) % maxSize;
下面贴上源码,都有详细注释,请你好好品:
package com.study.queue;
public class MoniQueue {
public static void main(String[] args) {
CirtleQueue queue = new CirtleQueue(3); //最大数据为3-1=2,因为预留了一个位置
queue.add(0);
queue.add(1);
queue.poll();
queue.show();
queue.add(1);
queue.show();
queue.getHead();
}
}
class CirtleQueue{
private int maxSize; //数组最大容量
private int front; //front初始值为0,队头
private int rear; //rear初始值为0,队尾
private int[] arr; //用于存储数据,模拟队列
//构造函数
public CirtleQueue(int maxSize) {
this.maxSize = maxSize;
arr = new int[maxSize];
}
//1.add
public void add(int a){
if(isFull()){
System.out.println("队列满,不能加入数据~");
return;
}
arr[rear]= a; //rear+1预留了一个位置,所以添加元素就是添加在arr[rear]
rear =(rear+1) % maxSize; //添加数据后rear+1,既rear位置后移一位,与maxSize取模是因为环形,这个地方你好好品
}
//2.show 展示所有数据
public void show(){
if(isEmpty()){
System.out.println("队列空的,没有数据~~");
return;
}
// 思路:从front开始遍历,遍历多少个元素
// 动脑筋
System.out.println("队列所有元素:");//front指向队头,加上有效数据个数,即为循环次数
for (int i = front; i < front + numsOfaccess() ; i++) {
System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
}
}
//3.getHead 获得队头数据,不是出队
public void getHead(){
if(isEmpty()){
System.out.println("队列空的,没有数据~~");
return;
}
System.out.println("队头数据:"+arr[front]);
}
//4.poll 出队
public void poll(){
if(isEmpty()){
// 没数据则抛出异常
throw new RuntimeException("队列空,不能取数据");
}
// 这里需要分析出 front是指向队列的第一个元素
// 1. 先把 front 对应的值保留到一个临时变量
// 2. 将 front 后移, 考虑取模
// 3. 将临时保存的变量返回
int value = arr[front];
front = (front + 1) % maxSize;
System.out.println("取出的数据为:"+value); ;
}
//5.isFull
public boolean isFull(){
return (rear+1) % maxSize == front ;
}
//6.isEmpty
public boolean isEmpty(){
return rear == front ;
}
//7.获取有效数据个数
public int numsOfaccess(){
return (rear-front+maxSize) % maxSize;//rear-front等于单链的有效数字个数,加上maxSize再取模,这个地方你好好品
}
}