数据结构之队列queue

来源:互联网 发布:竞彩代购软件 编辑:程序博客网 时间:2024/05/21 17:08

C++数据结构之队列queue

  • 什么是队列

  • 队列的基本特征

  • 队列是如何工作的

  • 队列的实现

  • 队列的应用

什么是队列

与栈相反,队列是一种先进先出(FIFO)的线性表,只允许在表的一端插入,在另一端删除。允许插入的一端叫队尾,允许删除 的一端叫队头。比较典型的例子有日常生活中的排队:银行排序办理业务、地铁排队上车(emmmm,这里假设所有人都遵守秩序)等,当然还有计算机系统的消息队列,操作系统的作业调度(这两者都可以看做是队列,不过是队列的高级应用:优先级队列)等


队列的基本特征

- 先进先出(FIFO)- 限制插入和删除:队尾(back)插入,队头(front)删除

队列是如何工作的

如下图所示:

队列

front代表队头,back代表队尾,初始状态,front与back指向同一位置,当插入一个新元素a后,队尾back向后移动一位,队头front不动,指向下一个位置,当在a的下一个位置插入元素b时,队尾back继续向后移动一位,直到满队列,此时back指向最后的位置。当删除一个元素时,队头front向后移动一位,队尾back不动。在这种队列结构下,可以通过(front == back)来判断队列是否为空。

队列的实现

队列的实现主要有两种方式:顺序表和链表;队列的操作主要有:取出队头元素(front())、删除队头元素(pop())、队尾插入元素(push())、是否为空(Empty())、队列元素数(size())、是否已满(Full())

顺序表实现队列

顺序表的实现较为简单,直接使用数据存储数据即可,而frontback代表数组的下标(索引),这样做的缺点就是队列的长度固定,同时由于每次删除元素时,队头向后移动一位,当队列中所有元素被删除时,此时front ==back,但是,此时继续向队列中插入元素时,就会出现数组越界的情况。

越界

如上所示,此时,frontback都以指向了最后位置,无法继续在队列中插入数,但是,front前面的空间仍旧是空的,没有存储内容,此时如果采用动态内存分配无疑会浪费内存空间,因此,为了能够充分利用已分配的数组空间,可以将数组想象为一个首尾相接的环,循环存储数据,称之为循环队列。

循环队列

如上,将数组想象成环状,初始时,frontback都指向起始位置,当有元素插入或者删除时,进行相应的移动,直到back的下一个位置为front时,队列为满。由于是环状的,因此,frontback的代表的位置应该对队列的长度取余后,才为数组的下标。同时,为了便于判断队列为满和队列为空,在设置队列长度时,应该为length+1,因为back始终指向队尾元素的下一个位置,所以,当队列满时,back应该指向队列长度的下一个位置,从而,可以通过(back+1)%(length+1) == front判断队列满,通过back==front判断队列为空。

代码实现

//头文件定义template <typename T>class Queue  {public:    Queue(int max_size);    virtual ~Queue();    T & Front() const;    void Pop();    void Push(T &element);    bool Empty() const;    int size() const;    bool Full() const;private:    int front_;    int back_;    int size_;    int max_size_;    T *contain; //队列指针};//代码实现#include "Queue.h"#include <iostream>#include <assert.h> //////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////template <typename T>Queue<T>::Queue(int max_size) {    front_ = back_ = 0;    size_ = 0;    max_size_ = max_size + 1;    contain = new T[max_size_]; //比队列长度多一个元素,用于辅助存放back_以及判断满}template <typename T>Queue<T>::~Queue() {    delete [] contain;}template <typename T>bool Queue<T>::Empty() const {    return front_ == back_; //指向同一位置}template <typename T>T & Queue<T>::Front() const {    assert(!Empty());   //断言不为空,为空则程序直接报出异常中止    return contain[front_];}template <typename T>bool Queue<T>::Full() const {    return (back_ + 1) % max_size_ == front_;   //由于是环状所以对最大长度取余}template <typename T>void Queue<T>::Pop() {    front_ = (front_ + 1) % max_size_;    size_--;}template <typename T>void Queue<T>::Push(T &element) {    assert(!Full());    contain[back_] = element;    back_ = (back_ + 1) % max_size_;    size_++;}template <typename T>int Queue<T>::size() const {    return size_;}

