队列及其基本操作

一.队列

1.队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。

队列是一种先进先出(First In First ut)的表简FIF。的一端称为队尾,允许删除的一端称为队头。假设队列是 q= ( a1,a2·....,a),那么a1 就是队头元素,而 an 是队尾元素。这样我们就可以删除时,总是从 ai 开始,而插入时,列在最后。这也比较符合我们通常生活中的习惯,排在第一个的优先出列,最后来的当然排在队伍最后, 如图所示:

 

队列存储结构的实现有以下两种方式:
顺序队列:在顺序表的基础上实现的队列结构。
链队列:在链表的基础上实现的队列结构。

两者的区别仅是顺序表和链表的区别,即在实际的物理空间中,数据集中存储的队列是顺序队列,分散存储的队列是链队列。

 2.队列如何设计

队列只有链式的设计方法,其本身分为多种队列,如顺序队列和循环队列,还有衍生的优先队列等等,以顺序队列的设计为例。

首先是队列的结点设计,可以设计出两个结构体,一个结构体 Node 表示结点,其中包含有 data 域和 next 指针,如图:

 其中 data 表示数据,其可以是简单的类型,也可以是复杂的结构体。next 指针表示,下一个的指针,其指向下一个结点,通过 next 指针将各个结点链接。

添加一个结构体,其包括了两个分别永远指向队列的队尾和队首的指针。 

 

 3.队列的抽象数据类型:

InitQueue:初始化操作,建立一个空队列 Q。
DestroyQueue:若队列Q存在,则销毁它。
ClearQueue :将队列Q清空。
QueueEmpty:若队列Q为空,返回true,否则返回 false。
GetHead:若队列Q存在且非空,用e返回队列Q的队头元素。
EnQueue:若队列Q存在,插入新元素e 到队列Q中并成为队尾元素。
DeQueue:删除队列Q中队头元素,并用e返回其值。
QueueLength:返回队列Q的元素个数。

#define OK      1
#define ERROR   0
#define OVERFLOW   -1
//#define MAXQSIZE 100  //最大队列长度
typedef int Status;
const int MaxQSize = 100;
typedef int ElemType;
typedef struct
{
    ElemType* base;  //初始化的动态分配存储空间
    int front;        //头指针,若队列不空,指向队列头元素
    int rear;         //尾指针,若队列不空,指向队列尾元素的下一个位置
    int cursize;      //循环队列元素的个数, 为0时队列空,当cursize == MAXQSIZE 时队列满 
    int maxsize;
}SeqQueue;

//构造一个空队列
Status InitQueue(SeqQueue* pe)
{
    assert(pe != nullptr);
    pe->base = (ElemType*)malloc(sizeof(ElemType) * MaxQSize);
    if (nullptr == pe->base)
    {
        exit(EXIT_FAILURE);
    }
    pe->cursize = 0;
    pe->front = 0;
    pe->rear = 0;
    pe->maxsize = MaxQSize;
    return OK;
}

//销毁队列,不再存在
void DestroyQueue(SeqQueue* pe)
{
    assert(pe != nullptr);
    free(pe->base);
    pe->base = nullptr;
    pe->front = pe->rear = pe->cursize = pe->maxsize = 0;
}

//将队列清为空
void ClearQueue(SeqQueue* pe)
{
    assert(pe != nullptr);
    pe->cursize = 0;
    pe->front = 0;
    pe->rear = 0;

}

//返回队列的元素个数,即为队列的长度
int QueueLength(const SeqQueue* pe)
{
    assert(pe != nullptr);
    return pe->cursize;
}

//检查循环队列是否为空
bool IsEmpty(const SeqQueue* pe) {
    assert(pe != nullptr);
    return pe->cursize == 0;
}

// 检查循环队列是否已满。
bool IsFull(const SeqQueue* pe) {
    assert(pe != nullptr);
    return pe->cursize == pe->maxsize;
}

//若队列不空,则用pval返回队头元素,并返回OK;否则返回ERROR
Status GetHead(const SeqQueue* pe, ElemType* pval)
{
    assert(pe != nullptr && pval != nullptr);
    if (IsEmpty(pe))
    {
        return ERROR;
    }
    *pval = pe->base[pe->front];
    return OK;
}

//若队列不空,则用pval返回的队尾元素,并返回OK;否则返回ERROR
Status GetTail(const SeqQueue* pe, ElemType* pval)
{
    assert(pe != nullptr && pval != nullptr);
    if (IsEmpty(pe))
    {
        return ERROR;
    }
    int rindex = pe->rear - 1;
    if (rindex < 0) rindex = pe->maxsize - 1;
}

