数据结构入门---队列

来源:互联网 发布:售后服务网络体系 编辑:程序博客网 时间:2024/05/27 08:13

本篇开始我们将开始下一个线性数据结构-队列的学习。在我们的日常生活中,排队是再常见不过的事情,先到先得,后来的等着,这没有什么问题。队列这一数据结构顾名思义,就是生活中排号排队的抽象化。例如客服人工服务时,有时会要求客户等待,待有客服人员空闲下来时会按照等待客户们的先后次序安排人工服务。或者在银行等待服务窗服务时,需要先获取一个排号单,这个排号单表示你是第几个客户,当排号次序到你的时候你才可以进行业务处理。等等之类都是应用了队列这的特性。

队列是一种特殊的线性表,它限定在一段插入元素,在另一端删除元素。其特性可以总结为 “先进先出”对于一个队列,我们称第一个元素为队头元素,最后一个元素为队尾元素。比如 Q ={ a1,a2,a3……,an} ,a1就是队头元素,an就是队尾元素

队列的抽象数据类型:

/*入队操作*/void EnQueue(T e)/*出队操作*/void DeQueue(T &e)/*清空队列*/void Clear()/*判断是否为空队列*/bool IsEmpty()/*获取队头元素*/T GetHead()/*获取队列长度*/int Length()/*从队头T队尾*/void Traverse()

队列既然是线性表的一种,所以也会有顺序与链式两种存储结构,我们还是先来介绍队列的顺序存储,也就是用数组的方式
用数组来存放一个队列,当我们想在队列中添加元素时,直接在队尾追加一个元素即可,但对于删除操作,因为队列的删除端在队头,在数组的下表为0的位置,所以删除队头元素需要将整个队列元素逐个往前移。现实生活中的排队即是如此,前一个排队的走了,后面补上去,这似乎没什么问题。不过编程与现实生活不同,我们需要时刻考虑代码的时间性能,对于每删除一个元素,我们都耗费O(n)的时间,这样性能是不是有些低呢?
其实我们不必拘泥于惯性思维,不去限制队列必须在数组前几个元素,对头也不一定非要在下标为0的位置。我们可以使用两个指针front,rear分别指向对头和队尾。空栈如下图所示
这里写图片描述
接下来我们入队a1,a2,a3,a4
这里写图片描述
继续入队a5,a6,a7,a8,出队a1,a2
这里写图片描述
这时我们发现出现了溢出的状况,因为数组无法再向后添加元素。但是这时数组的最前方却空留两个空闲空间。这种溢出我们称之为假溢出。
那么如何解决这种情况呢?道理也很简单,只要能让rear回来就行了呗。这样将我们的队列数组想象成一种循环的结构,就有了循环队列。
数组后面满了,就回来从头开始,这种首尾相接的数组队列我们称为循环队列
对于空队列,就是 front==rear。对于队列满,front与rear相差1,但它们可能只差一个单位,也可能差整一圈这里写图片描述
这里写图片描述

所以我们对于队列满的判断就为 (rear+1)%MaxSize这样取余操作。
对于队列的长度计算,也是有两种情况,当rear在front后面时,就直接用rear-front即可。当rear在front前面时,队列长度分为两段,MaxSize-front以及rear-0因此满足所有情况的长度计算公式就为 (rear-front+MaxSize)%MaxSize

那么接下来就将循环队列实现为具体的代码吧
Queue类成员变量:

template<class T>class ReQueue {private:    T *elements;    int front;  //队头    int rear;       //队尾    int MAXSIZE;        //最大长度

初始化操作:

    ReQueue()    {        /*队头队尾置0*/        this->front = 0;        this->rear = 0;        MAXSIZE = 10;   //队列最大长度        elements = new T[MAXSIZE];  //分配数组空间    }

入队操作:

    void EnQueue(T e)    {        if ((rear + 1) % MAXSIZE == front)        {            cout << "队列满" << endl;            return;        }        this->elements[rear] = e;        this->rear = (this->rear + 1) % MAXSIZE;    //如果到数组末尾则跳到数组头部    }

出队操作:

void DeQueue(T &e)    {        if (this->IsEmpty())        {            cout << "队列空" << endl;            return;        }        e = this->elements[this->front];        this->front = (this->front + 1) % MAXSIZE;  //如果到数组末尾则跳到数组头部    }

返回队列长度:

int Length()    {        return (this->rear - this->front + MAXSIZE) % MAXSIZE;    }

队列的链式存储依然与普通单链表区别不大,只是将插入限制在链表尾,删除在链表头部。

这里写图片描述

空队列时front与rea同时指向头结点。其余操作与单链表基本相同,下面直接放出入队与出队的代码

void EnQueue(T e)    {        Node *q = new Node; //生成新结点        q->data = e;        //为新结点赋值        /*链表尾插入一个元素*/        this->rear->next = q;        this->rear = q;        this->rear->next = NULL;        this->length++; //队长+1     }
void DeQueue(T &e)    {        if (this->IsEmpty())        {            cout << "空队列" << endl;            return;        }        Node *q = this->front->next;    //定位对头指针        e = q->data;        //回收删除结点数据        this->front->next = q->next;        delete q;   //回收结点空间        this->length--;     //队长-1    }
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 娃把豆豆弄进鼻孔了怎么办 20岁了不知道自己该干什么怎么办 遇到一个新手买家恶意拍下怎么办 淘宝卖螃蟹有什么要求美工怎么办 淘宝衣服吊牌剪了想退货怎么办修 用图片在淘宝搜衣服搜不到怎么办 汽车黑塑料水砂纸磨的不平怎么办 sat报名要你填10位电话怎么办 手绘板连接电脑绘画有点迟钝怎么办 走路不小心滑了一下特尴尬怎么办 小孩子头撞了头发长不出来怎么办 小孩子头磕破了不长头发怎么办 晚上洗了冷水头早上头痛怎么办 头发洗了一天就油了怎么办 米诺地尔搽剂喷了头皮油怎么办 头发可以种植吗如果是秃顶怎么办 前额头发少怎么办如何使头发增多 头发又细又软又少怎么办 宝宝一岁了头发又少又黄怎么办 生完孩子头发掉的厉害怎么办 洗完头发后头发很蓬松怎么办 头发掉的厉害怎么办吃什么好得快 头发掉的很厉害怎么办吃什么好 我头发掉的厉害怎么办吃什么药 头发干枯毛躁掉发怎么办吃什么 最近洗头时头发掉的厉害怎么办 生完小孩头发掉的厉害怎么办 生完小孩后头发掉的厉害怎么办 生完孩子后严重掉头发怎么办 生过孩子后掉头发严重怎么办 孩孑16岁了高中没考上怎么办 小孩的嘴巴里有点点该怎么办 小孩从出生哭笑嘴巴有点歪怎么办 儿童耳朵受伤后嘴巴歪了怎么办 手机锁屏图案忘了怎么办求解锁 忘给仓鼠买吃的了怎么办 两岁宝宝不爱吃饭只喝奶粉怎么办 下载百度云压缩包要提取密码怎么办 微信表情包图片过大无法添加怎么办 管理员吧群员全部踢了群主怎么办 微信笑脸表情斗图文字没有了怎么办