链表实现队列

用链表来实现队列更符合队列的特征,不需要进行循环,删除队头元素直接释放队头元素空间即可,插入队尾时,直接新增空间即可添加,同时队尾指针指向队尾元素,不再指向下一节点,如下图所示。

链式队列

与链表不同的是,链表有头结点,而队列不需要头结点,空队列时,队头指针与队尾指针都指向NULL,同时此时判断队列满也没有什么意义。因而用链表实现队列的功能有取头节点(Front())、删除头节点(Pop())、插入新元素(Push())、是否为空(Empty())、队列中元素个数(size())

代码实现

//头文件定义template <typename T>//节点struct ListNode{    T data;    ListNode<T> *link;};//链表类template <typename T>class ListQueue  {public:    ListQueue();    virtual ~ListQueue();    T & front() const;    void Pop();    void Push(T &element);    bool Empty() const;    int size() const;private:    int size_;    ListNode<T> *front_;    ListNode<T> *back_;};//cpp实现#include "ListQueue.h"#include <iostream>#include <assert.h>//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////template <typename T>ListQueue<T>::ListQueue() {    front_ = back_ = NULL;    size_ = 0;}template <typename T>ListQueue<T>::~ListQueue() {    while (!Empty()) {        this->Pop();    }}template <typename T>bool ListQueue<T>::Empty() const {    return front_ == NULL;}template <typename T>T & ListQueue<T>::front() const{    assert(!Empty());    return front_->data;}template <typename T>void ListQueue<T>::Pop() {    assert(!Empty());    ListNode<T> *temp = front_;    front_ = front_->link;    delete temp;    size_--;}template <typename T>void ListQueue<T>::Push(T &element) {    ListNode<T> *new_node= new ListNode<T>;    new_node->data = element;    new_node->link = NULL;    if (back_ == NULL) {        front_ = back_ = new_node;    } else {        back_->link = new_node;        back_ = back_->link;    }    size_++;}template <typename T>int ListQueue<T>::size() const {    return size_;}

队列的应用

  • 编程练习之队列篇:舞伴问题

  • 编程练习之队列篇:游程编码问题

  • 编程练习之队列篇:杨辉三角问题

  • 编程练习之队列篇:优先级队列

未完待续


以上是我关于队列的学习心得,如果有什么不对的地方,欢迎大家指出,一起交流讨论

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 两岁宝宝钙吸收不好怎么办 1岁宝宝害羞胆小怎么办 2岁宝宝害羞胆小怎么办 6个月的宝宝胆小怎么办 3岁半宝宝很胆小怎么办 分手了想他了怎么办 分手了还想联系怎么办 2岁多宝宝不长肉怎么办 2个月宝宝尿裤子怎么办 四岁宝宝脾气大怎么办 两周宝宝换奶粉怎么办 两周半宝宝不喝奶粉怎么办 2岁半宝宝太调皮怎么办 2岁宝宝晚上睡觉晚怎么办 三周岁半宝宝入园后不合群怎么办 数学懒于思考的孩子怎么办 2岁宝宝爱哭不讲道理怎么办 孩子不讲道理一直哭怎么办 白天不烧晚上烧怎么办 两岁宝宝出虚汗怎么办 两岁宝宝出水痘怎么办 两岁宝宝爱看手机怎么办 两岁宝宝太好动怎么办 五岁宝宝不会数数怎么办 四岁宝宝算数不好怎么办 两个月宝宝体内有火怎么办 两个月宝宝有火怎么办 2岁宝宝起眼屎怎么办 一周岁的宝宝皮肤过敏怎么办 两岁宝宝脾气倔不听话怎么办 22个月宝宝打人怎么办 两岁宝宝会打人怎么办 3岁哭闹倔强不止怎么办 我儿子二十三岁不爱说话怎么办 2岁宝宝不听话脾气大怎么办 2岁宝宝调皮不听话怎么办 2岁的宝宝不听话怎么办 2岁宝宝总是不听话怎么办 2岁宝宝淘气不听话怎么办 两岁宝宝不听大人的话怎么办? 来月经奶量减少怎么办