【数据结构】稀疏矩阵和队列

简介: 【数据结构】稀疏矩阵和队列

一、稀疏数组sparsearray

1、应用场景

需求:五子棋”存盘退出“ --> 二维数组保存

问题:这个二维数组大部分都是默认值0,记录了很多没有意义的数据 --> 稀疏数组

2、稀疏数组

稀疏数组:数组大部分为同一个值

处理方法:记录数组几行几列,有多少个的值。把不同值的行和列记录在小规模数组中。

行号row 列号col 值value
[0] 2 2 2
[1] 0 1 1
[2] 1 0 1

[0]:共几行几列,存在几个值

[1] - [n]:记录x行x列的值是多少

3、思路分析

1)二维转稀疏

  1. 遍历原始二维数组,得到有效数据个数 -> sum
  2. 创建稀疏数组sparseArr int[sum][3]
  3. 将有效数据存到sparseArr中

2)稀疏转二维

  1. 读取sparseArr的第一行的数据创建原始二维数组
  2. 读取sparseArr后面的数值,赋值给二维数组

4、代码实现

1)基础代码

package work.rexhao.sparsearray;

public class sparsearray {
   

    public static void main(String[] args) {
   
        // 创建一个原始的二维数组11*11
        // 0:没有旗子,1:黑子,2:蓝子
        int chessArr1[][] = new int[11][11];
        chessArr1[1][2] = 1;
        chessArr1[2][3] = 2;
        // 输出
        System.out.println("原始二维数组");
        for(int[] row : chessArr1) {
   
            for(int i : row) {
   
                System.out.printf("%d ",i);
            }
            System.out.println();
        }

        // 将二维数组转换成稀疏数组
        // 1.遍历二维数组,得到非0个数、行和列
        int r = 0, l = 0, v = 0;
        for(int[] row : chessArr1) {
   
            r++;
            for(int i : row) {
   
                l++;
                if(i != 0) {
   
                    v++;
                }
            }
        }
        l /= r;

        // 2.创建稀疏数组
        int sparseArr[][] = new int[v+1][3];

        // 3.给稀疏数组赋值
        sparseArr[0][0] = r;
        sparseArr[0][1] = l;
        sparseArr[0][2] = v;
        int ii = 0;
        for(int i = 0; i < r; i++) {
   
            for(int j = 0; j < l; j++) {
   
                if(chessArr1[i][j] != 0) {
   
                    sparseArr[++ii][0] = i;
                    sparseArr[ii][1] = j;
                    sparseArr[ii][2] = chessArr1[i][j];
                }
            }
        }

        // 稀疏数组的输出
        System.out.println("得到的稀疏数组是:");
        for(int[] row : sparseArr) {
   
            for(int i : row) {
   
                System.out.print(i + " ");
            }
            System.out.println();
        }

        // 将稀疏数组恢复二维数组
        // 1.读取第一行,创建二维数组
        int chessArr2[][] = new int[sparseArr[0][0]][sparseArr[0][1]];

        // 2.读取并赋值
        for(int i = 1; i <= sparseArr[0][2]; i++) {
   
            chessArr2[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
        }

        // 输出
        System.out.println("转换的二维数组是:");
        for(int[] row : chessArr2) {
   
            for(int i : row) {
   
                System.out.printf("%d ",i);
            }
            System.out.println();
        }
    }

}

2)IO代码

