【数据结构与算法】稀疏数组 + 循环队列 + 单链表【分析,代码实现,结果】

稀疏数组

(1)分析

例子:棋盘的存盘与续上局

将棋盘抽象成二维数组,元素为0表示此处无棋子,若为1则表示此处有棋子(当然,也可以再设2表示另一方的棋子),在下棋途中想要保存棋盘时,即将当前棋盘状态保存起来,方便下此导入,从而继续上局,为节省保存时的占用空间,可将棋盘二维数组压缩为稀疏数组,从而在外部持久化保存时,保存稀疏数组中的信息,再下次导入时,则将稀疏数组重新解析成二维数组,并生成上局的棋盘状态,即可完成棋盘。

(2)代码

package 稀疏数组;

public class Test {
    public static void main(String[] args) {
        // 1、创建 二维数组
        int[][] chessTable = new int[10][10];
        chessTable[0][2] = 1;
        chessTable[3][5] = 1;
        chessTable[5][8] = 1;
        chessTable[8][9] = 1;
        System.out.println("棋盘初始为----------");
        showDeepArray(chessTable);

        // 2、得到 稀疏矩阵
        // 得到数组中有效值的个数,以便于决定稀疏矩阵的 行数 - 1 即为此值
        int num = 0;
        for (int[] row : chessTable) {
            for (int col : row) {
                if (col != 0) {
                    num++;
                }
            }
        }
        int[][] compressedChessTable = new int[num + 1][3];
        compressedChessTable[0][0] = chessTable.length; // 棋盘行数
        compressedChessTable[0][1] = chessTable[0].length; // 棋盘列数
        compressedChessTable[0][2] = num; // 棋盘有效值个数
        int count = 1;
        for (int i = 0; i < chessTable.length; i++) {
            for (int j = 0; j < chessTable[0].length; j++) {
                if (chessTable[i][j] != 0) {
                    compressedChessTable[count][0] = i;
                    compressedChessTable[count][1] = j;
                    compressedChessTable[count][2] = chessTable[i][j];
                    count++;
                }
            }
        }
        System.out.println("稀疏矩阵为----------");
        showDeepArray(compressedChessTable);

        // 3、解析 稀疏矩阵 到新的 二维数组
        int[][] newChessTable = new int[compressedChessTable[0][0]][compressedChessTable[0][1]];
        for (int i = 1; i <= compressedChessTable[0][2]; i++) {
            newChessTable[compressedChessTable[i][0]][compressedChessTable[i][1]] = compressedChessTable[i][2];
        }
        System.out.println("解析出的数组为----------");
        showDeepArray(newChessTable);
    }

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

(3)结果

在这里插入图片描述

循环队列

(1)分析

为避免顺序存储方式的队列实现中,队列的“假溢出”现象,为实现队列数组的循环复用,设计了循环队列,将队列头指针 front 指向队列的第一个元素下标,而队列尾指针 rear 指向队列最后一个元素的下一个位置下标,从而便于区分队列空和队列满这两种状态

队列空:front == rear
队列满:(rear + 1) % maxSize == front
队列长度:(rear - front + maxSize) % maxSize

(2)代码

package 循环队列;

import java.util.Scanner;

class CircleQueue {
    private int maxSize; // 数组的最大容量
    private int front; // 队列头,规定它指向队列的第一个元素下标
    private int rear; // 队列尾,规定它指向队列最后一个元素的下一个位置的下标
    private int[] data; // 存放数据

    public CircleQueue(int maxSize) {
        this.maxSize = maxSize;
        data = new int[maxSize];
        front = 0;
        rear = 0;
    }

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

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

    // 添加数据到队列
    public void addQueue(int n) {
        if (isFull()) {
            throw new RuntimeException("队列满,不能添加数据~");
        } else {
            data[rear] = n;
            rear = (rear + 1) % maxSize;
        }
    }

    // 获取队列数据
    public int getQueue() {
        if (isEmpty()) {
            throw new RuntimeException("队列空,不能取数据~");
        } else {
            int temp = data[front];
            front = (front + 1) % maxSize;
            return temp;
        }
    }

    // 显示队列的所有数据
    public void showQueue() {
        if (isEmpty()) {
            throw new RuntimeException("队列空,没有数据~");
        }
        int temp = front;
        for (int i = 0; i < (rear - front + maxSize) % maxSize; i++) {
            System.out.printf("%d\t", data[temp]);
            temp = (temp + 1) % maxSize;
        }
        System.out.println();
    }
}

public class Test {
    public static void main(String[] args) {
        CircleQueue queue = new CircleQueue(5);
        char input = ' ';
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        while (loop) {
            System.out.println("-------------------------------------");
            System.out.println("s(show) 显示队列");
            System.out.println("e(exit) 退出程序");
            System.out.println("a(add) 添加数据到队列");
            System.out.println("g(get) 从队列中取出数据");
            System.out.println("-------------------------------------");
            input = scanner.next().charAt(0);
            switch (input) {
                case 's':
                    queue.showQueue();
                    break;
                case 'e':
                    loop = false;
                    break;
                case 'a':
                    System.out.print("请输入要添加的数据:");
                    int newNum = scanner.nextInt();
                    queue.addQueue(newNum);
                    break;
                case 'g':
                    int num = queue.getQueue();
                    System.out.println("取出的数据为:" + num);
            }
        }
    }
}

(3)结果

在这里插入图片描述

单链表

(1)分析

共有如下方法的实现
在这里插入图片描述
注意事项:

  • 注意条件判断,例如单链表为空不能进行查找,删除,更新,等等操作
  • 单链表反转时,若链表为空或只有一个结点,则不必反转
  • 若欲将单链表中的结点加入到另一个单链表上,切记之前结点中的 next 属性中包含了其后的结点信息,我们应该”复制“一个之前的结点(除其 next 信息外的其他信息),从而可避免此问题

(2)代码

package 链表.单链表;

class StudentNode {
    public int no;
    public String name;
    public StudentNode next;

    public StudentNode(int no, String name) {
        this.no = no;
        this.name = name;
    }

    @Override
    public String toString() {
        return "StudentNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }
}

class StudentLinkedList {
    StudentNode head = new StudentNode(0, "");

    /**
     * 普通插入,插入到末尾
     * @param node 待插入结点
     */
    public void add(StudentNode node) {
        StudentNode temp = head;
        while (temp.next != null) {
            temp = temp.next;
        }
        temp.next = node;
        System.out.println("添加成功~");
    }

    /**
     * 按编号顺序插入
     * @param node 待插入结点
     */
    public void addByNo(StudentNode node) {
        StudentNode pre = head;
        if (pre.next == null) { // 链表为空
            pre.next = node; // 直接将结点插入node.no
            System.out.println("添加成功~");
            return;
        }
        // 链表不为空
        StudentNode temp = pre.next;
        while (temp != null) {
            if (node.no < temp.no) {
                pre.next = node;
                node.next = temp;
                System.out.println("添加成功~");
                return;
            }
            pre = pre.next;
            temp = pre.next;
        }
        // temp 为null时,pre即为最后一个结点
        pre.next = node;
    }

    /**
     * 删除结点
     * @param no
     */
    public void deleteByNo(int no) {
        StudentNode temp = head.next;

        if (temp == null) { // 链表为空,则结束操作
            System.out.println("链表为空,不可执行删除操作~");
            return;
        } else if (temp.no == no) { // 第一个结点即为待删除结点
            head.next = temp.next;
            return;
        } else { // 待删除结点不是第一个结点
            while (temp != null && temp.next != null) {
                if (temp.next.no == no) {
                    temp.next = temp.next.next;
                    System.out.println("删除成功~");
                    return;
                }
                temp = temp.next;
            }
            System.out.println("未查找到~");
        }
    }

