用数组实现一个环形队列

841 阅读4分钟

1、队列基本介绍

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

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

栈: 先入后出(弹夹)

2、数组模拟队列

  1. 队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下,其中maxSize是该队列的最大容量。

  2. 因为队列的输出、输入是分别从前后端来处理,因此需要两个变量front及rear分别记录队列前后端的下标,front会随着数据输出而改变,而rear则是随着数据输入而改变

如图所示:

image.png

上图来自网络(侵删)

image.png

3、使用数组实现简单队列非环

3.1、思路

  1. 创建一个数组arrary,是作为队列的一个字段

  2. front初始化为-1

  3. rear, 表示队列尾部,初始化为-1

  4. 完成队列的基本查找

    AddQueue // 加入数据到队列

    GetQueue // 从队列取出数据

    ShowQueue // 显示队列

表现形式为:获取键盘输入作为指令进行队列元素的添加、获取、展示和退出操作

3.2、代码实现(非环队列)

// 数组模拟队列
// 非环队列
package main

import (
	"errors"
	"fmt"
	"os"
)

/*
思路:
1. 创建一个数组arrary,是作为队列的一个字段
2. front初始化为-1
3. rear, 表示队列尾部,初始化为-1
4. 完成队列的基本查找
AddQueue // 加入数据到队列
GetQueue // 从队列取出数据
ShowQueue // 显示队列
*/

type Queue struct {
	maxSize int
	array   [4]int // 数组模拟队列
	front   int    // 队列首(下标index), 不包含队首的元素
	rear    int    // 队列尾(下标index)
}

// 添加数据到队列 - 入队列
func (que *Queue) AddQueue(val int) (err error) {
	// 先判断队列是否已满
	if que.rear == que.maxSize-1 {
		return errors.New("queue full")
	}
	que.rear++ // rear 后移
	que.array[que.rear] = val
	fmt.Println("front = ", que.front, "rear = ", que.rear, "array = ", que.array)
	return
}

// 显示队列
func (que *Queue) ShowQueue() {
	fmt.Println("显示队列: ")
	fmt.Println("front = ", que.front, "rear = ", que.rear, "array = ", que.array)
	// front初始值是 -1, 不包含队首的元素
	for i := que.front + 1; i <= que.rear; i++ {
		fmt.Printf("array[%d] = %d\n", i, que.array[i])
	}
	fmt.Println()
}

// 出队列
func (que *Queue) GetQueue() (val int, err error) {
	// 判断队列是否是空
	if que.rear == que.front {
		return -1, errors.New("queue empty")
	}
	que.front++
	val = que.array[que.front]
	que.array[que.front] = 0
	fmt.Println("front = ", que.front, "rear = ", que.rear, "array = ", que.array)
	return val, err
}

func main() {
	queue := &Queue{
		maxSize: 4,
		front:   -1,
		rear:    -1,
	}
	var key string
	var val int
	for {
		fmt.Println("1. 输入 add 表示添加数据到队列")
		fmt.Println("2. 输入 get 表示从队列中获取数据")
		fmt.Println("3. 输入 show 表示显示队列")
		fmt.Println("4. 输入 exit 表示退出")
		fmt.Scanln(&key)
		switch key {
		case "add":
			fmt.Println("请输入要入队列的数")
			fmt.Scanln(&val)
			err := queue.AddQueue(val)
			if err == nil {
				fmt.Println("加入队列成功")
			} else {
				fmt.Println(err.Error())
			}
		case "get":
			val, err := queue.GetQueue()
			if err == nil {
				fmt.Println("取到的值:", val)
			} else {
				fmt.Println(err.Error())
			}
		case "show":
			queue.ShowQueue()
		case "exit":
			os.Exit(0)
		default:
			fmt.Println("输入有误,请重新输入")
		}
	}
}

/*
get
front =  2 rear =  3 array =  [0 0 0 4]
取到的值: 3
1. 输入 add 表示添加数据到队列
2. 输入 get 表示从队列中获取数据
3. 输入 show 表示显示队列
4. 输入 exit 表示退出
get
front =  3 rear =  3 array =  [0 0 0 0]
取到的值: 4
1. 输入 add 表示添加数据到队列
2. 输入 get 表示从队列中获取数据
3. 输入 show 表示显示队列
4. 输入 exit 表示退出
get
queue empty
*/

3.3、效果展示

image.png

4、数组模拟环形队列

4.1、思路

  1. 什么时候表示队列满

    • (tail + 1) % maxSize = head
  2. tail == head 表示空

  3. 初始化时, tail = 0 head = 0

  4. 环形实现:

    • tail = (tail + 1) % maxSize, head = (head + 1) % maxSize

    • 👉核心思想:到达队尾的时候,通过 加1取模 的方式回到队首

  5. 怎么统计该队列有多少个元素

    • (tail + maxSize - head ) % maxSize

