0
点赞
收藏
分享

微信扫一扫

[ 数据结构与算法 ]稀疏数组和队列

烟中雯城 2022-02-18 阅读 104

稀疏数组和队列

稀疏sparsearray数组

需求:

编写的五子棋程序中,有存盘退出和续上盘的功能。

image-20220216015445672

分析问题:

因为该二维数组的很多值是默认值 0, 因此记录了 很多没有意义的数据.-> 稀疏数组。

基本介绍

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

稀疏数组的处理方法是:

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

image-20220216015652622

应用实例

  1. 使用稀疏数组,来保留类似前面的二维数组(棋盘、地图等等)
  2. 把稀疏数组存盘,并且可以从新恢复原来的二维数组数
  3. 整体思路分析

image-20220216015730205

代码实现:

package com.hspedu.sparsearray_;

import java.io.*;

/**
 * @ClassName
 * @Description
 * @Author zxk
 * @DateTime 2022-02-15-23:58
 * @Version 稀疏数组
 */
public class SparseArray {
    public static void main(String[] args) {
        int[][] chessArr1=new int[11][11];
        //此处添加棋子的坐标即数组元素
        chessArr1[1][2]=1;
        chessArr1[2][3]=2;
        chessArr1[5][6]=1;

        //遍历原始二维数组
        for (int[] row : chessArr1) {
            for (int i : row) {//打印行
                System.out.print("\t"+i);
            }
            System.out.println();//换行
        }



        //声明稀疏数组
        int count=0;
        for (int i = 0; i < chessArr1.length; i++) {
            for (int j = 0; j < chessArr1[i].length; j++) {
                if (chessArr1[i][j] != 0) {
                    count++;
                }
            }
        }
        System.out.println();
        int[][] sparseArr=new int[count+1][3];
        //初始化稀疏数组
        sparseArr[0][0] = 11;//row
        sparseArr[0][1] = 11;//column
        sparseArr[0][2]=count;//count
        int num=0;
        for (int i = 0; i < chessArr1.length; i++) {
            for (int j = 0; j < chessArr1[i].length; j++) {
                if (chessArr1[i][j] != 0) {
                    num++;
                    sparseArr[num][0]=i;
                    sparseArr[num][1]=j;
                    sparseArr[num][2]=chessArr1[i][j];
                }
            }
        }
        //遍历稀疏数组
        System.out.println("得到稀疏数组:");
        for (int[] row : sparseArr) {
            for (int i : row) {//打印行
                System.out.print("\t"+i);
            }
            System.out.println();//换行
        }
        
        //调用存盘
        keep(sparseArr);
        //调用读取
        int[][] backSparseArr=get();
        
        //恢复后的稀疏数组
        System.out.println("恢复后的稀疏数组:");
        for (int[] row : backSparseArr) {
            for (int i : row) {//打印行
                System.out.print("\t"+i);
            }
            System.out.println();//换行
        }
        
        ///将稀疏数组 --》 恢复成 原始的二维数组
        int[][] chessArr02=new int[backSparseArr[0][0]][backSparseArr[0][1]];
        for (int i = 1; i < backSparseArr.length; i++) {
            chessArr02[backSparseArr[i][0]][backSparseArr[i][1]]=backSparseArr[i][2];
        }
        //遍历恢复后的二维数组
        System.out.println("由稀疏数组恢复后的二维数组:");
        for (int[] row : chessArr02) {
            for (int i : row) {//打印行
                System.out.print("\t"+i);
            }
            System.out.println();//换行
        }
    }
    
