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

167 阅读2分钟

写在前面

稀疏数组

  • 当一个数组中大部分元素时0,或为同一个值,例如五子棋棋盘,使用稀疏数组处理数组中没有意义的数据
  • 记录数组一共几行几列,有多少个不同值;把具有不同值的元素的行列及值记录在一个小规模的数组中
  • 自己的理解,通过协议的方式,固定存值的模型,例如[0][1]存总行数、[0][2]存总列数,[0][3]存总值数;[1][1]存行、[1][2]存列、[1][3]存值等等

代码实现

//创建存储的文件
String fileStr = "/Users/apple/Desktop/java/java-dataStructure/sparse-Array/src/array.txt";
File file = new File(fileStr);
file.createNewFile();
//创建原始二维数组 0无棋子,1黑,2蓝
int[][] chessArr = new int[11][11];
chessArr[1][2] = 1;
chessArr[2][3] = 2;
//将二维数组转换为稀疏数组
//遍历二维数组,记录相关数据
int sum = 0;
for (int i = 0; i < chessArr.length; i++) {
    for (int j = 0; j < chessArr.length; j++) {
        if (chessArr[i][j] != 0) {
            sum ++;
        }
    }
}
//创建稀疏数组
int[][] sparseArr = new int[sum + 1][3];
//赋值
sparseArr[0][0] = chessArr.length;
sparseArr[0][1] = chessArr[0].length;
sparseArr[0][2] = sum;
//遍历chessArr数组,存数据
//count记录第几个数据
int count = 0;
for (int i = 0; i < chessArr.length; i++) {
    for (int j = 0; j < chessArr.length; j++) {
        if (chessArr[i][j] != 0) {
            count ++;
            sparseArr[count][0] = i;
            sparseArr[count][1] = j;
            sparseArr[count][2] = chessArr[i][j];
        }
    }
}

//存稀疏数组
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
for (int i = 0; i < sparseArr.length; i++) {
    for (int j = 0; j < sparseArr[0].length; j++) {
        if (i == sparseArr.length - 1 && j == sparseArr[0].length) {
            writer.write(sparseArr[i][j] + "");
        } else {
            writer.write(sparseArr[i][j] + ",");
        }
    }
}
writer.close();

//读出数组,一维变二维
BufferedReader reader = new BufferedReader(new FileReader(file));
String resStr = reader.readLine();
reader.close();
String[] splitStr = resStr.split(",");
int[][] recoverSparseArr = new int[sum + 1][3];
//记录行数
int recoverCount = 0;
for (int i = 0; i < splitStr.length; i++) {
    recoverSparseArr[recoverCount][i % 3] = Integer.parseInt(splitStr[i]);
    if (i % 3 == 2) {
        //每行三列,也就是说每三个要换一行
        recoverCount ++;
    }
}

//将稀疏数组恢复成原始数组
int rowCount = recoverSparseArr[0][0];
int colCount = recoverSparseArr[0][1];
int valueCount = recoverSparseArr[0][2];
int[][] recoverChessArr = new int[rowCount][colCount];
int row = 0;
int col = 0;
int value = 0;
for (int i = 1; i < valueCount+1; i++) {
        row = recoverSparseArr[i][0];
        col = recoverSparseArr[i][1];
        value = recoverSparseArr[i][2];
        recoverChessArr[row][col] = value;
}

队列

  • 有序列表,可以用数组或者链表来实现;先进先出
  • 取模可以实现循环和情况归一

环形数组实现队列

  • 思路理解,通过取模的方式实现循环的效果,由于要保证frontrear两个指向头尾的指标,都要一直变动,而且不能相等,因此要预留一个空间作为约定,rear+1不能超过maxSize,所以实际队列大小是maxSize减1
  • front队列头,负责取第一个值,0开始,永远指向有值的索引,通过(front + 1) % maxSize来判断,front + 1保证每次取完数据后都会向后移动,且当front == maxSize - 1时,会自动跳到0rear同理,但是其中要保证,raer负责添加值,指向的地方永远没有值
  • 队列满条件(rear + 1) % maxSize == front,如果队列满,根据循环数组的前提,front在头,rear在尾,rear再加1就要回到头部与front相等了
  • 队列的有效数据个数(rear - front + maxSize) % maxSize,当rear > front时,有效数据个数就是rear - front,例如0 1 2 3rear指向没有值的3索引,那个数就是3 - 0 = 3个;而rear < front时,从头到尾front - rear的部分是永远没有值的(假定数值是从左到右放的,那么当rear < front时,也就是frontrear的左边),那么也就是说maxSize - (front - rear) = raer + maxSize - front是有值的部分。而与maxSize取模是将两种情况归一了,当rear - font > 0时,就是比maxSize多出来的那部分,就是模,也就是个数;当rear - front < 0时,再有maxSize - (front - rear),就是减去没有值的部分,再取模,就是个数
  • 遍历数据从front开始到front+size()结束,因为要从当前头部front开始取,到size()结束;索引值i % maxSize,循环找到当前值的位置
class ArrayCycleQueue {
    private int maxSize; //最大容量
    private int front; //队列头 只能指向第一个元素
    private int rear; //队列尾 指向最后一个元素的后一个位置 
    private int[] arr; //数组,存放数据
    public ArrayCycleQueue(int maxSize) {
        this.maxSize = maxSize + 1;
        arr = new int[this.maxSize];
        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("Queue is full");
            return;
        }
        //直接加入数据
        arr[rear] = n;
        //将rear后移,取模到前面
        rear = (rear + 1) % maxSize;

    }
    //获取数据
    public int getQueue() {
        if (isEmpty()) {
            //抛出异常
            throw new RuntimeException("Queue is empty");
        }
        //front指向队列的第一个元素
        //先把front的值保存到临时变量
        // 将front后移
        //将临时保存的变量返回
        int value = arr[front];
        front = (front + 1) % maxSize;
        return value;
    }
    //显示队列所有数据
    public void showQueue() {
        if (isEmpty()) {
            System.out.println("Queue is empty");
            return;
        }
        //从front开始遍历,遍历多少个元素
        for (int i = front; i < front + size(); i++) {
            System.out.println("arr[" +  i % maxSize + "]" + " = " + arr[i % maxSize]);
        }
    }
    //求当前队列有效个数
    public int size() {
        return (rear + maxSize - front) % maxSize;
    }
    // 显示队列的头数据
    public int headQueue() {
        if (isEmpty()) {
            //抛出异常
            throw new RuntimeException("Queue is empty");
        }
        return arr[front];
    }
}