14-数据结构和算法-数组相关

简介

编辑循环队列就是将

队列存储空间的最后一个位置绕到第一个位置,形成逻辑上的环状空间,供队列循环使用。在循环队列结构中,当存储空间的最后一个位置已被使用而再要进入队运算时,只需要存储空间的第一个位置空闲,便可将元素加入到第一个位置,即将存储空间的第一个位置作为队尾。

循环队列可以更简单防止伪溢出的发生,但队列大小是固定的。

在循环队列中,当队列为空时,有front=rear,而当所有队列空间全占满时,也有front=rear。

为了区别这两种情况,规定循环队列最多只能有MaxSize-1个队列元素,当循环队列中只剩下一个空存储单元时,队列就已经满了。

因此,队列判空的条件是front=rear,而队列判满的条件是front=(rear+1)%MaxSize

maxSize=5

初始 head=0 tail=0

----------------------------------------------------------------

0 1 2 3 4

-----------------------------------------------------------------

| | | | | |

队满情况1 我们先一次性先放满

head=0 tail=[1,2,3,4] 放入元素后this.tail 才变动 [ this.tail = (this.tail + 1) % this.maxSize ]

再放就放不进去了 因为队满 (this.tail+1)%this.maxSize == this.head==(4+1)%5=0

----------------------------------------------------------------

0 1 2 3 4

-----------------------------------------------------------------

| * | * | * | * | |

只有先取出一个 从队首开始取 取出元素后this.head才变动 取出前head=0 tail=4

取出后 head= this.head = (this.head + 1) % this.maxSize=(0+1)%this.maxSize=1 tail=4

----------------------------------------------------------------

0 1 2 3 4

-----------------------------------------------------------------

| | * | * | * | |

再取一个 从队首开始取 取出元素后this.head才变动 取出前head=1 tail=4

取出后 head= this.head = (this.head + 1) % this.maxSize=(1+1)%this.maxSize=2 tail=4

----------------------------------------------------------------

0 1 2 3 4

-----------------------------------------------------------------

| | | * | * | |

再取一个 从队首开始取 取出元素后this.head才变动 取出前head=2 tail=4

取出后 head= this.head = (this.head + 1) % this.maxSize=(2+1)%this.maxSize=3 tail=4

----------------------------------------------------------------

0 1 2 3 4

-----------------------------------------------------------------

| | | | * | |

此时 再取一个 从队首开始取 取出元素后this.head才变动 取出前head=3 tail=4

取出后 head= this.head = (this.head + 1) % this.maxSize=(3+1)%this.maxSize=4 tail=4

此时hea=tail 根据环形队列规则 这种情况就是队空

----------------------------------------------------------------

0 1 2 3 4

-----------------------------------------------------------------

| | | | | |

此时我们再放入一个元素 放入前 head=4 tail=4

队满条件不会触发 (this.tail+1)%this.maxSize == (4+1)%5 =0 != this.head 所以可以放入

从队尾放开始放入 放入后tail才变动

放入后: head=4 this.tail = (this.tail + 1) % this.maxSize=(4+1)%5=0

----------------------------------------------------------------

0 1 2 3 4

-----------------------------------------------------------------

| | | | | * |

再放入一个 放入前 head=4 tail=0

放入后: head=4 this.tail = (this.tail + 1) % this.maxSize=(0+1)%5=1

----------------------------------------------------------------

0 1 2 3 4

-----------------------------------------------------------------

| * | | | | * |

由此可见 head和tail都要规避数组越界 即存入和取出时都会+1然后和总长度取模

再放入一个 放入前 head=4 tail=1

放入后: head=4 this.tail = (this.tail + 1) % this.maxSize=(1+1)%5=2

----------------------------------------------------------------

0 1 2 3 4

-----------------------------------------------------------------

| * | * | | | * |

队满情况2再放入一个 放入前 head=4 tail=2

放入后: head=4 this.tail = (this.tail + 1) % this.maxSize=(2+1)%5=3

----------------------------------------------------------------

0 1 2 3 4

-----------------------------------------------------------------

| * | * | * | | * |

再放就放不进去了 因为队满 (this.tail+1)%this.maxSize == this.head==(3+1)%5=4=head

只有先取出一个 从队首开始取 取出元素后this.head才变动 取出前head=4 tail=3

取出后 head= this.head = (this.head + 1) % this.maxSize=(4+1)%this.maxSize=0 tail=3

----------------------------------------------------------------

0 1 2 3 4

-----------------------------------------------------------------

| * | * | * | | |

