算法03_队列

队列

队列介绍
队列是一个有序列表,可以使用 数组或者 链表来实现
遵循 先入先出的原则(先存入队列的数据,要先取出。后存入的要后取出)
样例图(使用 数组模型示意图)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200515221726322.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2x4cHF4bA==,size_16,color_FFFFFF,t_70
队列本身是 有序列表,如上面的图之中 maxSize是该队列的 最大容量开头,结尾分别记录队列前后端的 下标(类似索引), 开头会随着数据的 输出而改变, 结尾则是随着数据的 输入而改变。
小结:
: 1.队列是有序队列
: 2.开始初始化为-1,表示队列的头,但是约定不包含头元素,即指向队列的第一个元素的前一个位置
: 3.结尾初始化为-1,表示队列的尾,但是包含最后这个元素,即指向队列尾部
: 4.判断队列空,开始 == 结尾 表示空
: 5.判断队列满,结尾 == maxSize-1

向队列加入数据的时候会有两个步骤

1 将结尾向后移:结尾+1(这个过程要判断开始结尾是否相等,如果相等队列为空)
2 判断结尾跟maxSize-1:如果结尾小于maxSize-1,则将数据放入到结尾所指向的数组元素中;否则数据无法存入,即结尾 == maxSize(队列满了,已达到最大值)

代码(没优化前)

import scala.io.StdIn

object test01 {
  def main(args: Array[String]): Unit = {

    val queue = new addDateDemo(3)
    // 菜单演示
    var key = ""
    while (true) {
      println()
      println("请选择菜单")
      println("show : 显示队列")
      println("add  : 添加数据")
      println("get  : 获取数据")
      println("peek(偷看): 查看头元素值")
      println("exit : 退出程序")
      key = StdIn.readLine()
      key match {
        case "show" => queue.show()
        case "add" =>
          println("请输入一个数")
          val num: Int = StdIn.readInt()
          queue.addDate(num)
        case "get" =>
          // 获取返回值
          val res: Any = queue.getDates()
          // 判断返回值是否为空
          if (res.isInstanceOf[Exception]){
            println(res.asInstanceOf[Exception].getMessage)
          }else{
            // 查看队列元素信息
            printf("队列取出的值=%d",res)
          }
        case "peek" =>
          // 获取返回值
          val res: Any = queue.peek()
          // 判断返回值是否为空
          if (res.isInstanceOf[Exception]){
            println(res.asInstanceOf[Exception].getMessage)
          }else{
            // 查看头元素
            printf("队列当前头元素的值=%d",res)
          }

      }


    }
  }
}

// 编写一个数据结构的基本思路  创建-遍历(查看)-修改-删除
class addDateDemo(arrMaxSize: Int) {
  // 指定队列大小
  val maxSize = arrMaxSize
  // 队列中数据,存放在数组,即数组模拟队列
  val arr = new Array[Int](maxSize)
  // 初始化开始
  var start = -1
  // 初始化结尾
  var end = -1


  // 判断队列是否满了
  def isFull(): Boolean = {
    end == maxSize - 1
  }

  // 判断队列是否为空
  def isEmpty(): Boolean = {
    start == end
  }

  // 查看队列的头元素,但是不取出
  def peek(): Any ={
    if (isEmpty()) {
      return new Exception("队列为空,什么都没有")
    }
    return arr(start+1) // start不进行+=1
  }

  // 相队列中添加数据 num
  def addDate(num: Int): Unit = {
    // 如果已经满了就不能添加进去了
    if (isFull()) {
      println("队列已满,无法加入")
      return
    }
    // 队列没满 ,将end后移
    end += 1
    arr(end) = num
  }

  // 遍历(显示)
  def show(): Unit = {
    // 先判断队列是否为空
    if (isEmpty()) {
      println("什么都没有")
      println()
      return
    }
    // 如果不为空,遍历打印结果
    println("队列数据:")
    for (i <- start + 1 to end) {
      printf("arr(%d)=%d \t", i, arr(i))
    }
    println()
  }

  // 从队列中取数据, 可能取到数据,可能取不到数据
  def getDates(): Any = {
    if (isEmpty()) {
      return new Exception("队列为空,没有数据")
    }
    // 将start后移
    // 取数据不是把数据删了,而是不让我们访问到了
    // 又因为队列前进先出,数据必须从第一个元素(也就是start)开始取,所以+1就不会再看到之前的数据
    start += 1
    return arr(start)
  }


}

