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

目录

  • 稀疏数组和队列

    • 1.稀疏数组

      • 1.1 解决方法
      • 1.2 代码实现
    • 2. 队列
      • 2.1 数组模拟队列
      • 2.2 数组模拟环形队列

稀疏数组和队列

1.稀疏数组

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

?

在一个五子棋中,有存盘和续上盘的功能

分析问题:因为该二维数组的很多默认值是 0,因此记录了很多没有意义的数据 > 稀疏数组

?

1.1 解决方法

思路

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

    ?

应用实例

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

?

1.2 代码实现

public class SparseArray {
    public static void main(String[] args) {
        //创建一个二维数组
        //0:表示没有棋子 1表示黑子 2表示蓝子
        int chessArr[][] = new int[11][10];
        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();
        }

        int[][] array = getSparseArray(chessArr);
        System.out.println("-------");
        for(int i = 0 ; i< array.length;i++){
            System.out.printf("%d\t%d\t%d\t\n",array[i][0],array[i][1],array[i][2]);
        }
        System.out.println("--------");
        int[][] startArr = recovery(array);
        for(int[] row:startArr){
            for(int data:row){
                System.out.printf("%d\t",data);
            }
            System.out.println();
        }
    }

    /**
     * 将普通数组转换为稀疏数组
     * @param chessArr
     * @return
     */
    public static int[][] getSparseArray(int[][] chessArr){
        if(!checkIsRight(chessArr)){
            return null;
        }

        //1.拿到数组后 首先获取元素的个数,然后才能建立稀疏数组
        int sum = 0;
        for(int[] arr:chessArr){
            for(int i:arr){
                if(i != 0){
                    sum++;
                }
            }
        }

        //2.建立稀疏数组
        int[][] sparseArr = new int[sum+1][3];
        sparseArr[0][0] = chessArr.length; //行
        sparseArr[0][1] = chessArr[0].length;//列
        sparseArr[0][2] = sum; //元素个数

        //3.数组存放
        int count = 0;
        for(int i = 0; i <chessArr.length; i++ ){
            for(int j = 0; j <chessArr[i].length;j++ ){
                if(chessArr[i][j] != 0){
                    sparseArr[++count][0] = i;//行
                    sparseArr[count][1] = j;//列
                    sparseArr[count][2] = chessArr[i][j];
                }
            }
        }

        return sparseArr;
    }

    /**
     * 将稀疏数组转回普通数组
     * @param sparseArr
     * @return
     */
    public static int[][] recovery(int[][] sparseArr){
        if(!checkIsRight(sparseArr)){
            return null;
        }   

        //获取原数组的 行数和列数 并创建原数组
        int arr[][] = new int[sparseArr[0][0]][sparseArr[0][1]];

        for(int i = 1; i < sparseArr.length;i++){
            arr[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
        }

        return arr;
    }

    public static boolean checkIsRight(int[][] arr){
        if(arr == null || arr.length <= 1 ){
            return false;
        }
        return true;
    }

}

?

2. 队列

  • 队列是一个有序列表,可以用数组或链表来实现
  • 遵循先入先出的原则

?

2.1 数组模拟队列

  • 队列本身是有序列表,若使用数组的数据结构来存储队列的数据,则队列的数组声明如上图,其中maxSize是该队列的最大容量
  • 因为队列的输出、输入分别从头尾端来处理,因此需要两个变量front及rear分别记录队列头尾端的下标,front会随着数据输出而改变,而rear会随着队列的输入而改变
  • 当我们将数据输入队列时称为 addQueueaddQueue的处理有两个步骤:思路分析

(1) 将尾指针往后移:rear+1,当front == rear [空]

(2) 若尾指针rear小于队列的最大下标 maxSize - 1,则数据输入rear 所指的数组元素中,否则无法存入数据。

rear == maxSize - 1

代码实现

public class ArrayQueueDemo {
    public static void main(String[] args) {
        ArrayQueue queue = new ArrayQueue(10);
        queue.addQueue(1);
        queue.addQueue(2);
        queue.addQueue(3);
        queue.addQueue(4);
        queue.getQueue();
        queue.showQueue();
    }
}
//使用数组模拟队列-编写一个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];
        this.front = -1;
        this.rear = -1;
    }

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

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

    //添加数据到队列
    public void addQueue(int n){
        //判断队列是否满
        if(isFull()){
            System.out.println("队列已满");
            return;
        }

        arr[++rear] = n;
    }

    //获取队列的数据,出队列
    public int getQueue(){
        if(isEmpty()){
            throw new RuntimeException("队列已空");
        }
        return arr[++front];
    }

    //显示队列所有数据
    public void showQueue(){
        if(isEmpty()){
            System.out.println("队列已空");
            return;
        }

        for(int i = front+1 ;i <= rear;i++){
            System.out.printf("arr[%d]=%d\n",i,arr[i]);
        }
    }
}

