数据结构P2.2:队列

队列的基本概念

  • 定义:队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表
  • 顺序队列特点:会存在队满的情况,容量是不可扩展的
线性表:具有相同数据类型的有限个数据元素序列
栈:只允许在一端进行插入和删除的线性表(后进后出)
队列:只允许在一端进行插入(入队),在另一端进行删除(出队)的线性表
  • 特点:先进先出(First In First Out,简称FIFO)的线性表(与栈相反)。允许插入的一为队尾,允许删除的一为队头
  • 队列的基本操作–创销、增删改查:
初始化队列:构建一个空队列Q,分配内存空间
销毁操作:销毁队列并释放栈Q所占的内存空间

插入操作:进队,若队列Q未满,则将要插入的元素x加入其队尾使之成为新的队尾
删除操作:出队,若队列Q非空,删除队头元素

查找(GetPop):读队头元素

顺序队列的实现(顺序存储结构)

  • 队列的本质也是一个线性表,线性表有两种存储形式,所以队列也分为队列的的顺序存储结构和队列的链式存储结构
  • 顺序队列的缺点:顺序存储的不足。队列元素的出队在队头,即下标为0的位置,也就意味着,队列中的所有元素都得向前移动,以保证队列的队头位置不为空。队列的顺序存储结构还会带来假溢出等问题。
  • 循环队列:环形的队列,队列的头尾相接,属于顺序存储结构。
  • 循环队列特点:
    1.队空的判断条件head== tail;
    2.设队列的最大存储空间为MAXSIZE,入队操作是,tail需要加1后移一位,赋值语句为:tail = (tail + 1) % MAXSIZE,出队操作,head加1后移的赋值语句:head = (head + 1) % MAXSIZE
取模运算:将无限的整数域映射到有限的整数集合
取模运算将存储空间在逻辑上变成“环形”

多以引入了循环队列

顺序队列的初始化

//顺序队列的定义
typedef struct{
    ElemType data[MAXSIZE];     /*静态数组存放队列中元素*/
    int head,tail;              /*队头和队尾指针,队列数组的下标 */
}SqQueue;

//初始化顺序队列
void InitQueue(SqQueue &Q){
    //初始化时,队头,队尾都指向data[0]
    Q.head=Q.tail=0;
}

//判断是否空队列
bool EmptyQueue(SqQueue Q){
    if(Q.head==Q.tail)
        return true;            /*队空*/
    else
        return false;           /*队非空*/
}

//获取队列长度
int QueueLength(SqQueue Q){
    return (Q.tail - Q.head + MAXSIZE) % MAXSIZE;
}

void testQueue(){
    SqQueue Q;                  /*声明一个顺序队列结构体Q,为其分配内存空间*/
    InitQueue (Q);
}

顺序队列的入队操作

//插入,新元素入队
bool EnQueue(SqQueue &Q, ElemType x){
    if((Q.tail+1)%MAXSIZE==Q.head) /*队满,报错*/
        return false;
    Q.data[Q.tail]=x;             /*将元素x插入队尾*/
    Q.tail=(Q.tail+1)%MAXSIZE;    /*队尾指针+1后取模*/
    return true;
}

顺序队列的出队操作

//删除,队头元素出队
bool DeQueue(SqStack &S,ElemType &x){
    if(Q.tail==Q.head)          /*队空,报错*/
        return false;
    x=Q.data[Q.tail];            /*队头元素先出队,返回元素值x*/
    Q.head=(Q.head+1)&MAXSIZE    /*队尾指针+1后取模*/
    return true;
} 

顺序队列的读取队头元素

//查找:队头元素读取操作
bool GetHead(SqStack &S,ElemType &x){
    if(Q.tail==Q.head)          /*队空,报错*/
        return false;
    x=Q.data[Q.tail];            /*队头元素先出队,返回元素值x*/
    return true;
}  

链式队列的实现(链式存储结构)

  • 定义:采用链式存储结构的队列实现方式,本质为线性表的单链表,它只能尾进头出而已,简称链队列。
  • 链式队列的特点:容量可扩展,一般不会队满,除非内存不足

链式队列的初始化

//链式队列的定义
//由链式队列的各个结点的结构体定义和链式队列组成

typedef struct LinkNode{        /*链式队列的结点*/
    ElemType data;              /*数据域*/
    struct LinkNode *next;      /*指向下一个结点的指针*/
}LinkNode;

typedef struct{                 /*链式队列的定义*/
    LinkNode *head,*tail;       /*队列的队头和队尾指针*/
}LinkQueue;