    //写入方法
    public static void keep(int[][] arr) {
        BufferedWriter bw=null;
        try {
            bw = new BufferedWriter(new FileWriter("f:\\io\\sparseArr.txt"));
            bw.write(""+arr[0][2]);//存入原始二维数组非零个数,待恢复稀疏数组时声明行数时使用
            bw.newLine();
            for (int i = 0; i < arr.length; i++) {
                bw.write(arr[i][0] + " " + arr[i][1] + " " + arr[i][2]);//写入每行元素
                bw.newLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bw != null) {
                    bw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //读取方法
    public static int[][] get() {
        String data;
        BufferedReader br=null;

        int row=0;//用于表示数组行数但并非行数
        int count=0;//表示读到第几行
        int[][] arr=null;
        try {
            br = new BufferedReader(new FileReader("f:\\io\\sparseArr.txt"));
            row=Integer.parseInt(br.readLine());//数组非零个数用于表示行数
            arr=new int[row+1][3];
            while ((data = br.readLine()) != null) {
                String[] s = data.split(" ");
                arr[count][0]=Integer.parseInt(s[0]);
                arr[count][1]=Integer.parseInt(s[1]);
                arr[count][2]=Integer.parseInt(s[2]);
                count++;//刷新数组的行数

            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (br != null) {
                    br.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return arr;
    }
}

队列

使用场景

银行排队:

image-20220217120034718

队列介绍

  1. 队列是一个 有序列表,可以用 数组或是 链表来实现。
  2. 遵循 先入先出的原则。即: 先存入队列的数据,要先取出。后存入的要后取出
  3. 示意图:(使用数组模拟队列示意图)

image-20220217120116970

数组模拟(直型)队列

思路:

  • 队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下图, 其中 maxSize 是该队列的最大容量。
  • 因为队列的输出、输入是分别从前后端来处理,因此需要两个变量 front 及 rear 分别记录队列前后端的下标,front 会随着数据输出而改变,而 rear 则是随着数据输入而改变,如图所示:

image-20220217120244015

  • 当我们将数据存入队列时称为”addQueue”,addQueue 的处理需要有两个步骤:思路分析
  1. 将尾指针往后移:rear+1 , 当 front == rear 【空】
  2. 若尾指针 rear 小于队列的最大下标 maxSize-1,则将数据存入 rear 所指的数组元素中,否则无法存入数据。
    rear == maxSize - 1[队列满]

代码实现:

public class ArrayQueueDemo {
    public static void main(String[] args) {
        ArrayQueue arrayQueue = new ArrayQueue(3);
        char key = ' ';
        Scanner sc = 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):查看队列头部数据");
            System.out.println("请输入指令:");
            key = sc.next().charAt(0);
            switch (key) {
                case 's':
                    arrayQueue.show();
                    break;
                case 'e':
                    loop = false;
                    break;
                case 'a':
                    System.out.println("输入一个数");
                    int value = sc.nextInt();
                    arrayQueue.add(value);
                    break;
                case 'g':
                    try {
                        int num = arrayQueue.get();
                        System.out.println("取出的数为:"+num);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
                case 'h':
                    try {
                        int head = arrayQueue.head();
                        System.out.println("头部为:"+head);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                default:
                    break;
            }
        }
        System.out.println("程序退出~");
    }
}

//提示:指针只有在添加数据或取出数据时才后移
class ArrayQueue {
    private int maxSize;//容量
    private int rear;//尾
    private int front;//头
    private int[] arr;//

    public ArrayQueue(int num) {
        rear = -1;
        front = -1;
        maxSize = num;
        arr = new int[maxSize];

    }
    //判断数组已满
    public boolean isFull() {
        return rear==maxSize-1;
    }
    //判断数组为空
    public boolean isEmpty() {
        return front==rear;
    }
    //添加方法
    public void add(int num) {
        if (isFull()) {
            System.out.println("满了,添加失败");
            return;
        }
        rear++;
        arr[rear]=num;
    }
    //取出方法
    public int get() throws Exception {
        if (isEmpty()) {
            System.out.println("空的,没法取出");
            throw new Exception("数组为空,无法取出");
        }
        front++;
        return arr[front];
    }
    //遍历方法
    public void show() {
        if (isEmpty()) {
            System.out.println("数组为空");
            return;
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.println("arr[" + i+"]=" + arr[i]);
        }
    }
    //显示头部数据方法
    public int head() throws Exception {
        if (isEmpty()) {
            throw new Exception("数组为空");
        }
        return arr[front+1];
    }
}

问题分析并优化:

  1. 目前数组使用一次就不能用, 没有达到复用的效果
  2. 将这个数组使用算法,改进成一个列 环形的队列 取模:%

数组模拟(环形)队列

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

分析说明:

  1. 尾索引的下一个为头索引时表示队列满,即将队列容量空出一个作为约定,这个在做判断队列满的
    时候需要注意 (rear + 1) % maxSize == front 满]
  2. rear == front [空]
  3. 分析示意图:

img

image-20220218014702941

代码实现:

//数组模拟环形队列
@SuppressWarnings({"all"})
public class QueueDemo {
    public static void main(String[] args) {
        CircleQueue circleQueue = new CircleQueue(3);
        char key = ' ';
        Scanner sc = 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):查看队列头部数据");
            System.out.println("请输入指令:");
            key = sc.next().charAt(0);
            switch (key) {
                case 's':
                    circleQueue.show();
                    break;
                case 'e':
                    loop = false;
                    break;
                case 'a':
                    System.out.println("输入一个数");
                    int value = sc.nextInt();
                    circleQueue.add(value);
                    break;
                case 'g':
                    try {
                        int num = circleQueue.get();
                        System.out.println("取出的数为:"+num);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
                case 'h':
                    try {
                        int head = circleQueue.head();
                        System.out.println("头部为:"+head);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                default:
                    break;
            }
        }
        System.out.println("程序退出~");
    }
}

//提示:指针只有在添加数据或取出数据时才后移
class CircleQueue {
    private int maxSize;//容量
    private int rear;//尾
    private int front;//头
    private int[] arr;//

    public CircleQueue(int num) {
        maxSize = num;
        arr = new int[maxSize];

    }
    //判断数组已满
    public boolean isFull() {
        return (rear+1)%maxSize==front;
    }
    //判断数组为空
    public boolean isEmpty() {
        return front==rear;
    }
    //添加方法
    public void add(int num) {
        if (isFull()) {
            System.out.println("满了,添加失败");
            return;
        }
        arr[rear] = num;
        rear = (rear + 1) % maxSize;
    }
    //取出方法
    public int get() throws Exception {
        if (isEmpty()) {
            System.out.println("空的,没法取出");
            throw new Exception("数组为空,无法取出");
        }
        int value= arr[front];
        front = (front + 1) % maxSize;
        return value;
    }
    //遍历方法
    public void show() {
        if (isEmpty()) {
            System.out.println("数组为空");
            return;
        }
        for (int i = front; i < front+(rear+maxSize-front)%maxSize; i++) {
            System.out.println("arr[" + i%maxSize+"]=" + arr[i%maxSize]);
        }
    }
    //显示头部数据方法
    public int head() throws Exception {
        if (isEmpty()) {
            throw new Exception("数组为空");
        }
        return arr[front];
    }
}
举报

相关推荐

0 条评论