?

2.2 数组模拟环形队列

之前实现的队列存在一个明显的问题,就是数组使用一次就不能再用了,出队列数据的位置始终空在那,没有达到一个复用的效果,因此我们要对这个队列进行一次优化,将此队列变成一个环形队列

思路

  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
  6. 我们就可以在原来的队列上修改得到 一个环形队列

?

代码实现

public class CircleArrayQueueDemo {
    public static void main(String[] args) {
        //测试一把
        System.out.println("测试数组模拟环形队列的案例");

        //创建一个环形队列 说明设置4,其队列数据最大是3
        CircleArray queue = 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':
                queue.showQueue();
                break;
            case 'a':
                System.out.println("输出一个数字");
                int value = scanner.nextInt();
                queue.addQueue(value);
                break;
            case 'g':
                try {
                    int res = queue.getQueue();
                    System.out.printf("取出的数据是%d\n",res);
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                }
                break;
            case 'h'://查看队列头的数据
                try {
                    int res = queue.headQueue();
                    System.out.printf("队列头的数据是%d\n",res);
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                }
                break;
            case 'e'://退出
                scanner.close();
                loop = false;
                break;
            default:
                break;
            }
        }
    }
}
class CircleArray{
    private int maxSize;
    private int front;
    private int rear;
    private int[] arr;

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

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

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

    //添加数据到队列
    public void addQueue(int n){
        //判断队列是否已满
        if(isFull()){
            System.out.println("队列满,不能加入数据");
            return;
        }
        //直接将数据加入
        arr[rear] = n;
        //将rear后移,这里必须考虑取模
        rear = (rear+1)%maxSize;
    }

    //获取队列的数据
    public int getQueue(){
        //判断队列是否为空
        if(isEmpty()){
            //通过抛出异常
            throw new RuntimeException("队列为空,不能取数据");
        }
        int value = arr[front];
        front = (front+1)%maxSize;
        return value;
    }

    //显示队列的所有数据
    public void showQueue(){
        //遍历
        if(isEmpty()){
            System.out.println("队列为空,没有数据");
            return;
        }

        for(int i = front; i < front + size() ; i++){
            System.out.printf("arr[%d]=%d\n",i%maxSize,arr[i%maxSize]);
        }

    }

    //求出当前队列有效数据的个数
    public int size(){
        //加上maxSize 防止模出负数 因为这是一个环形队列
        return (rear + maxSize - front)%maxSize;
    }

    //显示队列的头数据
    public int headQueue(){
        //判断
        if(isEmpty()){
            throw new RuntimeException("队列是空的,~没有数据");
        }
        return arr[front];
    }

}

原文地址:https://www.cnblogs.com/dwlovelife/p/11191444.html

时间: 2024-11-06 17:58:13

数据结构与算法—稀疏数组和队列的相关文章

JAVA数据结构与算法-稀疏数组

实际需求 分析问题 因为该二维数组的很多值是默认值0, 因此记录了很多没有意义的数据.->稀疏数组. 1.基本介绍 当一个数据中大部分元素为0,或者同一个值的数组时,可以使用稀疏数组来保存该数组稀疏数组处理方法 1.记录数组一共有几行几列,有多少不同的值 2.把具有不同的值的元素的行列及值记录在一个小规模的数组中,从而去缩小程序规模 稀疏数组说明 2.应用实例 使用稀疏数组,来保留类似前面的二维数组(棋盘.地图等等) 把稀疏数组存盘,并且可以从新恢复原来的二维数组数 整体思路分析 3.加了比较多

《数据结构与算法》-3-栈和队列

目录 1. 栈 1.1 栈的基本概念 1.2 栈的顺序存储结构 1.3 栈的链式存储结构 2. 队列 2.1 队列的基本概念 2.2 队列的顺序存储结构 2.3 队列的链式存储结构 2.4 双端队列 3. 栈和队列的应用 3.1 栈在括号匹配中的应用 3.2 栈在表达式求值中的应用 3.3 栈对递归中的应用 3.4 队列在层次遍历中的应用 3.5 队列在计算机系统中的应用 4. 特殊矩阵的压缩存储 4.1 数组的定义 4.2 数组的存储结构 4.3 矩阵的压缩存储 ? 该系列博客的目的是为了学习

Java数据结构和算法之栈与队列

二.栈与队列 1.栈的定义 栈(Stack)是限制仅在表的一端进行插入和删除运算的线性表. (1)通常称插入.删除的这一端为栈顶(Top),另一端称为栈底(Bottom). (2)当表中没有元素时称为空栈. (3)栈为后进先出(Last In First Out)的线性表,简称为LIFO表. 栈的修改是按后进先出的原则进行. 每次删除(退栈)的总是当前栈中"最新"的元素,即最后插入(进栈)的元素,而最先插入的是被放在栈的底部,要到最后才能删除. 图1 [示例]元素是以a1,a2,-,a

Java数据结构和算法之数组与简单排序

一.数组于简单排序 数组 数组(array)是相同类型变量的集合,可以使用共同的名字引用它.数组可被定义为任何类型,可以是一维或多维.数组中的一个特别要素是通过下标来访问它.数组提供了一种将有联系的信息分组的便利方法. 一维数组 一维数组(one‐dimensional array )实质上是相同类型变量列表.要创建一个数组,你必须首先定义数组变量所需的类型.通用的一维数组的声明格式是: type var‐name[ ]; 获得一个数组需要2步: 第一步,你必须定义变量所需的类型. 第二步,你必

Java数据结构与算法之数组

数组特点: 1.大小固定 2.同一数据类型 3.下标访问 4.数据项可重复 Java数据类型:基本类型(int和double)和对象类型.在许多编程语言中,数组也是基本类型.但在Java中把它们当作对象来对待,因此在创建数组时必须使用new操作符. 有序数组与无序数组比较:最主要的好处是查找速度比无序数组快多了.不好的方面是在插入操作中由于所有靠后的数据都需要移动以疼开空间,所以速度较慢.有序数组和无序数组数据中的删除操作都很慢,这是因为数据项必须向前移动来填补已删除数据项的空洞. 数据访问:从

JAVA描述算法和数据结构(01):稀疏数组和二维数组转换

一.基本简介 1.基础概念 在矩阵中,若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律时,则称该矩阵为稀疏矩阵:与之相反,若非0元素数目占大多数时,则称该矩阵为稠密矩阵.定义非零元素的总数比上矩阵所有元素的总数为矩阵的稠密度. 2.处理方式 1).记录数组一共有几行几列,有多少个不同的值 2).把具有不同值的元素的行列及值记录在稀疏数组中,可以缩小程序代码的复杂度. 3.图解描述 稀疏数组表示 [0] 3 4 4 二维数组,3行,4列,4个非0的值: [1] 1 2 2 一行

稀疏数组和队列

一.数据结构的分型 数据结构包括线性结构和非线性结构 线性结构: 1.线性结构是最常见的数据结构,其特点是数据元素之间一对一的线性关系 2.线性结构有两种不同的存储结构(数组)和链式存储结构(链表),顺序存储的线性表称为顺序表,顺序表中存储的元素是连续的 3.链式存储的表称为链表,链表中的存储元素不一定是连续的,元素节点中存放数据元素以及相邻元素的地址信息 4.线性结构常见的有:数组,队列,链表和栈 非线性结构: 包括二维数组,多维数组,广义表,图结构,树结构 二.稀疏数组 当一个数组中大部分元

数据结构与算法系列七(队列)

1.引子 1.1.为什么要学习数据结构与算法? 有人说,数据结构与算法,计算机网络,与操作系统都一样,脱离日常开发,除了面试这辈子可能都用不到呀! 有人说,我是做业务开发的,只要熟练API,熟练框架,熟练各种中间件,写的代码不也能“飞”起来吗? 于是问题来了:为什么还要学习数据结构与算法呢? #理由一: 面试的时候,千万不要被数据结构与算法拖了后腿 #理由二: 你真的愿意做一辈子CRUD Boy吗 #理由三: 不想写出开源框架,中间件的工程师,不是好厨子 1.2.如何系统化学习数据结构与算法?

Java数据结构和算法(二)——数组

数组的用处是什么呢?--当你需要将30个数进行大小排列的时候,用数组这样的数据结构存储是个很好的选择,当你是一个班的班主任的时候,每次要记录那些学生的缺勤次数的时候,数组也是很有用.数组可以进行插入,删除,查找等. 1)创建和内存分配 Java中有两种数据类型,基本类型和对象类型,也有人称为引用类型,Java中把数组当成对象,创建数组时使用new操作符. int array[] = new int[10]; 既然是对象,那么array便是数组的一个引用,根据Java编程思想(一) -- 一切都是