01稀疏数组与队列

1、线性结构与非线性结构

数据结构包括:线性结构与非线性结构

线性结构

  1. 线性结构作为最常用的数据结构,其特点是数据元素之间存在一对一的线性关系
  2. 线性结构有两种不同的存储结构,即顺序存储结构(数组)链式存储结构(链表)。顺序存储的线性表称为顺序表,顺序表中的存储元素是连续的
  3. 链式存储的线性表称为链表,链表中的存储元素不一定是连续的,元素节点中存放数据元素以及相邻元素的地址信息
  4. 线性结构常见的有:数组、队列、链表和栈。

非线性结构

非线性结构包括:二维数组、多维数组,广义表,树结构,图结构。

2、稀疏数组

基本介绍 ·

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

稀疏数组的处理方法:

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

应用实例

  1. 使用稀疏数组,来保留类似前面的二维数组(棋盘,地图)
  2. 把稀疏数组存盘,并且可以重新恢复原来的二维数组
  3. 整体思路分析
/*
	二维数组转稀疏数组的思路
		1、遍历原始的二维数组,得到有效数据的个数sum
		2、根据sum就可以创建稀疏数组sparseArr int[sum+1][3]
		3、将二维数组的有效数据存入到稀疏数组
		
	稀疏数组转原始的二维数组的思路
		1、先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组,比如上面的chessArr2=iny[11][11]
		2、再读取稀疏数组后面几行的数据,并复制给原始的二维数组即可
*/

稀疏数组的代码实现

代码实现

package A稀疏数组;

import java.util.Arrays;

/**
 * @Author Zhou  jian
 * @Date 2019 ${month}  2019/12/24 0024  15:23
 */
public class SparseArray
{
    public static void main(String[] args) {
        /*
                创建一个原始的二维数组11*11
                0:表示没有旗子
                1:表示黑子
                2:表示蓝字
         */
        	//构建数组,并在非0数据处存放元素
            int[][] chessArr = new int[11][11];
            chessArr[1][2]=1;  
            chessArr[2][3]=2;

            //输出原始的二维数组
           for(int[] row:chessArr){
                for(int data:row){
                    System.out.printf("%d\t",data);
                }
                System.out.println();
           }

        /**
         * 将二维数组转换为稀疏数组:
         * 1、先遍历二维数组得到非0数据的个数
         * 2、根据sum就可以创建稀疏数组sparseArr int[sum+1][3]
         * 3、将二维数组的有效数据存入到稀疏数组
         */
        int sum = 0;
        for(int[] row:chessArr){
            for(int data:row){
                if(data!=0){
                    sum++;
                }
            }
        }
        //创建对应的稀疏数组
        int[][] sparseArr = new int[sum+1][3];
        sparseArr[0][0]= chessArr.length;
        sparseArr[0][1]= chessArr[0].length;
        sparseArr[0][2]= sum;
        //遍历二维数组,将非0的值存入稀疏数组中
        int count =1; //count用于记录第几个非0数据
        for(int row =0;row<chessArr.length;row++){
            for(int col=0;col<chessArr[0].length;col++){
                if(chessArr[row][col]!=0){
                    sparseArr[count][0]=row;
                    sparseArr[count][1]=col;
                    sparseArr[count][2]=chessArr[row][col];
                    count++;
                }
            }
        }
        //输出稀疏数组
        System.out.println("得到的稀疏数组为");
        for(int i=0;i<sparseArr.length;i++){
            System.out.printf("%d\t%d\t%d\t\n",sparseArr[i][0],sparseArr[i][1],sparseArr[i][2]);
        }

        /**
         * 将稀疏数组恢复成原始的二维数组
         *  1、先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组,比如上面的chessArr2=iny[11][11]
         2、再读取稀疏数组后面几行的数据,并复制给原始的二维数组即可
         */
	
        int[][] chessArry2 = new int[sparseArr[0][0]][sparseArr[0][1]];
        for(int i=1;i<sparseArr.length;i++){
            chessArry2[sparseArr[i][0]][sparseArr[i][1]]=sparseArr[i][2];
        }
        System.out.println("恢复的原始数组为");
        for(int[] row:chessArry2){
            for(int data:row){
                System.out.printf("%d\t",data);
            }
            System.out.println();
        }

    }
}




3、队列

