算法与数据结构(Java版)01-稀疏数组和队列详解及代码实现

1 稀疏数组

  • 所谓稀疏数组就是当数组中大部分的内容值都未被使用(或都为零),在数组中仅有少部分的空间使用。因此造成内存空间的浪费,为了节省内存空间,并且不影响数组中原有的内容值,我们可以使用稀疏数组去压缩数据。

1.1 稀疏数组的应用场景

在这里插入图片描述

1.2 稀疏数组的基本介绍

  • 当一个数组中大部分元素为0,或者为同一个数值时,可以使用稀疏数组来保存该数组
  • 稀疏数组的处理方法
    • 记录数组一共有几行几列,有多少个不同的值
    • 把具有不同值的元素的行列及记录在一个小规模的数组中从而缩小程序的规模

在这里插入图片描述

1.3 稀疏数组的应用

在这里插入图片描述

  • 将二维数组转换成稀疏数组
    • 遍历原有的二维数组,得知有效数据数据的总个数
    • 根据有效数据个数来创建稀疏数组 [有效数组+1]
    • 将二维数组中的有效数据存入到稀疏数组中
    • 将稀疏数组通过IO写入磁盘
  • 稀疏数组转成原始的二维数组
    • 从磁盘中读取到稀疏数组,根据第一行的数据,创建原始的二维数组 如上图 int [15] [15]
    • 在读取稀疏数组中剩余几行的数据,赋给二维数组即可

1.4 稀疏数组代码实现

1.4.1 创建二维数组并赋予初始值

/**
     * 二维数组初始化
     *
     * <p>
     *     这里模拟定义一个15*15的五子棋棋盘,并已知棋盘中已存在两个棋子
     *     来创建一个[15][15]的二维数组
     * </p>
     * @param
     * @return int[][]
     * @author ZhangSan_Plus
     * @description //TODO
     * @date 15:22 2022/4/15
     **/
    public static int[][] twoDimensionalGoBang() {
        int goBang[][] = new int[15][15];
        goBang[3][3] = 1;
        goBang[4][4] = 2;
        return goBang;
    }
复制代码

1.4.2 将原有的二维数组转化为稀疏数组

/**
     * 二维数组转成稀疏数组
     *
     * <p>
     *     1.首先遍历原有的二维数组,得知原二维数组有效数据的总个数
     *     2.根据得知的有效数据来创建稀疏数组 [有效数据+1]
     *     3.将二维数据中有效数据的位置和值放到稀疏数组中
     * </p>
     * @param
     * @return int[][]
     * @author ZhangSan_Plus
     * @description //TODO
     * @date 15:37 2022/4/15
     **/
    public static int[][] twoDimensionalToSparse() {
        //创建一个原始的二位数组
        int[][] goBang = twoDimensionalGoBang();
        //1.遍历原有的二维数组,得知有效数据数据的总个数
        int valid = 0;
        for (int i = 0; i < goBang.length; i++) {
            for (int j = 0; j < goBang.length; j++) {
                if (goBang[i][j] != 0) {
                    valid++;
                }
            }
        }
        //2.根据有效数据来创建稀疏数组
        int[][] sparse = new int[valid + 1][valid + 1];
        sparse[0][0] = goBang.length;
        sparse[0][1] = goBang.length;
        sparse[0][2] = valid;
        int count = 0;
        for (int i = 0; i < goBang.length; i++) {
            for (int j = 0; j < goBang.length; j++) {
                if (goBang[i][j] != 0) {
                    count++;
                    sparse[count][0] = i;
                    sparse[count][1] = j;
                    sparse[count][2] = goBang[i][j];
                }
            }
        }
        return sparse;
    }
复制代码

1.4.3 将稀疏数组转化为原来的二维数组

	public static void main(String[] args) {
        /**
         * <p>
         *     1.根据稀疏数组的特性已知其第一行存放为 二维数组的 行、列、值
         *     2.除第一行以外的数据其余存放的则是有效数据的 行、列、值
         * </p>
         */
        int[][] sparse = twoDimensionalToSparse();
        int[][] two = new int[sparse[0][0]][sparse[0][1]];
        for (int i = 1; i < sparse.length; i++) {
            //稀疏数组的第i行第0,1列为二维数组所在的位置 稀疏数组的第2列则为二维数组的值
            two[sparse[i][0]][sparse[i][1]] = sparse[i][2];
        }
        traverse(two);
    }
复制代码

1.4.4 遍历二维数组