队满情况3再放入一个 放入前 head=0 tail=3

放入后: head=0 this.tail = (this.tail + 1) % this.maxSize=(3+1)%5=4

----------------------------------------------------------------

0 1 2 3 4

-----------------------------------------------------------------

| * | * | * | * | |

再放就放不进去了 因为队满

(this.tail+1)%this.maxSize == this.head==(4+1)%5=0=head

队列中总共的元素个数: ([0,(整数A-1)) + 整数A)%整数A 其取值范围在[0,整数A)

(this.tail - this.head + this.maxSize) % this.maxSize

最后一种情况长度: (3-4+5)%5=(-1+5)%5=4%5=4

遍历分两种情况(这是特别要注意的地方)

head

head>tail 这是规避数组越界情况发生的遍历 比如最后一种情况head=4 tail=3

package main

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

// 使用一个结构体管理队列
type CircleQueue struct {
    maxSize int //5
    array   []int
    head    int //指向队首 0 有效元素的前一个位置
    tail    int //指向队尾 0
}

func NewCircleQueue(maxSize int) *CircleQueue {
    queue := &CircleQueue{
        maxSize: maxSize,
        array:   make([]int, maxSize),
        head:    0,
        tail:    0,
    }

    return queue
}

// 入队
func (this *CircleQueue) Push(val int) error {
    if this.IsFull() {
        return errors.New("队满")
    }
    fmt.Println("入队前: head=", this.head, "tail=", this.tail, "len=", this.Size())
    //从队尾放
    this.array[this.tail] = val
    //重新设置队尾标志位 有可能又到前面0的位置
    this.tail = (this.tail + 1) % this.maxSize
    fmt.Println("入队后: head=", this.head, "tail=", this.tail, "len=", this.Size())

    return nil
}

// 出队
func (this *CircleQueue) Pop() (int, error) {
    if this.IsEmpty() {
        return -1, errors.New("队空")
    }
    fmt.Println("出队前: head=", this.head, "tail=", this.tail, "len=", this.Size())
    //从队首取
    val := this.array[this.head]
    this.array[this.head] = 0
    //head指向队首 且包含队首 有可能又到前面0的位置
    this.head = (this.head + 1) % this.maxSize
    fmt.Println("出队后: head=", this.head, "tail=", this.tail, "len=", this.Size())
    return val, nil
}

// 判断队满
func (this *CircleQueue) IsFull() bool {
    return (this.tail+1)%this.maxSize == this.head
}

// 判断队空
func (this *CircleQueue) IsEmpty() bool {
    return this.tail == this.head
}

// 获取环形队列有多少个元素
func (this *CircleQueue) Size() int {
    return (this.tail - this.head + this.maxSize) % this.maxSize
}

// 显示队列
func (this *CircleQueue) ListQueue() {
    size := this.Size()
    if size <= 0 {
        fmt.Println("队空 显示不了")
        return
    }
    fmt.Println("list: head=", this.head, "tail=", this.tail, "len=", size)
    if this.head < this.tail {
        for i := this.head; i < this.tail; i++ {
            fmt.Printf("arr[%d]=%d \n", i, this.array[i])
        }
    } else { // this.head>this.tail 规避数组越界情况发生的遍历

        if this.tail-1 >= 0 {
            for j := 0; j < this.tail; j++ {
                fmt.Printf("arr[%d]=%d \n", j, this.array[j])
            }
        }

        for i := this.head; i < this.maxSize; i++ {
            fmt.Printf("arr[%d]=%d \n", i, this.array[i])
        }

    }
}

func main() {

    // //创建队列
    queue := NewCircleQueue(5)

    var key string
    var val int
    for {
        fmt.Println(" 输入push表示添加数据到队列")
        fmt.Println(" 输入pop表示从队列获取数据")
        fmt.Println(" 输入list表示显示队列数据")
        fmt.Println(" 输入exit表示退出")

        fmt.Scanln(&key)
        switch key {
        case "push":
            fmt.Println("请输入入队数据")
            fmt.Scanln(&val)
            err := queue.Push(val)
            if err != nil {
                fmt.Println("Push err: ", err.Error())
            } else {
                fmt.Println("Push ok")
            }
        case "pop":
            val, err := queue.Pop()
            if err != nil {
                fmt.Println("Pop err: ", err.Error())
            } else {
                fmt.Println("Pop ok val=", val)
            }
        case "list":
            queue.ListQueue()
        case "exit":
            os.Exit(0)
        }
    }

    //fmt.Println("OK")
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夸父手杖

谢谢老板

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值