    /**
     * 更新结点
     * @param node 更新后的结点
     */
    public void update(StudentNode node) {
        StudentNode temp = head.next;
        while (temp != null) {
            if (temp.no == node.no) {
                temp.name = node.name;
                System.out.println("修改成功~");
                return;
            }
            temp = temp.next;
        }
        System.out.println("查无此人~");
    }

    /**
     * 查找倒数第 k 个结点
     * @param k
     * @return
     */
    public StudentNode getLastIndexNode(int k) {
        // 首先得到链表长度,从而得知结点总个数
        int len = getLength();
        if (k > len || k < 0) { // 若k值过大
            throw new RuntimeException("k值越界~");
        }
        // 需要遍历多少次
        int count = len - k;
        StudentNode temp = head.next;
        for (int i = 0; i < count; i++) {
            temp = temp.next;
        }
        return temp;
    }

    /**
     * 单链表的逆序(打印)
     * 方式一:从此链表中遍历取出结点,头插法插入一个新的链表中
     */
    public void reverseLinkedList() {
        // 如果当前链表为 空 或 只有一个结点 则无需反转
        StudentNode temp = head;
        if (temp.next == null || temp.next.next == null) {
            return;
        }
        temp = temp.next; // 指向第一个结点
        StudentNode tempHead = new StudentNode(0, "");
        while (temp != null) {
            StudentNode node = new StudentNode(temp.no, temp.name);
            node.next = tempHead.next;
            tempHead.next = node;
            temp = temp.next;
        }
        head = tempHead;
    }

    /**
     * 单链表的逆序(打印)
     * 方式二:利用栈
     */
    public void reverseLinkedList_ByStack() {
        // 如果当前链表为 空 或 只有一个结点 则无需反转
        StudentNode temp = head;
        if (temp.next == null || temp.next.next == null) {
            return;
        }
        Stack<StudentNode> stack = new Stack<>();
        temp = head.next;
        while (temp != null) {
            stack.push(temp);
            temp = temp.next;
        }
        while (stack.size() > 0) {
            StudentNode node = stack.pop();
            System.out.println(node);
        }
    }
    /**
     * 得到链表长度
     * @return
     */
    public int getLength() {
        int num = 0;
        StudentNode temp = head.next;
        while (temp != null) {
            num++;
            temp = temp.next;
        }
        return num;
    }

    /**
     * 展示链表中所有结点
     */
    public void show() {
        StudentNode temp = head.next;
        if (temp == null) {
            System.out.println("链表为空~");
        }
        while (temp != null) {
            System.out.println(temp);
            temp = temp.next;
        }
    }
}

public class Test {
    public static void main(String[] args) {
        StudentNode node1 = new StudentNode(2, "tom");
        StudentNode node2 = new StudentNode(1, "mike");
        StudentNode node3 = new StudentNode(3, "jhon");
        StudentLinkedList linkedList = new StudentLinkedList();

        linkedList.show();
        System.out.println("----------------------------");

        linkedList.addByNo(node1);
        linkedList.addByNo(node2);
        linkedList.addByNo(node3);
        linkedList.show();
        // 得到倒数第 2 个结点
        int k = 2;
        System.out.println("倒数第" + k + "个结点:" + linkedList.getLastIndexNode(k));
        System.out.println("将链表反转=======");
        linkedList.reverseLinkedList();
        linkedList.show();
        System.out.println("----------------------------");

        linkedList.deleteByNo(2);
        linkedList.show();
        System.out.println("长度为:" + linkedList.getLength());
        System.out.println("----------------------------");

        linkedList.deleteByNo(1);
        linkedList.show();
        System.out.println("----------------------------");

        linkedList.update(new StudentNode(3, "Jhon SiNa"));
        linkedList.show();
    }
}

(3)结果

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

超周到的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值