• Go


    队列介绍

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

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

    数组模拟队列

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

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

    如下图所示:

    先完成一个非环形的队列(数组来实现)

    当我们将数据存入队列时称为“addqueue”,addqueue 的处理需要两个步骤:

    1、将尾指针往后移,rear + 1 ,front = rear 【空】

    2、若尾指针 rear 小于等于队列的最大下标 MaxSize - 1 ,则将数据,存入 rear 所指向的数组元素中,否则无法存入数据。rear = MaxSize - 1 【队列满】

    使用数组实现队列

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

    2、front  初始化为-1

    3、real , 表示队列尾部,初始化为 -1

    4、完成队列的基本查找:

      AddQueue //加入数据到队列

      GetQueue //从队列取出数据

      ShowQueue //显示队列

    代码如下:

    package main
    
    import (
        "errors"
        "fmt"
        "os"
    )
    
    // 使用一个结构体管理队列
    type Queue struct {
        maxSize int    
        array   [5]int // 数组=>模拟队列
        front   int    // 表示指向队列首
        rear    int    //表示指向队列的尾部
    }
    
    // 添加数据到队列
    func (this *Queue) AddQueue(val int) (err error) {
        // 先判断队列是否已满
        if this.rear == this.maxSize-1 { // 重要重要的提示; rear 是队列尾部(含最后元素)
            return errors.New("queue full")
        }
        this.rear++
        this.array[this.rear] = val
        return
    }
    
    // 从队列中取出数据
    func (this *Queue) GetQueue() (val int, err error) {
        // 先判断队列是否为空
        if this.front == this.rear { // 队空
            return -1, errors.New("queue empty")
        }
        this.front++
        val = this.array[this.front]
        return val, err
    }
    
    // 显示队列, 找到队首,然后到遍历到队尾
    func (this *Queue) ShowQueue() {
        fmt.Println("队列当前的情况是:")
        for i := this.front + 1; i <= this.rear; i++ {
            fmt.Printf("array[%d]=%d	", i, this.array[i])
        }
        fmt.Println()
    }
    
    func main() {
        // 先创建一个队列
        queue := &Queue{
            maxSize: 5,
            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(err.Error())
                } else {
    
                    fmt.Println("加入队列ok")
                }
            case "get":
                val, err := queue.GetQueue()
                if err != nil {
                    fmt.Println(err.Error())
                } else {
                    fmt.Println("从队列中取出了一个数=", val)
                }
            case "show":
                queue.ShowQueue()
            case "exit":
                os.Exit(0)
            }
        }
    }

    上面代码实现了基本队列结构,但是没有有效的利用数组空间

    数组模拟环形队列

    对前面的数组模拟队列的优化,充分利用数组,因此将数组看做是一个环形的。(通过取模的方式可以实现)

    分析思路

    1、什么时候表示队列满?  (rear + 1)% maxSize = front

    2、front = rear 【空】

    3、初始化时,front = 0  rear = 0

    4、怎么统计队列有多少个元素:

      (rear + maxSize - front)%maxSize

    遇到的问题(循环队列空一个元素的位置)

      在得到队列满足的条件:(rear+1)%maxSize ==front 时,怎么算都感觉在 rear 已经表示最后元素的后一位了,这种情况下 +1 肯定是不对的,查到一些资料:

    那么,循环队列为什么用一个空一个元素的位置呢???

    这个是根据需要来用的
    循环队列中,由于入队时尾指du针向前追赶头指针;zhi出队时头指针向前追赶尾指针,造成dao队空和队满时头尾指针均相等。因此,无法通过条件front==rear来判别队列是""还是""。
    解决这个问题的方法至少有三种:
    ①另设一布尔变量以区别队列的空和满;
    ②少用一个元素的空间。约定入队前,测试尾指针在循环意义下加1后是否等于头指针,若相等则认为队满(注意:rear所指的单元始终为空);
    ③使用一个计数器记录队列中元素的总数(即队列长度)。

    代码如下:

    package main
    
    import (
        "errors"
        "fmt"
        "os"
    )
    
    // 使用一个结构体管理环形队列
    type CircleQueue struct {
        maxSize int    // 最多存储 maxSize - 1 个元素
        array   [5]int // 数组
        front   int    //指向队列队首 0
        rear    int    //指向队尾 0
    }
    
    // 入队列 AddQueue(push)  GetQueue(pop)
    func (this *CircleQueue) Push(val int) (err error) {
        if this.IsFull() {
            return errors.New("queue full")
        }
        //分析出this.rear(tail) 在队列尾部,但是包含最后的元素
        this.array[this.rear] = val //把值给尾部
        this.rear = (this.rear + 1) % this.maxSize
        return
    }
    
    //出队列
    func (this *CircleQueue) Pop() (val int, err error) {
    
        if this.IsEmpty() {
            return 0, errors.New("queue empty")
        }
        //取出,front(head) 是指向队首,并且含队首元素
        val = this.array[this.front]
        this.front = (this.front + 1) % this.maxSize
        return
    }
    
    //显示队列
    func (this *CircleQueue) ListQueue() {
    
        fmt.Println("环形队列情况如下:")
        //取出当前队列有多少个元素
        size := this.Size()
        if size == 0 {
            fmt.Println("队列为空")
        }
    
        //设计一个辅助的变量,指向head
        tempHead := this.front
        for i := 0; i < size; i++ {
            fmt.Printf("arr[%d]=%d	", tempHead, this.array[tempHead])
            tempHead = (tempHead + 1) % this.maxSize
        }
        fmt.Println()
    }
    
    //判断环形队列为满
    func (this *CircleQueue) IsFull() bool {
        return (this.rear+1)%this.maxSize == this.front
    }
    
    //判断环形队列是空
    func (this *CircleQueue) IsEmpty() bool {
        return this.rear == this.front
    }
    
    //取出环形队列有多少个元素
    func (this *CircleQueue) Size() int {
        //这是一个关键的算法.
        return (this.rear + this.maxSize - this.front) % this.maxSize
    }
    
    func main() {
        // 初始化一个环形队列
        queue := &CircleQueue{
            maxSize: 5,
            front:   0,
            rear:    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.Error())
                } else {
    
                    fmt.Println("加入队列ok")
                }
            case "get":
                val, err := queue.Pop()
                if err != nil {
                    fmt.Println(err.Error())
                } else {
                    fmt.Println("从队列中取出了一个数=", val)
                }
            case "show":
                queue.ListQueue()
            case "exit":
                os.Exit(0)
            }
        }
    }
  • 相关阅读:
    编程之类 字符串包括问题
    Performance Counter的使用
    MVVM Light Toolkit使用指南
    Lambda表达式详解
    C#线程篇---Task(任务)和线程池不得不说的秘密(5)
    在WPF中如何使用RelativeSource绑定
    WPF中使用ObjectDataProvider绑定方法
    免费的精品: Productivity Power Tools 动画演示
    使用Myeclipse进行简单webservice开发的示例
    <context:component-scan>使用说明
  • 原文地址:https://www.cnblogs.com/taotaozhuanyong/p/14661260.html
Copyright © 2020-2023  润新知