Java数据结构之稀疏数组和队列

稀疏数组:

应用场景,实际的需求:

编写五子棋程序中,有存档退出和保存上一句的功能。

实现:

用0代表还没有下的位置,用1代表黑子,用2代表白子。使用二维数组记录棋盘。

分析问题:

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

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

稀疏数组的处理方法是:

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

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

二维数组转稀疏数组的思路:

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

2、根据sum就可以创建稀疏数组spareseArr intsum+1

3、将二维数组的有效数据存入到稀疏数组中

棋盘的稀疏数组:
row col val
0 11 11 2
1 1 2 1
2 2 3 2

第一行代表:棋盘的大小,11*11的二维数组,有2个有效位置。

第二行代表:row代表有效位置的行,col代表有效位置的列,val代表该位置的数:

第三行代表:第二个有效数字的位置和它的值。

//稀疏数组和五子棋盘
public class test01 {
    public static void main(String[] args) {
        //创建一个原始的二维数组11*11棋盘
        //0表示该位置没有棋子,1代表白棋,2代表黑棋
        int chessArr[][] = new int[11][11];
        //代表该棋盘第二行第三列含有一颗白棋
        chessArr[1][2] = 1;
        //代表该棋盘第三行第三列含有一颗黑棋
        chessArr[2][3] = 2;
        System.out.println("原始的二维数组~~");
        for(int row[]:chessArr) {
            for(int data: row) {
                System.out.printf("%d\t",data);
            }
            System.out.println();
        }
        //将二维数组转化成稀疏数组的思想
        //先遍历二维数组,获得非0数据的个数
        int sum = 0;
        for(int i =0 ; i < 11 ; i++) {
            for(int j = 0 ; j < 11 ; j++) {
                if(chessArr[i][j] != 0) {
                    sum++;
                }
            }
        }
        System.out.println("原始二维数组的有效数字个数"+sum);
        //创建稀疏数组,遍历原始二维数组的数据,存入稀疏数组中
        int xishuArr[][] = new int[sum+1][3];
        //存入稀疏数组的第一行
        xishuArr[0][0] = 11;
        xishuArr[0][1] = 11;
        xishuArr[0][2] = sum;
        int count = 0;
        for(int i =0 ; i < 11 ; i++) {
            for(int j = 0 ; j < 11 ; j++) {
                if(chessArr[i][j] != 0) {
                    count++;
                    //有效数据从稀疏数组的第二行开始存放
                    xishuArr[count][0] = i;
                    xishuArr[count][1] = j;
                    xishuArr[count][2] = chessArr[i][j];
                }
            }
        }
        //输出稀疏数组
        for(int chess[]:xishuArr) {
            for(int a:chess) {
                System.out.printf("%d\t",a);
            }
            System.out.println();
        }
        /*  稀疏数组转二维数组的思路:
            1、先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组。
            2、再读取稀疏数组后几行数据,并赋予原始二维数组即可。
        */
        int chessArr2[][] = new int[xishuArr[0][0]][xishuArr[0][1]];
        //注意这里的xishuArr.length计算的就是稀疏数组的行数
        for(int i=1;i<xishuArr.length;i++) {
            //稀疏数组的第二行的第一列和第二列的数据分别作为棋子在新棋盘的位置,并赋予该棋子的值
            chessArr2[xishuArr[i][0]][xishuArr[i][1]] = xishuArr[i][2];
        }
        System.out.println("根据稀疏数组恢复后的数组~~");
        for(int row[]:chessArr2) {
            for(int data: row) {
                System.out.printf("%d\t",data);
            }
            System.out.println();
        }
    }
}

循环队列

介绍

​ 队列是一个有序列表,可以用数组或是链表来实现。

​ 遵循先入先出的原则。先存入的队列的数据,要先取出,后存入的要后取出。

数组模拟队列:

​ 因为队列的输出,输入分别是从前后端来处理,因此需要两个变量front以及rear分别记录队列前后端的下标,front会随着数据输出而改变,而rear则使随着数据输入而改变。注意先存先取原则。

循环队列思路分析:

​ 注意循环队列是为了区分队列是否为空,是否为满,做了一个解决办法,将循环队列的空间空出一个位置。

队列为空的判断条件是:rear=front。

队列为满的判断条件是:(rear+1)%maxSize = front

以下是百度百科给出的解释:

  • 在循环队列中,当队列为空时,有front=rear,而当所有队列空间全占满时,也有front=rear。为了区别这两种情况,规定循环队列最多只能有MaxSize-1个队列元素,当循环队列中只剩下一个空存储单元时,队列就已经满了。因此,队列判空的条件是front=rear,而队列判满的条件是front=(rear+1)%MaxSize。

代码实现:

package queue;

import java.util.Scanner;

public class CircleArrayQueue {

    public static void main(String[] args) {
        // 测试
        System.out.println("测试数组环形队列~~");
        CircleArray queue = new CircleArray(4); //设置值为4,其队列的有效数据最大为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(git):获取数据");
            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) {
                        // TODO: handle exception
                        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;
            }
        }
        System.out.println("程序退出~~");
    }

}
class CircleArray{
    private int maxSize;        //表示数组的最大容量
    private int front;          //队列头
    private int rear;           //队列尾
    private int[] arr;          //该数组用于存放数据,模拟队列
    
    //构造器
    public CircleArray(int arrMaxsize) {
        maxSize = arrMaxsize;
        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("队列为空,不能取数据~~");
            //这里不能写return,throw已经终止了程序。
        }
        /* 
         * 这里需要分析出front是指向队列的第一个元素
         * 1、先把front对应的值保留到一个临时变量中
         * 2、将front后移考虑取模
         * 3、将临时保存的变量返回
         */
         int value = arr[front];
         front = (front+1)%maxSize;
         return value;
    }
    
    //显示队列的所有数据
    public void showQueue() {
        //先判断是否为空
        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 size() {
        //这里再加上一个maxSize的原因就是怕rear比front小的情况
        return (rear+maxSize-front) % maxSize;
    }
    
    //显示队列的头部
    public int headQueue() {
        //判断是否为空
        if(isEmpty()) {
            throw new RuntimeException("队列时空的,无法输出~~");
        }
        return arr[front];
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • 1稀疏数组 没什么好说的,挺简单的。就是讲数组转换为n行3列的二维数组。 接下来是代码 package com.a...
    文茶君阅读 244评论 0 0
  • 一、栈 1.1 栈的定义 栈(Stack):只允许在一端进行插入或删除操作的线性表。首先栈是一种线性表,但是限定这...
    末雨潮声阅读 633评论 0 0
  • 数据结构 第7讲 循环队列 过了一段时间,小张再也受不了...
    rainchxy阅读 8,976评论 4 16
  • 一 线性结构 数据元素之间存在一对一的线性关系 顺序存储结构 顺序表中的存储元素是连续的 链式存储结构 链表中的存...
    guideEmotion阅读 377评论 0 0
  • 1.数据结构包括:线性结构和非线性结构 1.1线性结构 线性结构为最常用的数据结构,其特点是数据元素之间存在一对一...
    smallmartial阅读 454评论 0 0