效果图:
在这里插入图片描述在这里插入图片描述在这里插入图片描述

数组模拟环形队列

对前面的数组模拟队列的优化,充分利用数组。因此将数组看做是一个环形的。(通过 取模的方式来实现即可)
1.将start初始化为0,start指向队列的第一个元素
2.将end初始化为0,end指向的是队列的最后一个元素的后一个位置
3.通过%将队列当做环形,判断队列是否为空通过 start == end
4.判断队列元素满的条件是(end+1)%maxSize=start, +1的原因的预留了一个空间作为约定

代码(优化后)

import scala.io.StdIn

object test02 {
  def main(args: Array[String]): Unit = {

    val queue = new addDateDemo2(4)
    // 菜单演示
    var key = ""
    while (true) {
      println()
      println("请选择菜单")
      println("show : 显示队列")
      println("add  : 添加数据")
      println("get  : 获取数据")
      println("peek(偷看): 查看头元素值")
      println("exit : 退出程序")
      key = StdIn.readLine()
      key match {
        case "show" => queue.show()
        case "add" =>
          println("请输入一个数")
          val num: Int = StdIn.readInt()
          queue.addDate(num)
        case "get" =>
          // 获取返回值
          val res: Any = queue.getDates()
          // 判断返回值是否为空
          if (res.isInstanceOf[Exception]) {
            println(res.asInstanceOf[Exception].getMessage)
          } else {
            // 查看队列元素信息
            printf("队列取出的值=%d", res)
          }
        case "peek" =>
          // 获取返回值
          val res: Any = queue.peek()
          // 判断返回值是否为空
          if (res.isInstanceOf[Exception]) {
            println(res.asInstanceOf[Exception].getMessage)
          } else {
            // 查看头元素
            printf("队列当前头元素的值=%d", res)
          }

      }


    }
  }
}

// 编写一个数据结构的基本思路  创建-遍历(查看)-修改-删除
class addDateDemo2(arrMaxSize: Int) {
  // 指定队列大小
  val maxSize = arrMaxSize
  // 队列中数据,存放在数组,即数组模拟队列
  val arr = new Array[Int](maxSize)
  // 初始化开始
  var start = 0
  // 初始化结尾
  var end = 0


  // 判断队列是否满了
  def isFull(): Boolean = {
    (end + 1) % maxSize == start
  }

  // 判断队列是否为空
  def isEmpty(): Boolean = {
    start == end
  }

  // 查看队列的头元素,但是不取出
  def peek(): Any = {
    if (isEmpty()) {
      return new Exception("队列为空,什么都没有")
    }
    return arr(start) // start不进行+=1
  }

  // 相队列中添加数据 num
  def addDate(num: Int): Unit = {
    // 如果已经满了就不能添加进去了
    if (isFull()) {
      println("队列已满,无法加入")
      return
    }
    arr(end) = num
    // 队列没满 ,将end后移
    end = (end + 1) % maxSize
  }


  // 从队列中取数据, 可能取到数据,可能取不到数据
  def getDates(): Any = {
    if (isEmpty()) {
      return new Exception("队列为空,没有数据")
    }
    // 因为start指向队列的第一个元素
    // 先将数据保存到临时变量中
    val res: Int = arr(start)
    // start 后移
    start = (start + 1) % maxSize
    return res
  }


  // 遍历(显示)
  // 从start开始打印,打印多少个元素就可以了,所以需要统计出该队列有多少个有效元素
  def show(): Unit = {
    // 先判断队列是否为空
    if (isEmpty()) {
      println("什么都没有")
      println()
      return
    }

    // 使用取模的方式
    // 如果不为空,遍历打印结果
    println("队列数据:")
    for (elem <- start until start + size()) {
      printf("arr(%d)=%d \t", (elem % maxSize), arr(elem % maxSize))
    }
  }

  // 编写一个方法,统计当前有多少个元素
  def size(): Int = {
    return (end + maxSize - start) % maxSize
  }

}

效果图:
在这里插入图片描述在这里插入图片描述在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/lxpqxl/article/details/106150732