稀疏数组和队列

一.数据结构的分型

  数据结构包括线性结构和非线性结构

  线性结构:

    1.线性结构是最常见的数据结构,其特点是数据元素之间一对一的线性关系

    2.线性结构有两种不同的存储结构(数组)和链式存储结构(链表),顺序存储的线性表称为顺序表,顺序表中存储的元素是连续的

    3.链式存储的表称为链表,链表中的存储元素不一定是连续的,元素节点中存放数据元素以及相邻元素的地址信息

    4.线性结构常见的有:数组,队列,链表和栈

  非线性结构:

    包括二维数组,多维数组,广义表,图结构,树结构

二.稀疏数组

  

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

   稀疏数组的处理方式:

    1.记录数组中一共有几行几列,有多少个不同的值

    2.把具有不同值的元素的行列及其值记录在一个小规模的数组中,从而缩小数据的规模

   二维数组转稀疏数组

    1.遍历原始的二维数组,得到有效数据的个数

    2.根据有效数据的个数就可以创建相应的稀疏数组

    3.将二维数组的有效数据填入到稀疏数组中

public static int[][] convertSparseArray(int[][] chaseArr){
        /*
        *
        * 1.遍历原始的二维数组,得到有效数据的个数sum
        * 2.根据sum来创建稀疏数组
        * 3.将二维数组的有效数据存入到稀疏数组
        * */
        int sum = 0;
        for (int i = 0; i < chaseArr.length; i++) {
            for (int j = 0; j < chaseArr[i].length; j++) {
                if (chaseArr[i][j] != 0){
                    sum++;
                }
            }
        }
        //创建稀疏数组
        int[][] sparseArray = new int[sum+1][3]; //二维数组转稀疏数组
        // 给稀疏数组赋值
        sparseArray[0][0] = chaseArr.length;     // 原二维数组的行
        sparseArray[0][1] = chaseArr[0].length;  // 原二维数组的列
        sparseArray[0][2] = sum;                 // 原二维数组有效数据的个数

        int count = 0;
        for (int i = 0; i < chaseArr.length; i++) {
            for (int j = 0; j < chaseArr[i].length; j++) {
                if(chaseArr[i][j] != 0){
                    count++;
                    sparseArray[count][0] = i;  // 获取有效值所在的行
                    sparseArray[count][1] = j;  // 获取有效值所在的列
                    sparseArray[count][2] = chaseArr[i][j]; // 获取原数组中的有效值
                }

            }
        }
        return sparseArray;
    }

  稀疏数组还原成二维数组

    1.先读取稀疏数组的第一行,根据第一行创建原始的二维数组

    2.根据有效值,根据行列,传进二维数组

