【java】队列和链表

1.稀疏数组

定义

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

语法

1.先记录(原数组)一共有几行几列,有多少个不同的值

2.再将不同元素的行和列及值记录在一个小规模的数组中,从而缩小程序的规模

提问:当数组大部分为同一值时应该怎么做

应用需求

1.使用稀疏数组来保留类似棋盘,地图的二维数组

2.把稀疏数组存盘,并且可以重新恢复到原来的二维数组

二维数组转稀疏数组

1.遍历二维数组,读取二维数组中有效数据的个数sum;

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

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

稀疏数组装二维数组

1.根据稀疏数组的第一行,创建原始的二维数组

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

	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;
      chessArr1[4][5] = 2;
      // 输出原始的二维数组
      System.out.println("原始的二维数组~~");
      for (int[] row : chessArr1) {
         for (int data : row) {
            System.out.printf("%d\t", data);
         }
         System.out.println();
      }

      // 将二维数组 转 稀疏数组的思
      // 1. 先遍历二维数组 得到非0数据的个数
      int sum = 0;
      for (int i = 0; i < 11; i++) {
         for (int j = 0; j < 11; j++) {
            if (chessArr1[i][j] != 0) {
               sum++;
            }
         }
      }

      // 2. 创建对应的稀疏数组
      int sparseArr[][] = new int[sum + 1][3];
      // 给稀疏数组赋值
      sparseArr[0][0] = 11;
      sparseArr[0][1] = 11;
      sparseArr[0][2] = sum;
      
      // 遍历二维数组,将非0的值存放到 sparseArr中
      int count = 0; //count 用于记录是第几个非0数据
      for (int i = 0; i < 11; i++) {
         for (int j = 0; j < 11; j++) {
            if (chessArr1[i][j] != 0) {
               count++;
               sparseArr[count][0] = i;
               sparseArr[count][1] = j;
               sparseArr[count][2] = chessArr1[i][j];
            }
         }
      }
      
      // 输出稀疏数组的形式
      System.out.println();
      System.out.println("得到稀疏数组为~~~~");
      for (int i = 0; i < sparseArr.length; i++) {
         System.out.printf("%d\t%d\t%d\t\n", sparseArr[i][0], sparseArr[i][1], sparseArr[i][2]);
      }
      System.out.println();
      
      //将稀疏数组 --》 恢复成 原始的二维数组
      /*
       *  1. 先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组,比如上面的  chessArr2 = int [11][11]
         2. 在读取稀疏数组后几行的数据,并赋给 原始的二维数组 即可.
       */
      
      //1. 先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组
      
      int chessArr2[][] = new int[sparseArr[0][0]][sparseArr[0][1]];
      
      //2. 在读取稀疏数组后几行的数据(从第二行开始),并赋给 原始的二维数组 即可
      
      for(int i = 1; i < sparseArr.length; i++) {
         chessArr2[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
      }
      
      // 输出恢复后的二维数组
      System.out.println();
      System.out.println("恢复后的二维数组");
      
      for (int[] row : chessArr2) {
         for (int data : row) {
            System.out.printf("%d\t", data);
         }
         System.out.println();
      }
   }

}

2.队列

介绍

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

遵循先进先出

因为队列的输出和输入分别是从前后端来处理,因此需要两个变量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;
        arr = new int[maxSize];
        front = -1;//指向队列头部的前一个位置,不包含具体的数据
        rear = -1;//指向队列尾部的具体的数据
    }

    //判断队列是否满
    public boolean isFull() {
        return rear == maxSize - 1;//因为数组是从0开始的
    }

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

    //添加数据
    public void addQueue(int n) {
        if (isFull()) {
            return;
        }
        rear++;
        arr[rear] = n;
    }

    //出队列
    public int getQueue() {
        if (isEmpty()) {
            throw new RuntimeException("队列空");
        }
        front++;
        return arr[front];
    }
    //显示队列的所有数据
    public void showQueue(){
        //遍历
        if(isEmpty()){
            System.out.println("队列为空");
        }
        for(int i = 0; i < arr.length; i++){
            System.out.println(String.format("arr[%d] = %d\n",i,arr[i]));
        }
    }
    //显示队列的头部数据,不是取出数据
    public int headQueue(){
        if(isEmpty()){
        throw new RuntimeException("没有数据");
        }
        return arr[front+1];
    }
}

环形队列

思路分析

1.front的含义调整为指向队列的第一个元素,初始值为0;

2.reard的含义调整为指向对列最后一个元素的后一个位置,因为要预留一个空间做约定,rear的初始值为0

3.当队列满时,条件为(rear + 1)%maxsize = front吗,即最后一个空间被front占据

4.当队列为空时,rear = front

5.队列中有效的数据个数:(rear + maxsize - front) % maxsize,模实际上只对rear有效果

class Arrayqueue {
    private int maxSize;
    private int front;
    private int rear;
    private int[] arr;

    //构造器

    public Arrayqueue(int maxSize) {
        this.maxSize = maxSize;
        arr = new int[maxSize];
        front = -1;//指向队列头部的前一个位置,不包含具体的数据
        rear = -1;//指向队列尾部的具体的数据
    }

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

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

    //添加数据
    public void addQueue(int n) {
        if (isFull()) {
            return;
        }
        arr[rear] = n;
        rear = (rear + 1) % maxSize;
    }

