队列
- 队列介绍
-
队列是一个有序列表,可以使用
数组
或者链表
来实现 - 遵循 先入先出的原则(先存入队列的数据,要先取出。后存入的要后取出)
-
样例图(使用
数组模型
示意图)
队列本身是 有序列表,如上面的图之中 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
}
}
效果图: