队列

220 阅读3分钟

定义

队列(Queue)是仅在表尾进行插入操作,在表头进行删除操作的线性表(头插尾删)。它是一种先进先出(FIFO)的线性表
形如图: image.png 表尾即an端。称为队尾:表头即a1端,称为队头。`
同样的队列的储存结构也可以同时使用链队或者顺序队[然而我们常用的是循环顺序队列]。

队列抽象数据类型定义

image.png

队列的常见应用

队列的特点就是需要排队

  • 打印机打印输出:按申请的先后顺序依次输出
  • 多用户系统中,多个用户排队(是不是想到了OJ
  • 按用户的优先级排成多队,每个优先级一个队列
  • 实时控制系统,信号按接受的先后顺序依次处理

队列的实现

顺序队列

顺序队列,我们一般使用循环队列,原因在于循环利用空间,解决假上溢的问题。
设数组大小为MAXSIZEE,当rear等于MAXSIZE时,头部可能还有空间,但是却无法使用,造成了队列已满的假象,就是假上溢。

image.png

所以引进循环队列。 结构体:

typedef  struct {
    QueueElemType *base;//初始化的动态分配储存空间,其实就是base数组
    int front;//头指针,队头
    int rear;//尾指针,队尾
    //其实不是指针类型,只是表示下标位置
}SqQueue;

初始化:

//初始化
Status InitQueue(SqQueue &Q) {
//    Q.base = new QueueElemType[MAXSIZE];
    Q.base = (QueueElemType *) malloc(MAXSIZE *sizeof (QueueElemType));
    if(!Q.base) exit(-1);
    Q.front = Q.rear = 0;
    return true;
}

长度:

//长度
int QueueLength(SqQueue Q) {
    return (Q.rear - Q.front + MAXSIZE) % MAXSIZE;//循环队列,因为可能会减成负数。
    //正数等于直接减,负数等于加上MAXSIZE
}

入队:

//入队
Status EnQueue(SqQueue &Q, int e) {
    if((Q.rear + 1) % MAXSIZE == Q.front)//为了防止与队空情况相同,我们需要少用一个空间
        return false;//队满错误
    Q.base[Q.rear] =e ;//新元素插入队尾
    Q.rear = (Q.rear + 1) % MAXSIZE;//循环队列,为了节省空间,队尾指针+1,但到达队列数组的顶部,返回0位置
    return true;
}

判空:

bool QueueEmpty(SqQueue Q) {   //判断队列是否为空
    if(Q.front == Q.rear)
        return true;
    else
        return true;
}

遍历:

void Traval(SqQueue &Q) {
    int temp = Q.front;
    while(temp!= Q.rear){
        cout << Q.base[temp] << " ";
        temp++;
        temp = temp % MAXSIZE;
    }
    cout << endl;
}

出队:

//出队
Status DeQueue(SqQueue &Q, int &e) {
    if(Q.rear == Q.front)//队空
        return false;
    e = Q.base[Q.front];//保存要删除的队头元素
    Q.front = (Q.front + 1) % MAXSIZE;
    return true;
}

取队头元素:

//取队头元素
QueueElemType GetHead(SqQueue Q) {
    if(Q.front != Q.rear)
        return Q.base[Q.front];
}

链队列

当用户无法估计所用队列的长度时,则宜使用链队列 结构体:

typedef struct Qnode{
    QueueElemType data;
    struct Qnode *next;
}Qnode,*QueuePtr;

typedef struct {
    QueuePtr front;//头指针
    QueuePtr rear;//尾指针
}LinkQueue;

具体入队,出队操作: image.png 初始化:

//初始化
Status InitQueue(LinkQueue &Q){
    Q.front = Q.rear = (QueuePtr) malloc(sizeof (Qnode));//结点空间
    if(Q.front) exit(-1);
    Q.front->next = NULL;
    return true;
}

销毁:

//销毁队列
Status DestroyQueue(LinkQueue &Q){
    while(Q.front){
        QueuePtr  p = Q.front->next;
        free(Q.front);
        Q.front = p;
    }
    return true;
}

入队:

//入队
Status enQueue( LinkQueue &Q,QueueElemType e){
    QueuePtr  p = (QueuePtr) malloc(sizeof (Qnode));//结点空间
    if(!p) exit(-1);
    p->data = e;//数据域存进去
    p->next = NULL;//新结点的指针域指向空
    Q.rear->next = p;//插到尾结点后面
    Q.rear = p;//更新尾结点
}

出队:

//出队
Status DnQueue(LinkQueue &Q,QueueElemType &e){
    if(Q.front == Q.rear) return false;//队空,错误
    QueuePtr  p = Q.front->next;//头结点的下一个,就是要出的队头
    e = p->data;//用e存除队的
    Q.front->next = p->next;//将队列跨过队头链接
    if(Q.rear == p)
        Q.rear = Q.front;//防止尾结点称为野指针,(直接把他删除了d
    //delete p;
    free(p);
    return true;
}

求队头元素:

//求队头yuansu
Status GetHEead(LinkQueue Q,QueueElemType &e){
    if(Q.front == Q.rear)
        return false;//空队列,无元素可取
    e = Q.front->next->data;
    return true;
}

像其他比如遍历,判空就不写在这里了,没准那天回来写。