//队尾插入元素val, val为新的队尾元素
Status EnQueue(SeqQueue* pe, ElemType val)
{
    assert(pe != nullptr);
    if (IsFull(pe))
    {
        return ERROR;
    }
    pe->base[pe->rear] = val;
    pe->rear = (pe->rear + 1) % pe->maxsize;
    pe->cursize += 1;
    return OK;
}

//若队列不空,则删除队头元素,用pval返回其值,并返回0K,否则返回ERROR
Status DeQueue(SeqQueue* pe, ElemType* pval)
{
    assert(pe != nullptr && pval != nullptr);
    if (IsEmpty(pe))
    {
        return ERROR;
    }
    *pval = pe->base[pe->front];
    pe->front = (pe->front + 1) % pe->maxsize;
    return OK;
}
int main()
{
    SeqQueue seq;
    InitQueue(&seq);

    DestroyQueue(&seq);
    return 0;
}

二.链队列

用链表表示的队列简称为链队列。一个链队列显然需要两个分别指示队头和队尾的指针(分别称为头指针和尾指针)才能惟一确定。这里,和线性表的单链表一样,为了操作方便起见,我们也给链队列添加一个头结点,并令头指针指向头结点。 由此,空的链队列的判决条件为头指针和尾指针均指向头结点。 

 链队列的基本操作及其代码展示:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>



#define OK 0
#define ERROR  -1
typedef int Status;   
typedef int QElemType;
typedef struct QNode
{
    QElemType data;
    struct QNode* next;
}QNode, * QueuePtr;
typedef struct
{
    QueuePtr front; // 对头指针
    QueuePtr rear;  // 队尾指针
    int cursize;    // 元素个数
}LinkQueue;

QNode* Buynode(QElemType val, QNode* narg = nullptr)      //购买节点 数据域   next域
{
    QNode* s = (QNode*)malloc(sizeof(QNode));      //购买QNode结点
    if (nullptr == s)                           //malloc不一定成功                     
    {
        exit(EXIT_FAILURE); // _exit;  abort();         exit终止当前的进程
    }
    s->data = val;
    s->next = narg;
    return s;
}
void Freenode(QNode* p)
{
    assert(p != nullptr);
    free(p);              //释放结点
}

//构造一个空队列
Status InitQueue(LinkQueue* pe)
{
    assert(pe != nullptr);
    pe->cursize = 0;
    pe->front = pe->rear = Buynode(0);
    return OK;
}
//将队列清为空
void ClearQueue(LinkQueue* pe)
{
    assert(pe != nullptr);
    while (pe->front->next != nullptr)
    {
        QNode* q = pe->front->next;
        pe->front->next = q->next;
        Freenode(q);
    }
}

//销毁队列,不再存在
void DestroyQueue(LinkQueue* pe)
{
    assert(pe != nullptr);
    ClearQueue(pe);
    Freenode(pe->front);
    pe->front = pe->rear = nullptr;
}


//返回队列的元素个数,即为队列的长度
int QueueLength(const LinkQueue* pe)
{
    assert(pe != nullptr);
    return pe->cursize;
}

//检查队列是否为空
bool IsEmpty(const LinkQueue* pe)
{
    assert(pe != nullptr);
    return pe->cursize == 0;

}
//若队列不空,则用pval返回队头元素,并返回OK;否则返回ERROR
Status GetHead(const LinkQueue* pe, QElemType* pval)
{
     assert(pe != nullptr);
     if (IsEmpty(pe))
     {
         return ERROR;
     }
     *pval = pe->front->next -> data;
     return OK;
}

//若队列不空,则删除队头元素,用pval返回其值,并返回0K,否则返回ERROR
Status DeQueue(LinkQueue* pe, QElemType* pval)
{
    assert(pe != nullptr && pval != nullptr);
    if (IsEmpty(pe))
    {
        return ERROR;
    }
    QNode* q = pe->front->next; // first;
    *pval = q->data;
    pe->front->next = q->next;
    Freenode(q);
    pe->cursize -= 1;
    if (pe->cursize == 0)
    {
        pe->rear = pe->front;
    }
    return OK;
}

int main()
{
    LinkQueue myq;
    InitQueue(&myq);
   
    int x;
    while (!IsEmpty(&myq))
    {
        DeQueue(&myq, &x);
        printf("%d\n", x);
    }

    DestroyQueue(&myq);
    return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值