基本介绍

  1. 队列是一个有序列表,可以用数组或是链表来实现。
  2. 遵循先入先出的原则。即:先存入队列的数据,要先取出。后存入的要后取出(出入口在两个方向

数组模拟简单队列

  1. 队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下图,其中maxSize是该队列的最大容量

  2. 因为队列的输出、输入分别是从前后两端来处理,因此需要两个变量frontrear分别记录队列前后两端的下标,front会随着数据输出而改变,rear会随着数据输入而改变
    在这里插入图片描述


    package B队列;
    import java.util.Scanner;
    
    /**
     * @Author Zhou  jian
     * @Date 2019 ${month}  2019/12/24 0024  16:16
     */
    public class ArrayQueueDemo {
        public static void main(String[] args) {
    
            //创建一个队列
            ArrayQueue arrayQueue = new ArrayQueue(3);
            char key = ' ';//接受用户输入
            Scanner scanner = new Scanner(System.in);
            boolean loop = true;
            //输出一个菜单
            while(loop){
                System.out.println("s(show):显示队列");
                System.out.println("e(exit):退出程序");
                System.out.println("a(add):添加数据到队列");
                System.out.println("g(get):从队列取出数据");
                System.out.println("h(head):查看队列头数据");
                key = scanner.next().charAt(0);
                switch (key){
                    case 's':
                        arrayQueue.showQueue();
                        break;
                    case 'a':
                        System.out.println("输入一个数");
                        int value = scanner.nextInt();
                        arrayQueue.addQueue(value);
                        break;
                    case 'g':
                        try{
                            System.out.println("取出的数据是"+arrayQueue.getQueue());
                        }catch (Exception e){
                            System.out.println(e);
                        }
                        break;
                    case 'h':
                        try {
                            System.out.println("取出的头部数据为"+arrayQueue.headQueue());
                        }catch (Exception e){
                            System.out.println(e.getMessage());
                        }
                        break;
                    case 'e':
                        scanner.close();
                        loop = false;
                }
            }
        }
    
    }
    
    //使用数组模拟队列--编写一个ArrayQueue
    class ArrayQueue{
    
        //表示数组最大容量
        private int maxSize;
        private  int front;//队列头(不包含)
        private int rear;//队列尾部(包含)
        private  int[] arr;//该数组用于存放数据
    
        //创建队列的构造器
        public ArrayQueue(int maxSize) {
            this.maxSize = maxSize;
            arr = new int[maxSize];
            front = -1; //指向队列头部,分析出front是指向队列头的前一个位置(不包含)
            rear =-1; //指向队列尾部,指向队列尾部的具体数据(即包含,就是队列的最后一个数据)
        }
    
        //判断队列是否满
        public boolean isFull(){
            return rear==maxSize-1;
        }
    
        //判断队列是否为空
        public boolean isEmpty(){
            return rear==front;
        }
    
        //添加数据到队列
        public void addQueue(int data){
            //判断队列是否满
            if(isFull()) {
                System.out.println("队列满。不能加入数据~");
                return;
            }else{
                rear++;
                arr[rear]=data;
            }
        }
    
        //获取队列数据出队列
        public int getQueue(){
            if(isEmpty()){
                System.out.println("队列为空");
                throw  new RuntimeException("队列空,不能取数据");
            }else{
                front++; //front后羿
                return arr[front];
            }
        }
    
        //显示队列的所有数据:不是
        public void showQueue(){
            //遍历
            if(isEmpty()){
                System.out.println("队列空的,没有数据");
                return;
            }else{
                for(int i=0;i<arr.length;i++){
                    System.out.printf("arr[%d]=%d\n",i,arr[i]);
                }
            }
        }
    
        //显示队列的头数据,不是取数据
        public int headQueue(){
            if(isEmpty()){
                throw new RuntimeException("队列为空");
            }else{
                return arr[front+1];
            }
        }
    
    }
    
    

    问题分析并优化

    目前数组使用一次就不能复用

    将这个数组使用算法,改进成一个环形的数组:取模实现

数组模拟环形队列

对前面的数组模拟队列的优化,充分利用数组,因此将数组看做是一个环形的(通过取模的方式来实现即可)

思路如下

  1. front变量的含义做一个调整:front指向队列的第一个元素,也就是说arr[front]就是队列的第一个元素;front的初始值为0

  2. rear的变量的含义做一个调整:rear指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为一个约定,rear的初始值0

  3. 当队列满时,条件是:(rear+1)%maxSize=front(思考为甚么要取模)

  4. 当队列空时,条件是:rear等于front

  5. 当我们这样分析时,队列中的有效数据个数==(rear+maxSize-front)%maxSize==

    环形队列中需要预留一个空间用来判断队列是否满(尾索引的下一个为头索引时表示队列满,即将队列容量空出一个做为约定);也可以用其他的算法实现,但是本实现中采用此种思路

    思考:若没有预留空间会出现什么情况??则无法判断队列空与满的情况

在这里插入图片描述

package B队列;

import java.util.Scanner;

/**
 * @Author Zhou  jian
 * @Date 2019 ${month}  2019/12/24 0024  17:25
    环形的数组队列实现
 */
public class CircleArrayDemo {
    public static void main(String[] args) {

        System.out.println("测试数组模拟环形队列");
        //创建一个队列,最多存储三个数据
        CircleArray circleArray = new CircleArray(4);
        char key = ' ';//接受用户输入
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        //输出一个菜单
        while(loop){
            System.out.println("s(show):显示队列");
            System.out.println("e(exit):退出程序");
            System.out.println("a(add):添加数据到队列");
            System.out.println("g(get):从队列取出数据");
            System.out.println("h(head):查看队列头数据");
            key = scanner.next().charAt(0);
            switch (key){
                case 's':
                    circleArray.showQueue();
                    break;
                case 'a':
                    System.out.println("输入一个数");
                    int value = scanner.nextInt();
                    circleArray.addQueue(value);
                    break;
                case 'g':
                    try{
                        System.out.println("取出的数据是"+circleArray.getQueue());
                    }catch (Exception e){
                        System.out.println(e);
                    }
                    break;
                case 'h':
                    try {
                        System.out.println("取出的头部数据为"+circleArray.headQueue());
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e':
                    scanner.close();
                    loop = false;
            }
        }
    }





    }




class CircleArray{

    //表示数组最大容量
    private int maxSize;
    //front变量的含义做一个调整:front指向队列的第一个元素,也就是说arr[front]就是队列的第一个元素;
    // ==front的初始值为0==
    private  int front;
    //rear的变量的含义做余个调整:rear指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为一个约定,
    // ==rear的初始值=0==
    private int rear;
    private  int[] arr;//该数组用于存放数据


    public CircleArray(int maxSize) {
        this.maxSize = maxSize;
        arr = new int[maxSize];
        front =0;
        rear=0;
    }

    //判断队列是否满
    public boolean isFull(){
        return (rear+1)%maxSize==front;
    }

    //判断队列是否为空
    public boolean isEmpty(){
        return rear==front;
    }

    //添加数据到队列
    public void addQueue(int data){
        //判断队列是否满
        if(isFull()) {
            System.out.println("队列满。不能加入数据~");
            return;
        }else{
            //因为rear指向最后一个元素的下一个位置
            //直接将数据加入
            arr[rear]=data;
            //将rear后羿,必须考虑取模
            rear = (rear+1)%maxSize;
        }
    }

    //获取队列数据出队列
    public int getQueue(){
        if(isEmpty()){
            System.out.println("队列为空");
            throw  new RuntimeException("队列空,不能取数据");
        }else{
            //这里需要分析出,front是指向队列的第一个元素
            //先把front对应的值保存到一个临时变量
            int value = arr[front];
            //将front后羿
            front = (front+1)%maxSize;
            //将临时保存的变量返回
            return value;
        }
    }


    //显示队列的所有数据:不是
    public void showQueue(){
        //遍历
        if(isEmpty()){
            System.out.println("队列空的,没有数据");
            return;
        }else{
            //从front开始遍历,遍历多少个元素
            for(int i=front;i<front+size();i++){
                System.out.printf("arr[%d]=%d\n",i%maxSize,arr[i%maxSize]);
            }
        }
    }

    //求当前队列有效数据的个数
    public  int size(){
        return (rear-front+maxSize)%maxSize;
    }


    //显示队列的头数据,不是取数据
    public int headQueue(){
        if(isEmpty()){
            throw new RuntimeException("队列为空");
        }else{
            return arr[front];
        }
    }
}


​ ------------------------------------2019/12/25

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值