数据结构--队列(数组)的一种实现
【数据结构--队列(数组)的一种实现】单向队列(数组实现)
package mainimport (
"errors"
"fmt"
"os"
)//队列是一种重要的数据结构,应用也相对广泛,实现队列的方式主要有数组和链表两种方式
//下面首先使用数组实现一个简单的单向队列
//队列的信息包括队列的大小、队列的存储形式(数组)、队列的头(不指向第一元素)、队列的尾(指向最后一个元素)
//对列的操作方法主要有向队列添加一个元素、从队列中获取一个元素、显示队列中的元素
//定义一个结构体用于保存队列的信息
type signalQueue struct {
maxSize int
array [5]int //模拟队列
head int
tail int
}//定义一个向队列添加元素的方法
func (q *signalQueue) Push(val int) error{
//先判断队列是否已满
if q.tail == q.maxSize - 1 { //tail含最后一个元素
return errors.New("队列已满")
}
q.tail++ //向后移动尾部
q.array[q.tail] = val
return nil
}//定义一个从队列获取元素的方法
func (q *signalQueue) Pop() (val int, err error) {
//判断队列是否为空
if q.tail == q.head {
return -1, errors.New("队列为空")
}
q.head++ //由于head指向第一个元素的前面,因此要先向后移动
val = q.array[q.head]
return val, nil
}//定义一个显示队列元素的方法
func (q *signalQueue) List() error {
//找到队首(不含第一个元素),然后遍历到队尾
for i := q.head + 1;
i <= q.tail;
i++{
fmt.Printf("array[%d]=%d\t", i, q.array[i])
}
fmt.Println()
return nil
}func main (){
queue := &signalQueue{
maxSize: 5,
array:[5]int{},
head:-1,
tail:-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.Push(val)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("成功入队")
}
case "get":
val, err := queue.Pop()
if err != nil {
fmt.Println(err)
} else {
fmt.Println("出队列的数为:", val)
}
case "show":
queue.List()
case "exit":
os.Exit(0)
}
}
}//总结:
//上面实现的单向队列存在的一个最大的问题是:
//没有有效的利用数据的有效空间,会存在添加数据显示队列已满,但是获取数据又显示队列为空的情况
//解决的办法就是将数组的尾部和头部连接到一起实现一个环形队列即可解决上面的问题
环形队列(数组实现)
package mainimport (
"errors"
"fmt"
"os"
)//环形队列实现时head指向队首第一个元素,tail指向队尾元素的下一个位置,(空一个位置作为保留)
//定义一个结构体管理环形队列
type circelQueue struct {
maxSize int
array [5]int
head int
tail int
}//定义一个入队列方法
func (q *circelQueue) Push(val int) error {
//判断是否已满
if q.IsFull(){
return errors.New("队列已满")
}
q.array[q.tail] = val
q.tail = (q.tail + 1) % q.maxSize //tail指向尾部的后一个位置
return nil
}//定义一个出队列方法
func (q *circelQueue) Pop() (val int, err error) {
//判断队列是否为空
if q.IsEmpty(){
return -1, errors.New("队列为空")
}
val = q.array[q.head]
q.head = (q.head + 1) % q.maxSize //head指向下一个元素(下一个队首)
return val, nil
}//定义一个方法判断环形队列是否已满
func (q *circelQueue) IsFull () bool {
return (q.tail + 1) % q.maxSize == q.head
}//定义一个方法判断环形队列是否为空
func (q *circelQueue) IsEmpty() bool {
return q.tail == q.head
}//获取环形队列的元素个数
func (q *circelQueue) Size() int {
return (q.tail + q.maxSize - q.head) % q.maxSize
}//定义一个显示环形队列元素的方法
func (q *circelQueue) List(){
//判断队列是否为空
if q.Size() == 0 {
fmt.Println("队列为空")
}
//定义一个辅助变量指向head, 临时head
tempHead := q.head
for i := 0;
i < q.Size();
i++ {
fmt.Printf("arr[%d]=%d\t", tempHead, q.array[tempHead])
tempHead = (tempHead + 1) % q.maxSize
}
fmt.Println()
}func main(){
queue := &circelQueue{
maxSize: 5,
array:[5]int{},
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 := queue.Push(val)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("成功入队")
}
case "get":
val, err := queue.Pop()
if err != nil {
fmt.Println(err)
} else {
fmt.Println("出队列的数为:", val)
}
case "show":
queue.List()
case "exit":
os.Exit(0)
}
}
}
//总结:
//环形队列可以解决单向队列没有有效的利用数组有效空间的问题
//环形队列的实现也符合大部分应用场景
推荐阅读
- 数组常用方法一
- Java|Java基础——数组
- JS常见数组操作补充
- 《数据结构与算法之美》——队列
- JS|JS 数组求和与数组求平均值
- 超帅的js数组去重
- JavaScript|JavaScript — 初识数组、数组字面量和方法、forEach、数组的遍历
- JavaScript判断数组的方法总结与推荐
- 一些非常有用的snippets
- [leetcode数组系列]1两数之和