[java版数据结构和算法系列之一]稀疏数组和队列

 

稀疏数组

    基本介绍: 当一个数组中大部分元素为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 是该队列的最大容量。 因为队列的输出输入是分别从前后端来处理,因此需要两个变量 frontrear分别记录队列前后端的下标,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再取模,这个地方你好好品
		  }
	
	
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值