//带头结点的链式队列初始化
bool InitLinkQueue(&Q){
    LinkNode *L=(LinkNode*)malloc(sizeof(LinkNode));     /*声明一个头结点指针L并分配空间*/
    Q.head=Q.tail=L;                                    /*初始化时,队头,队尾都指向头结点*/
}

//判断是否空队列(带头结点)
bool IsEmptyQueue(Q){
    if(Q.tail==Q.head)
        return true;            /*队空*/
    else
        return false;           /*队非空*/
}

//不带头结点的链式队列初始化
bool InitLinkQueue(&Q){
    Q.head=Q.tail=NULL;                                    /*初始化时,队头,队尾都指向NULL*/
}

//判断是否空队列(不带头结点)
bool IsEmptyQueue(Q){
    if(Q.head==NULL)
        return true;            /*队空*/
    else
        return false;           /*队非空*/
}

void testLinkQueue(){
    LinkQueue Q;
    InitLinkQueue(Q);
}

链式队列的入队操作

//插入,新元素入队(带头结点)
void EnLinkQueue(LinkQueue &Q,ElemType x){
    LinkNode *s=(LinkNode*)malloc(sizeof(LinkNode));     /*声明一个新结点指针s并分配空间*/
    s->data=x;                                            /*将要插入的元素赋值给新节点的数据域*/
    s->next=NULL;                                         /*新结点s是要插入到队尾的,因此指向NULL*/    
    Q.tail->next=s;                                       /*新的结点插入到当前队列的Q的队尾,相当于当前Q的队尾指针的下一个结点是s*/
    Q.tail=s;                                             /*修改队尾指针,结点s为Q的新队尾*/
}

//插入,新元素入队(不带头结点)
void EnLinkQueue(LinkQueue &Q,ElemType x){
    LinkNode *s=(LinkNode*)malloc(sizeof(LinkNode));     /*声明一个新结点指针s并分配空间*/
    s->data=x;                                            /*将要插入的元素赋值给新节点的数据域*/
    s->next=NULL;                                         /*修改队头指针,新结点s是要插入到队尾的,因此指向NULL*/    
    //当在一个空队列中插入新元素时,这个元素为队列的第一个元素,既是队头结点也是队尾结点
    if(Q.head==NULL)
        Q.head=Q.tail=s;
    else{
        Q.tail->next=s;                                       /*新的结点插入到当前队列的Q的队尾,相当于当前Q的队尾指针的下一个结点是s*/
        Q.tail=s;                                             /*修改队尾指针,结点s为Q的新队尾*/
    }
}

链式队列的出队操作

//删除,队头元素出队(带头结点)
bool DeLinkQueue(LinkQueue &Q,ElemType &x){
    if(Q.tail==Q.head)                      /*带头结点空队判断条件*/
        return false;
    LinkNode *p=Q.head->next                /*删除的结点p是当前队列的头结点的下一个结点(当前队头head=Q.head->next)*/
    x=p->data;                              /*变量x返回当前结点p(当前队头)数据*/
    Q.head->next=p->next;                   /*修改当前Q的队头head指针为p结点的下一个结点*/
    //等价于:Q.head->next=Q.head->next->next;
    if(p==Q.tail)                           /*删除的结点p如果是队尾*/
        Q.tail=Q.head;                      /*修改tail指针*/
    free(p);                                /*释放结点p*/
    return true;
}

//删除,队头元素出队(不带头结点)
bool DeLinkQueue(LinkQueue &Q,ElemType &x){
    if (Q.head==NULL)                       /*不带头结点空队判断条件*/
        return false;
    LinkNode *p=Q.head;                     /*删除的结点p是当前队列的队头head指针指向的结点*/
    x=p->data;                              /*变量x返回当前结点p(当前队头)数据*/
    Q.head=p->next;                         /*修改当前Q的队头head指针为p结点的下一个结点*/
    //等价于:Q.head=Q.head->next;
    if(p==Q.tail)                           /*删除的结点p如果是队尾*/
        Q.tail=Q.head=NULL;                 /*队伍已删空,head和tail都要指向NULL*/
    free(p);                                /*释放结点p*/
    return true;
}

双端队列

  • :只允许一端插入和删除的线性表
  • 队列:允许一端插入、另一端删除的线性表
  • 双端队列:只允许从两端插入、两端删除的线性表
  • 输入受限双端队列:只允许从一端插入、两端删除的线性表
  • 输出受限双端队列:只允许从两端插入、一端删除的线性表
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kxwang_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值