稀疏数组、队列、链表

稀疏数组和队列

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

  • 稀疏数组的处理方法

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

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

  • 二维数组装稀疏数组的思路

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

    2. 根据sum创建稀疏数组sparseArr int[sum + 1] [3]

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

  • 稀疏数组转原始二维数组的思路

    1. 先读取稀疏数组的第一行,根据第一行的数据,创建原始的二位数组

    2. 再读取稀疏数组后几行的数据,并赋给原始的二维数组即可

  • 代码实现

    public class SparseArray {
       public static void main(String[] args) throws Exception {
           int arr[][] = new int[11][11];
           arr[1][2] = 2;
           arr[2][3] = 1;
           for (int[] ints : arr) {
               for (int item : ints) {
                   System.out.print(item + "\t");
              }
               System.out.println();
          }

           //将二维数组转换为稀疏数组
           int sum = 0; //用来计算有效个数
           for (int i = 0; i < 11; i++) {
               for (int j = 0; j < 11; j++) {
                   if (arr[i][j] != 0) {
                       sum++;
                  }
              }
          }
           //创建稀疏数组
           int spar[][] = new int[sum+1][3];
           spar[0][0] = 11;
           spar[0][1] = 11;
           spar[0][2] = sum;

           //计数器,计算查到第几个非0数据
           int count = 0;
           for (int i = 0;i<11;i++) {
               for (int j = 0;j<11;j++) {
                   if(arr[i][j]!=0){
                       count++;
                       spar[count][0] = i;
                       spar[count][1] = j;
                       spar[count][2] = arr[i][j];
                  }
              }
          }

           for (int[] ints : spar) {
               for (int anInt : ints) {
                   System.out.print(anInt+"\t");
              }
               System.out.println();
          }
           //C:\Users\zxy\Desktop\文本文件\test
           String filePath = "C:\\Users\\zxy\\Desktop\\文本文件\\test\\map.data";
           ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(filePath));
           stream.writeObject(spar);
           stream.close();
           System.out.println("完成序列化存储");

           //对象反序列化
           ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(filePath));
           int sparr[][]= (int[][]) inputStream.readObject();
           System.out.println("反序列化后的数据-------");
           //转换为二维数组
           int newarr[][] = new int[sparr[0][0]][sparr[0][1]];

           for (int i=1;i<sparr.length;i++){
               newarr[sparr[i][0]][sparr[i][1]] = sparr[i][2];
          }

           for (int[] ints : newarr) {
               for (int anInt : ints) {
                   System.out.print(anInt + "\t");
              }
               System.out.println();
          }

      }
    }

     

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

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

  • 数组模拟环形队列思路

    1. front变量指向队列的第一个元素,也就是说初始值为0

    2. rear变量指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为约定,初始值为0

    3. 当队列满时,条件是(rear + 1) % maxSize = front 【满】

    4. 队列为空的条件,rear == front

    5. 队列中有效的数据的个数 (rear + maxSize - front) % maxSize

    6. 我们就可以得到一个环形队列

  • 代码实现

    public class ArrayQueueDemo {
       public static void main(String[] args) {
           System.out.println("测试数组模拟环形队列的案例");
           //创建一个队列
           CircleArray queue = new CircleArray(4);
           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(get):从队列取出数据");
               System.out.println("h(head):查看队列头的数据");
               key = scanner.next().charAt(0);//接受一个字符
               switch (key){
                   case 's':
                       queue.showQueue();
                       break;
                   case 'a':
                       System.out.println("输入一个数");
                       int val = scanner.nextInt();
                       queue.addQueue(val);
                       break;
                   case 'g':
                       try {
                           int res = queue.getQueue();
                           System.out.printf("取出的数据是%d\n",res);
                      }catch (Exception e){
                           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;
              }
          }
      }
    }

    class CircleArray{
       private int maxSize; //表示数组的最大容量
       private int front; //初始值0 指向队列的第一个元素
       private int rear; //初始值0 指向队列的最后一个元素的后一个位置
       private int[] arr; //该数组用于存放数据,模拟队列

       public CircleArray(int arrMaxSize){
           maxSize = arrMaxSize;
           arr = new int[maxSize];
      }

       //判断队列数据是否已满
       public boolean isFull(){
           //利用队列尾指针 + 1 % 数组长度的值 与 队列头指针是否在同一下标判断队列数据是否已满
           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()){
               throw new RuntimeException("队列空,不能取数据");
          }
           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(){
           //rear 2
           //front 1
           //maxSize 3
           return (rear + maxSize - front) % maxSize;
      }

       //显示队列的头数据
       public int headQueue(){
           if(isEmpty()){
               throw new RuntimeException("队列空的,没有数据");
          }
           return arr[front];
      }
    }