注意: 数组的长度比实际存储的长度多1

表现形式为:获取键盘输入作为指令进行队列元素的添加、获取、展示和退出操作

4.2、代码实现

// 数组模拟环形队列(有缺口)
package main

import (
	"errors"
	"fmt"
	"os"
)

/*
分析思路:
1. 什么时候表示队列满
 (tail + 1) % maxSize == head
2. tail == head 表示空
3. 初始化时, tail = 0 head = 0
4. 怎么统计该队列有多少个元素
(tail + maxSize - head ) % maxSize
*/

type CircleQueue struct {
	maxSize int
	array   [5]int
	head    int // 队首, 初始 0
	tail    int // 队尾, 初始 0
}

// 判断环形队列是否已满
func (que *CircleQueue) IsFull() bool {
	fmt.Println("IsFull --- head", que.head, "tail", que.tail)
	return (que.tail+1)%que.maxSize == que.head
}

// 判断环形队列是否为空
func (que *CircleQueue) IsEmpty() bool {
	return que.tail == que.head
}

// 环形队列所有元素
func (que *CircleQueue) Size() int {
	return (que.tail + que.maxSize - que.head) % que.maxSize
}

// 入队列
func (que *CircleQueue) Push(val int) (err error) {
	// 先判断队列是否已满
	if que.IsFull() {
		return errors.New("CircleQueue full")
	}
	que.array[que.tail] = val
	fmt.Println("head = ", que.head, "tail = ", que.tail, "array = ", que.array)
	// que.tail = (que.tail + 1) % que.maxSize
	que.tail = (que.tail + 1) % len(que.array)
	// que.tail++ // tail 后移
	return
}

// 出队列
func (que *CircleQueue) Pop() (val int, err error) {
	// 判断队列是否是空
	if que.IsEmpty() {
		return 0, errors.New("CircleQueue empty")
	}
	val = que.array[que.head]
	que.array[que.head] = 0
	fmt.Println("Pop --- head = ", que.head, "tail = ", que.tail, "array = ", que.array)
	que.head = (que.head + 1) % que.maxSize
	return val, err
}

// 显示队列
func (que *CircleQueue) ShowQueue() {
	fmt.Println("显示队列: ")
	size := que.Size()
	if size == 0 {
		fmt.Println("队列为空")
	}

	tempHead := que.head
	for i := 0; i < size; i++ {
		fmt.Printf("arr[%d]=%d\t", tempHead, que.array[tempHead])
		tempHead = (tempHead + 1) % que.maxSize
	}
	fmt.Println()
	fmt.Println("head = ", que.head, "tail = ", que.tail, "array = ", que.array)
	fmt.Println()
}

func main() {
	circleQueue := &CircleQueue{
		maxSize: 5,
		head:    0,
		tail:    0,
	}
	var key string
	var val int
	for {
		fmt.Println("1. 输入 add 表示添加数据到队列")
		fmt.Println("2. 输入 get 表示从队列中获取数据")
		fmt.Println("3. 输入 show 表示显示队列")
		fmt.Println("4. 输入 exit 表示退出")
		fmt.Scanln(&key)
		switch key {
		case "add":
			fmt.Println("请输入要入队列的数")
			fmt.Scanln(&val)
			err := circleQueue.Push(val)
			if err == nil {
				fmt.Println("加入队列成功")
			} else {
				fmt.Println(err.Error())
			}
		case "get":
			fmt.Println("取出")
			val, err := circleQueue.Pop()
			if err == nil {
				fmt.Println("取到的值:", val)
			} else {
				fmt.Println(err.Error())
			}
		case "show":
			circleQueue.ShowQueue()
		case "exit":
			os.Exit(0)
		default:
			fmt.Println("输入有误,请重新输入")
		}
	}
}

/*
get
取出
Pop --- head =  1 tail =  0 array =  [0 0 3 4 5]
取到的值: 2
1. 输入 add 表示添加数据到队列
2. 输入 get 表示从队列中获取数据
3. 输入 show 表示显示队列
4. 输入 exit 表示退出
add
请输入要入队列的数
6
IsFull --- head 2 tail 0
head =  2 tail =  0 array =  [6 0 3 4 5]
加入队列成功
1. 输入 add 表示添加数据到队列
2. 输入 get 表示从队列中获取数据
3. 输入 show 表示显示队列
4. 输入 exit 表示退出
show
显示队列:
arr[2]=3        arr[3]=4        arr[4]=5        arr[0]=6
head =  2 tail =  1 array =  [6 0 3 4 5]
*/

4.3 效果展示

image.png

image.png


🎈🎈🎈

欢迎大家点赞收藏关注转发,蟹蟹🎉🎉

我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