public static int[][] convertOriArrar(int[][] sparseArr){
       /*
       * 稀疏数组转二维数组
       * 1.先读取稀疏数组的第一行,根据第一行创建原始的二维数组
       * 2.在读取稀疏数组的后几行数据,并赋给原始的二维数组即可
       * */
       int row = sparseArr[0][0];
       int col = sparseArr[0][1];
       int[][] chaseArr = new int[row][col];
        for (int i = 1; i < sparseArr.length; i++) {
            chaseArr[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
        }
       return chaseArr;
    }

完整版:

public class SparseArray {
    /*从二维数组转变为稀疏数组,在由稀疏数组转变成二维数组*/

    public static void main(String[] args) {
        // 棋盘,1表示黑色,2表示白色
        int[][] chaseArr = new int[11][11];
        chaseArr[1][2] = 1;
        chaseArr[2][3] = 2;
        showArr(convertSparseArray(chaseArr));

        int[][] sparseArr = convertSparseArray(chaseArr);

        showArr(convertOriArrar(sparseArr));

    }

    public static int[][] convertOriArrar(int[][] sparseArr){
       /*
       * 稀疏数组转二维数组
       * 1.先读取稀疏数组的第一行,根据第一行创建原始的二维数组
       * 2.在读取稀疏数组的后几行数据,并赋给原始的二维数组即可
       * */
       int row = sparseArr[0][0];
       int col = sparseArr[0][1];
       int[][] chaseArr = new int[row][col];
        for (int i = 1; i < sparseArr.length; i++) {
            chaseArr[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
        }
       return chaseArr;
    }

    public static int[][] convertSparseArray(int[][] chaseArr){
        /*
        *
        * 1.遍历原始的二维数组,得到有效数据的个数sum
        * 2.根据sum来创建稀疏数组
        * 3.将二维数组的有效数据存入到稀疏数组
        * */
        int sum = 0;
        for (int i = 0; i < chaseArr.length; i++) {
            for (int j = 0; j < chaseArr[i].length; j++) {
                if (chaseArr[i][j] != 0){
                    sum++;
                }
            }
        }
        //创建稀疏数组
        int[][] sparseArray = new int[sum+1][3]; //二维数组转稀疏数组
        // 给稀疏数组赋值
        sparseArray[0][0] = chaseArr.length;     // 原二维数组的行
        sparseArray[0][1] = chaseArr[0].length;  // 原二维数组的列
        sparseArray[0][2] = sum;                 // 原二维数组有效数据的个数

        int count = 0;
        for (int i = 0; i < chaseArr.length; i++) {
            for (int j = 0; j < chaseArr[i].length; j++) {
                if(chaseArr[i][j] != 0){
                    count++;
                    sparseArray[count][0] = i;  // 获取有效值所在的行
                    sparseArray[count][1] = j;  // 获取有效值所在的列
                    sparseArray[count][2] = chaseArr[i][j]; // 获取原数组中的有效值
                }

            }
        }
        return sparseArray;
    }

    public static void showArr(int[][] arr){
        for (int[] row : arr) {
            for (int i : row) {
                System.out.printf("%d\t",i);
            }
            System.out.println();
        }

    }
}

三.队列

  1.队列是一个有序的列表,可以用数组或链表来实现

  2.遵循先进先出的原则

 

   3.数组模拟队列思路

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

    因为队列的输出,输入分别从前后端来处理,因此需要front和rear两个变量分别记录队列前后端的下标,front会随着输出而改变,rear会随着输入而改变

  示意图:

class ArrayQueue{
    //模拟数组队列的实现类
    private int maxSize;
    private int front;  // 指向头部的指针,指向第一个元素的前一个位置
    private int rear;   // 指向尾部的指针,指向队列的最后一个元素
    private int[] arr;

    public ArrayQueue(int maxSize){

        this.maxSize = maxSize;
        front = -1;
        rear = -1;
        arr = new int[maxSize];
    }

    /*判断队列是否为空*/
    public boolean isEmpty(){

        return front == rear;
    }

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

    /*添加元素到队列中*/
    public void addElement(int e){
        if(isFull()){
            System.out.println("队列已满,不能添加元素");
            return;
        }
        rear++;   // 尾部指针后移
        arr[rear] = e; //添加元素到队列中
    }

   /*获取队列中的元素*/
    public int getElement(){
        if (isEmpty()){
            throw new RuntimeException("队列为空,不能取数据");
        }
        front++; // 头指针后移
        return arr[front]; // 获取元素
    }

    /*打印队列中的元素*/
    public void show(){
        if (isEmpty()){
            System.out.println("队列为空,没有数据");
            return;
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.printf("arr[%d]=%d\n",i,arr[i]);
        }
    }

    /*打印队列的头部元素*/
    public int getHeadElement(){
        if (isEmpty()){
            throw new RuntimeException("队列为空,没有数据");
        }
        return arr[front+1];
    }

}
public static void main(String[] args) {
        testArrayQueue();//测试代码

    }

    public static void testArrayQueue(){
        // 初始化队列的元素,3个
        ArrayQueue queue = new ArrayQueue(3);
        boolean loop = true;
        char key = ‘ ‘;
        Scanner scanner = new Scanner(System.in);
        while (loop){
            System.out.println("请输入队列的操作,s(show)\te(exit)\ta(add)\tg(get)\th(head)");
            //获取用户的输入操作
            key = scanner.next().charAt(0);
            switch (key){
                case ‘s‘:
                    queue.show();
                    break;
                case ‘a‘:
                    int value = scanner.nextInt();
                    queue.addElement(value);
                    break;
                case ‘g‘:
                    int res = queue.getElement();
                    System.out.println("取出的数是:"+res);
                    break;
                case ‘h‘:
                    int head = queue.getHeadElement();
                    System.out.println("队列的头元素是:"+head);
                    break;
                case ‘e‘:
                    scanner.close();
                    loop = false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出");
    }

执行结果:

队列无法复用,只能用一次,不能再次使用

4.改进

  使用环形队列(通过取模的方式来实现)

5.思路

  front指向队列中的第一个元素,arr[front]就是队列的第一个元素,初始值是0

  rear指向队列的最后一个元素,arr[rear],就是队列的最后一个元素,需要预留出约定的空间

  队列满时的条件:(rear+1)%maxSize == front

  队列为空的条件: front == rear

  队列中的有效个数:(rear+maxSize-front)%maxSize

class CircleArray{
    /*
    * 1.front指向队列的第一个元素,也就是说arr[front]就是队列的第一个元素,front的初始值是0
    * 2.rear指向队列的最后一个元素的后一个位置,要预留出一个空间作为约定
    * 3.当队列满的时候(rear+1)%maxSize == front
    * 4.队列中的有效的数据个数(rear+maxSize-front)%maxSize
    *
    * */
    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 isEmpty(){
        return front == rear;
    }

    /*判断队列是否已满*/
    public boolean isFull(){
        return (rear+1) % maxSize == front;
    }
    /*添加元素*/
    public void addElement(int e){
        if (isFull()){
            System.out.println("队列已满,不能在添加元素");
            return;
        }
        arr[rear] = e;// 直接加入数据
        rear = (rear +1)%maxSize; //取模来实现环形例rear=1,maxSize=3

    }

   /*获取队列元素*/
    public int getElement(){
        if (isEmpty()){
            throw new RuntimeException("队列为空,不能获取元素");
        }
        int v = arr[front]; // 把front对应的值保存到临时变量中
        front = (front+1)%maxSize; // front指针取模,后移
        return v;  // 将临时变量返回
    }

    /*打印输出队列*/
    public void show(){
        if (isEmpty()){
            System.out.println("队列为空,没有数据");
            return;
        }
        // 从front开始遍历,遍历队列中的有效元素的个数
        for (int i = front; i < front+size(); i++) {
            System.out.printf("arr[%d]=%d\n",(i%maxSize),arr[i%maxSize]);
        }
    }
   /*查看队列的第一个元素*/
    public int getHeadElement(){
        if (isEmpty()){
            throw new RuntimeException("队列为空,不能打印队列");
        }
        return arr[front];
    }

    public int size(){
        //例如: rear=2,front=1,maxSize=3  带入 有效的元素个数为1
        return (rear+maxSize-front)%maxSize;
    }
}
 public static void main(String[] args) {
        testCircleQueue();
    }

    public static void testCircleQueue(){
        CircleArray circle = new CircleArray(4);
        boolean loop =true;
        char key = ‘ ‘;
        Scanner scanner = new Scanner(System.in);
        while (loop){
            System.out.println("请输入队列的操作,s(show)\te(exit)\ta(add)\tg(get)\th(head)");
            key = scanner.next().charAt(0);
            switch (key){
                case ‘s‘:
                    circle.show();
                    break;
                case ‘a‘:
                    circle.addElement(scanner.nextInt());
                    break;
                case ‘g‘:
                    System.out.println("取出的队列元素是:"+circle.getElement());
                    break;
                case ‘h‘:
                    System.out.println("队列的头部元素是:"+circle.getHeadElement());
                    break;
                case ‘e‘:
                    scanner.close();
                    loop = false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出");
    }

运行结果:

可以实现队列的复用

  

   

原文地址:https://www.cnblogs.com/luhuajun/p/12228252.html

时间: 2024-08-26 15:31:16

稀疏数组和队列的相关文章

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

目录 稀疏数组和队列 1.稀疏数组 1.1 解决方法 1.2 代码实现 2. 队列 2.1 数组模拟队列 2.2 数组模拟环形队列 稀疏数组和队列 1.稀疏数组 所谓稀疏数组就是当数组中大部分的内容值都未被使用(或都为零),在数组中仅有少部分的空间使用.因此造成内存空间的浪费,为了节省内存空间,并且不影响数组中原有的内容值,我们可以使用稀疏数组去压缩数据.OK,如果你不明白,那我们来看一个例子. ? 在一个五子棋中,有存盘和续上盘的功能 分析问题:因为该二维数组的很多默认值是 0,因此记录了很多

稀疏数组与环形数组

数据结构与算法的关系 数据结构(data structure)是一门研究组织数据方式的学科,有了编程语言也就有了数据结构.学好数据结构可以编写出跟家漂亮,更加有效率的代码 要学好数据结构就要多多考虑如何将生活中遇到的问题,用程序去实现解决 程序=数据结构+算法 数据结构是算法的基础,换言之,想要学好算法,需要把数据结构学到位 数据结构包括:线性结构和非线性结构 线性结构: 线性结构作为最常用的数据结构,其特点是数据元素之间存在一对一的线性关系(a[0]=30) 线性结构有两种不同的存储结构,即顺

重学数据结构 --- 分类+稀疏数组

一.数据结构的分类 1. 数据结构两大类 线性结构和非线性结构 1) 线性结构 线性结构是最常见的数据结构,特点是元素间存在一对一的线性关系. 线性结构又分两种,一种是顺序存储(称为顺序表),另外一种是链式存储(称为链表).顺序表中的存储元素的连续的.链表中的存储元素不一定是连续的,元素节点中存放数据元素以及相邻元素的地址信息. 常见的线性结构有:数组.队列.链表和栈(这里只是讲个大概,具体内容后面的文章会展开阐述). 2) 非线性结构 非线性结构就是结点元素可能存在多个直接前趋和多个直接后续(

Android 性能优化之稀疏数组SparseArray&lt;E&gt;

SparseArray<E> 就是对数组的压缩,用一种压缩方式来表示数组. 在我们定义数组的时候 ,数组中 有时候会有大部分内容 未被使用(或为0),造成内存控件的浪费.为了节省内存控件,且不影响数组中原有的数据,我们就采用了一种压缩方式来表示数组.   图中黄色显示的是我们使用了的元素,这里其他 元素都被浪费了 .来看看 用 稀疏 数组 表示的 方法 稀疏数组的 第一部分 表示了 数组的行数 .列数.以及元素使用的个数.第二部分 记录了 使用了的 元素在 原数组中的 位置 及 内容 . Sp

javascript中的稀疏数组(sparse array)和密集数组

学习underscore.js数组相关API的时候,遇到了sparse array这个东西,以前没有接触过. 这里学习下什么是稀疏数组和密集数组. 什么是密集数组呢?在java和C语言中,数组是一片连续的存储空间,有着固定的长度.加入数组其实位置是address,长度为n,那么占用的存储空间是address[0],address[1],address[2].......address[n-1].即数组元素之间是紧密相连的,不存在空隙.如下的js代码创建的就是一个密集数组 var data = [

数组的队列和栈方法

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>数组的队列和栈方法</title></head><body><script>// 栈是一种LIFO(Last-In-First-Out后进先出)的数据结构,js中的push()和pop()类似栈的行为// 队列是一种FIFO(

【Weiss】【第03章】练习3.25:数组模拟队列

[练习3.25] 编写实现队列的例程,使用 a.链表 b.数组 Answer: 在这章一开头就已经写了个链表的队列例程了,所以实际上只要做b小题就可以. 数组模拟队列和链表的两点小不同是: ①.数组空间有限,入队需要检测数组是否已经满 ②.数组经过几次操作后,rear可能绕回front前面,所以许多操作都要用模来实现. 测试代码: 1 #include <iostream> 2 #include "queue.h" 3 using namespace std; 4 usin

技术文章-数组与队列

在Java编程中,常常会遇到需要存储和处理大量同类信息的时候,这时候就要运用数组或者队列的数据存储结构来方便操作. 1.数组 定义:数组是属于数据结构中一种线性的数据结构,因为其对象在内存中的存储方式是一个连续的存储空间. 数组在使用时的书写格式:(以一维数组为) 定义和实例化对象同步进行: 已知存储数据的类型和长度时:数据类型 [] 数组名 = new 数据类型[长度]; 已经知道具体的每一项数据时:数据类型 [] 数组名 = {数据,...}; 已经知道具体的每一项数据同时规定数据类型时:数

08.18 javascript 06 数组 数组的概念 创建数组 读取数组中的元素 稀疏数组 添加和删除数组的元素 数组遍历 多维数组 数组的方法 类数组对象 作为数组的字符串

# 数组 ### 数组的概念 * 数组是值的有序集合 * 数组中的每个值 称之为 元素 * 每个元素可以是任意数据类型的值 * 每个元素都有索引(下标) * 元素的索引从0开始,按照顺序递增. 元素最大的索引 2^32-2 ### 创建数组 * 直接量 `[]` * 构造函方式  `new Array()` ### 读写数组中的元素 * 数组名[索引] ### 稀疏数组 * js数组的索引是连续的 * 没有连续的给元素赋值 , 没有赋值的元素会自动赋值 undefined ### 添加和删除 数