zoukankan      html  css  js  c++  java
  • 稀疏数组和队列

    一.数据结构的分型

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

      线性结构:

        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	",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
    ",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)	e(exit)	a(add)	g(get)	h(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
    ",(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)	e(exit)	a(add)	g(get)	h(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("程序退出");
        }

    运行结果:

     可以实现队列的复用

      

       

  • 相关阅读:
    .Net Core2.1 秒杀项目一步步实现CI/CD(Centos7.2)系列一:Docker入门
    在ASP.Net Core 中使用枚举类而不是枚举
    ASP.Net Core 中使用Zookeeper搭建分布式环境中的配置中心系列一:使用Zookeeper.Net组件演示基本的操作
    Redis系列文章总结:ASP.Net Core 中如何借助CSRedis实现一个安全高效的分布式锁
    从源码中学习设计模式系列——单例模式序/反序列化以及反射攻击的问题(二)
    ASP.NET Core依赖注入——依赖注入最佳实践
    2019年第一天——使用Visual Studio 2019 Preview创建第一个ASP.Net Core3.0的App
    ASP.Net Core2.1中的HttpClientFactory系列二:集成Polly处理瞬态故障
    ASP.Net Core2.1中的HttpClientFactory系列一:HttpClient的缺陷
    Docker for .Net Developers(part1:Docker基本概念介绍)
  • 原文地址:https://www.cnblogs.com/luhuajun/p/12228252.html
Copyright © 2011-2022 走看看