    //出队列
    public int getQueue() {
        if (isEmpty()) {
            throw new RuntimeException("队列空");
        }
        int value = arr[front];
        front = (front + 1) % front;
        return arr[front];
    }
    //显示队列的所有数据
    public void showQueue(){
        //遍历
        if(isEmpty()){
            System.out.println("队列为空");
        }
        //思路:从front开始遍历,遍历多少个元素
        //
        for(int i = 0; i < front + size(); i++){
            System.out.println(String.format("arr[%d] = %d\n",i % maxSize,arr[i % maxSize]));
        }
    }
    //求出有效数据个数
    public int size() {
        return (rear + maxSize - front) % maxSize;
    }
    //显示队列的头部数据,不是取出数据
    public int headQueue(){ 
        if(isEmpty()){
        throw new RuntimeException("没有数据");
        }
        return arr[front];
    }
}

单向链表

特点

1.链表是以节点的方式来储存的

2.每个节点包含data域,next域(指向下一个节点)

3.链表的顺序是由每个next来决定的

4.链表分带头结点的链表和没有头结点的链表

应用

第一种方式:直接添加链表尾部

public class singlelinkedlisy {
    public static void main(String[] args) {
        //创建节点
        HeroNode heroNode1 = new HeroNode(1, "lhb", "saui");
        HeroNode heroNode2 = new HeroNode(2, "lh", "sau");
        HeroNode heroNode3 = new HeroNode(3, "l", "sa");

        //创建链表
        SinglelinkedList singlelinkedList = new SinglelinkedList();
        //加入
        singlelinkedList.cadd(heroNode1);
        singlelinkedList.cadd(heroNode3);
        singlelinkedList.cadd(heroNode2);
        singlelinkedList.List();

    }
}

//定义SinglelinkedList
class SinglelinkedList {
    //初始化头节点,头结点不要动,不存放具体的数据
    private HeroNode head = new HeroNode(0, "", "");

    //添加节点
    //不考虑添加顺序
    public void add(HeroNode node) {
        HeroNode temp = head;
        while (true) {
            if (temp.next == null) {
                break;
            }
            temp = temp.next;
        }
        temp.next = node;
    }


    //显示链表
    public void List() {
        //判断是否为空
        if (head.next == null) {
            return;
        }
        HeroNode temp = head.next;
        while (true) {
            if (temp == null) {
                break;
            }
            System.out.println(temp);
            temp = temp.next;
        }
    }
}

class HeroNode {
    public int no;
    public String nams;
    public String nickname;
    public HeroNode next;

    public HeroNode(int no, String nams, String nickname) {
        this.no = no;
        this.nams = nams;
        this.nickname = nickname;
    }

    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", nams='" + nams + '\'' +
                ", nickname='" + nickname +
                '}';
    }
}

双向链表

双向链表的遍历,添加,修改,删除

遍历

思路

方式和单向列表一样,只是可以从后往前

代码

public void list() {
   // 判断链表是否为空
   if (head.next == null) {
      System.out.println("链表为空");
      return;
   }
   // 因为头节点,不能动,因此我们需要一个辅助变量来遍历
   HeroNode2 temp = head.next;
   while (true) {
      // 判断是否到链表最后
      if (temp == null) {
         break;
      }
      // 输出节点的信息
      System.out.println(temp);
      // 将temp后移, 一定小心
      temp = temp.next;
   }
}

修改

思路

方式和单向列表一样

代码

public void update(HeroNode2 newHeroNode) {
   // 判断是否空
   if (head.next == null) {
      System.out.println("链表为空~");
      return;
   }
   // 找到需要修改的节点, 根据no编号
   // 定义一个辅助变量
   HeroNode2 temp = head.next;
   boolean flag = false; // 表示是否找到该节点
   while (true) {
      if (temp == null) {
         break; // 已经遍历完链表
      }
      if (temp.no == newHeroNode.no) {
         // 找到
         flag = true;
         break;
      }
      temp = temp.next;
   }
   // 根据flag 判断是否找到要修改的节点
   if (flag) {
      temp.name = newHeroNode.name;
      temp.nickname = newHeroNode.nickname;
   } else { // 没有找到
      System.out.printf("没有找到 编号 %d 的节点,不能修改\n", newHeroNode.no);
   }
}

删除(比较一下单向和双向)

直接找到要删除的节点temp

temp.next.pre = temp.pre;

temp.pre.next = temp.next;

代码

public void del(int no) {

   // 判断当前链表是否为空
   if (head.next == null) {// 空链表
      System.out.println("链表为空,无法删除");
      return;
   }

   HeroNode2 temp = head.next; // 辅助变量(指针)
   boolean flag = false; // 标志是否找到待删除节点的
   while (true) {
      if (temp == null) { // 已经到链表的最后
         break;
      }
      if (temp.no == no) {
         // 找到的待删除节点的前一个节点temp
         flag = true;
         break;
      }
      temp = temp.next; // temp后移,遍历
   }
   // 判断flag
   if (flag) { // 找到
      // 可以删除
      // temp.next = temp.next.next;[单向链表]
      temp.pre.next = temp.next;
      // 这里我们的代码有问题?
      // 如果是最后一个节点,就不需要执行下面这句话,否则出现空指针
      if (temp.next != null) {
         temp.next.pre = temp.pre;
      }
   } else {
      System.out.printf("要删除的 %d 节点不存在\n", no);
   }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值