链表

链表是有序的列表

  • 链表vs数组

    • 因为数组可以随机访问,所以它的查询和修改效率更高,但在增加删除元素时需要移动元素,所以效率低;

      链表只能顺序访问,所以它查询修改效率低,但是增加删除时只需修改指针指向就可以了,所以效率高。

  • 单向链表

    • 添加元素思路

      • 循环列表,按照顺序规则找到找到位置后,将左边的next指针指向新的节点;将新节点的next指针指向下一个节点

    • 修改元素思路

      • 循环列表,找到要修改的节点,将左边的next指针指向新的节点;将新节点的next指针指向下一个节点

    • 删除元素思路

      • 循环列表,找到要删除的节点,将前一个节点的next指针指向要删除的节点的下一个节点

    • 遍历元素思路

      • 循环列表,如果next节点不为null,则一直循环打印

    • 求单链表中有效节点的个数

      • 循环列表,如果next节点下的主要变量值不为空,则计数器++

    • 查找单链表中的倒数第k个节点

      • 循环列表,循环的次数为链表中有(效节点数)- k ;最后一个有效节点就是倒数第k个节点

    • 单链表的反转

      • 创建一个新的链表头。并循环原链表,将新链表的head-->原链表的第一个节点,再将第一个节点指向这个head.next。每次循环,将原链表的下一节点指向head.next,并将next指向新链表的第一个节点

    • 从尾到头打印单链表

      • 使用Stack先进后出的机制实现

    • 合并两个有序的单链表,合并之后的链表依然有序

      • 循环两个链表,将较小值的节点放在新练表的next,然后将新链表与原链表后移一位。当一条原列表遍历结束,用相同的方法遍历另一链表

    /**
    * 单向链表
    */
    public class SingleLinkedListDemo {
       public static void main(String[] args) throws InterruptedException {
           SingleLinkedList list = new SingleLinkedList();
           list.add(new MyNode(1,"hello"));
           list.add(new MyNode(2,"hello"));
           list.add(new MyNode(4,"hello"));
    //       list.iter();
    //       list.set(new MyNode(2,"nohello"));
    //       list.iter();
    //       list.del(3);
    //       list.iter();
    //       System.out.println(list.size());
    //       list.getIndex(2);
    //       list.rev();
    //       list.iter();
    //       list.desc();
           SingleLinkedList list2 = new SingleLinkedList();
           list2.add(new MyNode(1,"hello"));
           list2.add(new MyNode(3,"hello"));
           list2.add(new MyNode(4,"hello"));
           list.merge(list2.head.next);
           list.iter();

      }
    }

    //定义模拟链表
    class SingleLinkedList {
       MyNode head = new MyNode(0, "");

       //添加节点
       public void add(MyNode node) {
           MyNode n = head;
           MyNode tail;
           while (true) {
               if (n.next == null) {
                   n.next = node;
                   break;
              } else if (n.next.no > node.no) {
                   tail = n.next;
                   n.next = node;
                   node.next = tail;
                   break;
              } else if (n.next.no == node.no) {
                   System.out.println("已存在");
                   break;
              }
               n = n.next;
          }
      }
       //遍历节点
       public void iter(){
           MyNode n = head;
           while (true){
               if(n.next == null) {
                   break;
              }
               System.out.println(n.next);
               n = n.next;
          }
      }
       //修改节点
       public void set(MyNode node){
           MyNode n = head;
           //辅助变量
           MyNode tail;
           while (true){
               if(n.next==null){
                   break;
              }
               if(n.next.no == node.no){
                   tail = n.next;
                   n.next = node;
                   node.next = tail.next;
                   break;
              }
               n = n.next;
          }
      }
       //删除节点
       public void del(int num){
           MyNode n = head;
           //辅助变量
           MyNode tail;
           while (true){
               if(n.next==null){
                   break;
              }
               if(n.next.no == num){
                   tail = n.next;
                   n.next = tail.next;
                   break;
              }
               n = n.next;
          }
      }
       //有效节点的个数
       public int size(){
           MyNode n = head;
           int count=0;
           while (true){
               if(n.next!=null){
                   count++;
              }else{
                   break;
              }
               n = n.next;
          }
           return count;
      }

       //查找链表中的倒数第k个节点
       public void getIndex(int index){
           MyNode n = head.next;
           if(n == null){
               System.out.println("链表为空");
          }
           for (int i=0;i<size()-index;i++){
               n = n.next;
          }
           System.out.println("倒数第k个为:"+n);
      }

       //链表反转
       public void rev(){
           MyNode n = head.next;
           //辅助节点
           MyNode node = new MyNode(0,"");
           MyNode tail;
           MyNode m;
           while (true){
               if (n == null) {
                   break;
              }
               m = n.next;
               tail = node.next;
               node.next = n;
               n.next = tail;
               n = m;
          }
           head.next = node.next;
      }

       //从尾到头打印单链表
       public void desc(){
           MyNode node = head.next;
           Stack<MyNode> stack = new Stack<>();
           while (node!=null){
               stack.push(node);
               node = node.next;
          }
           for (int i = 0; i <= stack.size(); i++) {
               System.out.println(stack.pop());
          }
      }
       //合并两个有序的单链表,合并之后的链表依然有序
       public void merge(MyNode n2){
           MyNode n1 = head.next;
           MyNode node = new MyNode(0,"");
           MyNode tail = node;
           while (n1!=null&&n2!=null){
               if(n1.no<=n2.no){
                   tail.next = n1;
                   n1 = n1.next;
              }else{
                   tail.next = n2;
                   n2 = n2.next;
              }
               tail = tail.next;
          }

           while (n1!=null){
               tail.next = n1;
               n1 = n1.next;
               tail = tail.next;
          }
           while (n2!=null){
               tail.next = n2;
               n2 = n2.next;
               tail = tail.next;
          }
           head.next = node.next;
      }
    }

    //定义链表节点
    class MyNode {
       public int no;
       public String name;
       public MyNode next;

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

       @Override
       public String toString() {
           return "MyNode{" +
                   "no=" + no +
                   ", name='" + name + '\'' +
                   '}';
      }
    }
  • 双向链表

    public class DoubleLinkedListDemo {
       public static void main(String[] args) {
           DoubleLinkedList list = new DoubleLinkedList();
           list.add(new Node(1,"Jack"));
           list.add(new Node(2,"Tom"));
           list.add(new Node(4,"Jarry"));
           list.add(new Node(3,"Baby"));
           list.iter();
           Node n = new Node(4,"Big Jarry");
           list.upNode(n);
           System.out.println("updated");
           list.iter();
           System.out.println("deleted");
           list.delNode(4);
           list.iter();
      }
    }

    class DoubleLinkedList{
       public Node head = new Node(0,"");

       //add
       public void add(Node node){
           Node myNode = head;
           Node tail;
           while (true){
               if(myNode.next==null){
                   myNode.next = node;
                   node.pre = myNode;
                   break;
              }
               if(myNode.next.no>node.no){
                   tail = myNode.next;
                   node.pre = myNode;
                   myNode.next = node;
                   node.next = tail;
                   if(node.next!=null) {
                       node.next.pre = node;
                  }
                   break;
              }
               if(myNode.next.no == node.no){
                   System.out.println("already exist");
                   break;
              }
               myNode = myNode.next;
          }
      }

       //iterable
       public void iter(){
           Node node = head;
           if(node.next == null){
               System.out.println("list is null");
               return;
          }
           while (true){
               if(node.next==null){
                   break;
              }
               System.out.println(node.next);
               node = node.next;
          }
      }

       //update
       public void upNode(Node node){
           Node n = head;
           Node tail;
           while (true){
               if(n == null){
                   break;
              }
               if(n.next.no == node.no){
                   tail = n.next;
                   node.pre = n;
                   n.next = node;
                   node.next = tail.next;
                   if(node.next!=null) {
                       node.next.pre = node;
                  }
                   break;
              }
               n = n.next;
          }
      }

       //delete
       public void delNode(int no){
           Node n = head.next;
           if(n==null){
               return;
          }
           while (true){
               if(n==null){
                   break;
              }
               if(n.no==no){
                   n.pre.next = n.next;
                   if(n.next!=null){
                       n.next.pre = n.pre;
                  }
                   break;
              }
               n=n.next;
          }
      }
    }

    class Node{
       public int no;
       public String name;
       public Node pre;//pre
       public Node next;//rear

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

       @Override
       public String toString() {
           return "Node{" +
                   "no=" + no +
                   ", name='" + name + '\'' +
                   '}';
      }
    }
posted @ 2021-09-19 16:10  你们都不上班吗  阅读(28)  评论(0)    收藏  举报