/**
     * 二维数组遍历
     *
     * @param array 二维数组
     * @return void
     * @author ZhangSan_Plus
     * @description //TODO
     * @date 15:22 2022/4/15
     **/
    public static void traverse(int[][] array) {
        for (int[] row : array) {
            for (int data : row) {
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }
    }
复制代码

2 队列

  • 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

请添加图片描述

2.1 队列的应用场景

  • 如:银行存款取款等、医院的叫号等都算是队列

2.2 队列的基本介绍

  • 队列是一个有序列表,可以使用数组或者链表来实现
  • 遵循先入先出的原则,即:先存入队列的数据要先取出,后存入的后取出

2.3 单向队列模拟实现

2.3.1 使用数组来模拟实现队列

public class ArrayImitateQueue {
    /**
     * 数组最大容量
     */
    private int maxSize;
    /**
     * 队列头
     */
    private int front;
    /**
     * 队列尾
     */
    private int rear;
    /**
     * 存放数据
     */
    private int[] arr;

    public ArrayImitateQueue(int maxSize) {
        this.maxSize = maxSize;
        arr = new int[maxSize];
        //指向队列头的前一个位置
        front = -1;
        //指向队列尾
        rear = -1;
    }

    /**
     * 判断队列是否已满
     *
     * @param
     * @return boolean
     * @author ZhangSan_Plus
     * @description //TODO
     * @date 16:43 2022/4/15
     **/
    public boolean isFull() {
        return rear == maxSize - 1;
    }

    /**
     * 判断队列是否为空
     *
     * @param
     * @return boolean
     * @author ZhangSan_Plus
     * @description //TODO
     * @date 16:44 2022/4/15
     **/
    public boolean isEmpty() {
        return rear == front;
    }

    /**
     * 向队列中添加数据
     *
     * @param num
     * @return void
     * @author ZhangSan_Plus
     * @description //TODO
     * @date 16:46 2022/4/15
     **/
    public void addQueue(int num) {
        if (isFull()) {
            System.err.println("队列已满不能添加数据");
            return;
        }
        rear++;
        arr[rear] = num;
    }

    /**
     * 取出队列中的值
     *
     * @param
     * @return int
     * @author ZhangSan_Plus
     * @description //TODO
     * @date 16:50 2022/4/15
     **/
    public int getQueue() {
        if (isEmpty()) {
            throw new RuntimeException("ERROR:index out of bounds");
        }
        front++;
        return arr[front];
    }

    /**
     * 显示队列中全部内容
     *
     * @param
     * @return void
     * @author ZhangSan_Plus
     * @description //TODO
     * @date 16:50 2022/4/15
     **/
    public void showQueue() {
        if (isEmpty()) {
            System.err.println("Queue is Null~");
            return;
        }
        for (int i : arr) {
            System.out.println(i);
        }
    }

    /**
     * 获取队列的头数据
     *
     * @param
     * @return int
     * @author ZhangSan_Plus
     * @description //TODO
     * @date 16:52 2022/4/15
     **/
    public int getFirstQueue() {
        if (isEmpty()) {
            throw new RuntimeException("ERROR:index out of bounds");
        }
        return arr[front + 1];
    }
}

复制代码

2.3.2 使用链表来模拟实现队列

public class ChainImitateQueue<T> {
    private Node first;
    private Node last;
    private int n;

    /**
     * 在链表中添加数据
     *
     * @param item
     * @return void
     * @author ZhangSan_Plus
     * @description //TODO
     * @date 17:09 2022/4/15
     **/
    public void addQueue(T item) {
        //在链表尾部插入结点
        Node oldLast = last;
        last = new Node();
        last.item = item;
        last.next = null;
        if (isEmpty()) {
            //队列插入第一个元素
            first = last;
        } else {
            oldLast.next = last;
        }
        n++;
    }

    /**
     * 删除链表中的头数据
     *
     * @param
     * @return T
     * @author ZhangSan_Plus
     * @description //TODO
     * @date 17:10 2022/4/15
     **/
    public T removeQueue() {
        //在链表表头删除结点,(对单链表而言,不好删除表尾结点)
        if (isEmpty()) {
            //删除队列中最后一个元素
            throw new RuntimeException("ERROR: There is no more data in the queue to delete");
        }
        T item = first.item;
        first = first.next;
        n--;
        return item;
    }

    /**
     * 判断列表是否为空
     *
     * @param
     * @return boolean
     * @author ZhangSan_Plus
     * @description //TODO
     * @date 17:10 2022/4/15
     **/
    public boolean isEmpty() {
        return n == 0 ? true : false;
    }

    /**
     * 获取列表的长度
     *
     * @param
     * @return int
     * @author ZhangSan_Plus
     * @description //TODO
     * @date 17:11 2022/4/15
     **/
    public int size() {
        return n;
    }


    class Node {
        Node next;
        T item;
    }

    public static void main(String[] args) {
        ChainImitateQueue<Integer> queue = new ChainImitateQueue<>();
        queue.addQueue(10);
        queue.addQueue(100);
        System.out.println(queue.size());
        System.out.println(queue.removeQueue());
        System.out.println(queue.removeQueue());
        System.out.println(queue.size());
        System.out.println(queue.removeQueue());
    }
}
复制代码

2.4 环形队列模拟实现

猜你喜欢

转载自juejin.im/post/7087787258555662344