package work.rexhao.sparsearray;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class sparsearray_out {
   
    public static void main(String[] args) throws FileNotFoundException, IOException {
   
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("./chess.data"));
        // 创建一个原始的二维数组11*11
        // 0:没有旗子,1:黑子,2:蓝子
        int chessArr1[][] = new int[11][11];
        chessArr1[1][2] = 1;
        chessArr1[1][3] = 2;
        // 将二维数组转换成稀疏数组
        // 1.遍历二维数组,得到非0个数、行和列
        int r = 0, l = 0, v = 0;
        for (int[] row : chessArr1) {
   
            r++;
            for (int i : row) {
   
                l++;
                if (i != 0) {
   
                    v++;
                }
            }
        }
        l /= r;

        // 2.创建稀疏数组
        int sparseArr[][] = new int[v + 1][3];

        // 3.给稀疏数组赋值
        sparseArr[0][0] = r;
        sparseArr[0][1] = l;
        sparseArr[0][2] = v;
        int ii = 0;
        for (int i = 0; i < r; i++) {
   
            for (int j = 0; j < l; j++) {
   
                if (chessArr1[i][j] != 0) {
   
                    sparseArr[++ii][0] = i;
                    sparseArr[ii][1] = j;
                    sparseArr[ii][2] = chessArr1[i][j];
                }
            }
        }


        // 4.序列化
        oos.writeObject(sparseArr);
        oos.close();
        System.out.println("存档成功!");
    }
}
package work.rexhao.sparsearray;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class sparsearray_in {
   

    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
   
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("./chess.data"));
        int sparseArr[][] = (int[][])ois.readObject();
        System.out.println("读档成功!");
        // 将稀疏数组恢复二维数组
        // 1.读取第一行,创建二维数组
        int chessArr2[][] = new int[sparseArr[0][0]][sparseArr[0][1]];

        // 2.读取并赋值
        for (int i = 1; i <= sparseArr[0][2]; i++) {
   
            chessArr2[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
        }

        // 输出
         for (int[] row : chessArr2) {
   
            for (int i : row) {
   
                System.out.printf("%d ", i);
            }
            System.out.println();
        }

    }

}

二、队列

1、队列概述

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

遵循先入先出原则

2、数组模拟队列

1)数组结构介绍

数组的结构存储队列元素,maxSize是队列最大容量

两个变量front和rear记录队列前后端

2)思路分析

  1. 尾指针后移:rear+1
  2. rear < maxSize - 1:可以存

当front == rear,队列空

当rear == maxSize - 1,队列满

3)代码实现

package work.rexhao.queue;

import java.util.Scanner;

public class arrayQueueDemo {
   

    public static void main(String[] args) {
   
        ArrayQueue aq = new ArrayQueue(3);
        boolean loop = true;
        while (loop) {
   
            Scanner sc = new Scanner(System.in);
            System.out.println("1. 添加数据");
            System.out.println("2. 弹出数据");
            System.out.println("3. 显示首数据");
            System.out.println("4. 遍历");
            System.out.println("0. 退出");
            int key = sc.nextInt();
            if (key == 1) {
   
                System.out.println("请输入需要添加的数据");
                int value = sc.nextInt();
                aq.addQueue(value);
            } else if (key == 2) {
   
                try {
   
                    int value = aq.getQueue();
                    System.out.printf("弹出元素:%d\n",value);
                } catch (Exception e) {
   
                    System.out.println(e.getMessage());
                }

            } else if (key == 3) {
   
                try {
   
                    int value = aq.headQueue();
                    System.out.printf("首元素:%d\n", value);
                } catch (Exception e) {
   
                    System.out.println(e.getMessage());
                }
            } else if (key == 4) {
   
                aq.showQueue();
            } else if (key == 0) {
   
                loop = false;
            } else {
   
                System.out.println("请检查输入");
            }
        }
    }

}

/**
 * 使用数组模拟队列----编写一个ArrayQueue类
 */
class ArrayQueue {
   
    private int maxSize; // 数组最大容量
    private int front; // 队列头
    private int rear; // 队列尾
    private int[] arr; // 队列的数据

    /**
     * 创建队列的构造器
     */
    public ArrayQueue(int arrMaxSize) {
   
        maxSize = arrMaxSize;
        arr = new int[arrMaxSize];
        front = -1;// 指向队列头的前一个位置
        rear = -1;// 指向队列尾
    }

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

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

    /**
     * 添加队列数据
     */
    public void addQueue(int n) {
   
        if (isFull()) {
   
            System.out.println("队列满,添加失败!");
            return;
        }
        arr[++rear] = n;
    }

    /**
     * 出队列
     */
    public int getQueue() {
   
        if (isEmpty()) {
   
            // 抛出异常 -- 不需要写return
            throw new RuntimeException("队列空");
        }
        return arr[++front];
    }

    /**
     * 遍历
     */
    public void showQueue() {
   
        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 headQueue() {
   
        if (isEmpty()) {
   
            throw new RuntimeException("队列空");
        }
        return arr[front + 1];
    }
}

4)问题与优化

  1. 对于普通队列,数组使用一次就不能用,没有达到复用的效果
  2. 将这个数组使用算法,改进成一个环形的队列 (取模:%)

3、数组模拟环形队列

1)思路分析

  1. front变量的含叉做一个调整:front就指向队列的第一个元素,也就是说ari[front] 就是队列的第一个元素。front 的初始值=0
  2. rear 变量的含义做一个调整:rear指向队列的最后一个元素的后一个位置,空出一个空间做为约定。rear 的初始值=0
  3. 当队列满时,条件是 (rear +1) % maxsize == front
  4. 对队列为空的条件,rear == front
  5. 队列中有效的数据的个数 (rear+ maxsize - front) % maxsize

2)代码实现

package work.rexhao.queue;

import java.util.Scanner;

public class circleQueueDemo {
   

    public static void main(String[] args) {
   
        CircleQueue cq = new CircleQueue(3);
        boolean loop = true;
        while (loop) {
   
            Scanner sc = new Scanner(System.in);
            System.out.println("1. 添加数据");
            System.out.println("2. 弹出数据");
            System.out.println("3. 显示首数据");
            System.out.println("4. 遍历");
            System.out.println("0. 退出");
            int key = sc.nextInt();
            if (key == 1) {
   
                System.out.println("请输入需要添加的数据");
                int value = sc.nextInt();
                cq.addQueue(value);
            } else if (key == 2) {
   
                try {
   
                    int value = cq.getQueue();
                    System.out.printf("弹出元素:%d\n", value);
                } catch (Exception e) {
   
                    System.out.println(e.getMessage());
                }

            } else if (key == 3) {
   
                try {
   
                    int value = cq.headQueue();
                    System.out.printf("首元素:%d\n", value);
                } catch (Exception e) {
   
                    System.out.println(e.getMessage());
                }
            } else if (key == 4) {
   
                cq.showQueue();
            } else if (key == 0) {
   
                loop = false;
            } else {
   
                System.out.println("请检查输入");
            }
        }

    }

}

/**
 * 使用数组模拟环形队列----编写一个CircleQueue类
 */
class CircleQueue {
   
    private int maxSize; // 数组最大容量
    private int front; // 队列头
    private int rear; // 队列尾
    private int[] arr; // 队列的数据

    /**
     * 创建队列的构造器
     */
    public CircleQueue(int arrMaxSize) {
   
        maxSize = arrMaxSize;
        arr = new int[arrMaxSize];
        front = 0;// 指向队列头
        rear = 0;// 指向队列尾的后一个位置(空出一个空间做为约定)

    }

    /**
     * 判断队列是否满
     */
    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 + 1) % maxSize;
    }

    /**
     * 出队列
     */
    public int getQueue() {
   
        if (isEmpty()) {
   
            // 抛出异常 -- 不需要写return
            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 headQueue() {
   
        if (isEmpty()) {
   
            throw new RuntimeException("队列空");
        }
        return arr[front];
    }

    /**
     * 有效数据
     */
    public int size() {
   
        return (rear - front + maxSize) % maxSize;
    }
}
目录
相关文章
|
4月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
404 9
|
2月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
164 77
|
14天前
|
算法 调度 C++
STL——栈和队列和优先队列
通过以上对栈、队列和优先队列的详细解释和示例,希望能帮助读者更好地理解和应用这些重要的数据结构。
26 11
|
1月前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
2月前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
59 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
2月前
|
存储 C语言 C++
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
53 9
|
2月前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
48 7
|
4月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
110 5
|
4月前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
5月前
初步认识栈和队列
初步认识栈和队列
79 10