队列:一种特殊的线性表,其特性就是先进先出(FIFO),即从一端进从另一端出
队头:允许删除的一端 front
队尾:允许插入的一端 rear
如下图所示,出队和入队的流程:
---------------------------------------------------------------------------------------------------------------------------------------------------
可以发现,无论是出队还是入队,front指针 和 rear指针都会增加而不是减少,因此很容易造成溢出 和 空间浪费
因此队列因为存在溢出问题所以日常的软件很少使用队列,那么如何解决,先说说两个概念:
假设最大的存储空间是6
假溢出:front != 0 ,rear = M ,再有元素插入时发生溢出 称为假溢出,存储空间还有剩余,如上图最后一张
真溢出:front = 0 ,rear = M, 再有元素插入时发生溢出 称为真溢出,存储空间已满。
因此为了使得空间不被,因此需要允许假溢出行为,即像时钟那样超过最大值则从头开始存储。
所以可以 与 最大值 QUEUE_ MAX_SIZE 取余(mod) 来继续从头开始利用空间。
而真溢出会导致存储值被破坏因此不能允许发生。如果找到满足队列满了的条件就可以阻止真溢出行为。
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
如上图,可以发现当队列空和满时,front == rear,因此为了判断队列是否真的满了,有如下三种方法:
方法一:少用一个存储单元
满的条件为
(rear + 1)%QUEUE_MAX_SIZE == front
空的条件为
rear == front
方法二:标志位
添加一个标志位 tag = 0
当入队成功 tag = 1,出队成功 tag = 0
满的条件为
rear == front && tag = 1
空的条件为
rear == front && tag = 0
方法三:计数器
添加一个计数器 count = 0
当入队成功 count++ ,出队成功 count0--
满的条件为
count > 0 && rear == front
空的条件为
count == 0
下面是队列的实现代码,使用第一种方法防止溢出
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <unistd.h> #define OK 1 #define TRUE 1 #define FALSE 0 #define ERROR 0 #define OVERFLOW -2 #define QUEUE_MAX_LEN 1024 typedef int Status; typedef int ElemType; typedef struct{ ElemType * base; //基地址 int front; //头偏移量 int rear; //尾偏移量 } sqQueue; /***********初始化**********/ Status initQueue(sqQueue *Q){ Q->base = (ElemType*)malloc(QUEUE_MAX_LEN * sizeof(ElemType)); Q->front = Q->rear = 0; return OK; } /**********是否空**********/ Status isEmpty(sqQueue Q){ if(Q.front == Q.rear)return TRUE; else return FALSE; } /**********是否满**********/ Status isFull(sqQueue Q){ if(Q.rear % QUEUE_MAX_LEN +1 == Q.front)return TRUE; else return FALSE; } /**********获取长度**********/ Status getLength(sqQueue Q){ return (Q.rear - Q.front + QUEUE_MAX_LEN) % QUEUE_MAX_LEN; } /*********获取头值**********/ Status getHead(sqQueue Q,ElemType *e){ if(isEmpty(Q))return ERROR; *e = *(Q.base + Q.front); return OK; } /***********入队**********/ Status enQueue(sqQueue *Q,ElemType e){ if(isFull(*Q))return OVERFLOW; *( Q->base + Q->rear ) = e; Q->rear = (Q->rear + 1)%QUEUE_MAX_LEN; return OK; }
/***********出队**********/Status deQueue(sqQueue *Q,ElemType *e){ if(isEmpty(*Q))return OVERFLOW; *e = *(Q->base + Q->front); Q->front = (Q->front +1 )%QUEUE_MAX_LEN; return OK; } /***********打印队列**********///事实上队列是不能这么用的//这里只是为了能看到先进先出的效果/****************************/ Status printQueue(sqQueue Q){ if(isEmpty(Q)) printf("queue is empty\n"); int len = getLength(Q); while(Q.rear - Q.front){ printf("[%d] ",*(Q.base+Q.front)); Q.front = (Q.front+1)%QUEUE_MAX_LEN; } printf("\n"); return OK; } int main(){ char sel; int val; sqQueue Q; initQueue(&Q); while(1){ system("clear"); printf("\n"); printQueue(Q); printf("e = enQueue\nd = deQueue\n"); printf("g = getHead\n"); printf("plese enter your choose[e|d|g]:"); sel = getchar(); if(sel == ‘e‘){ printf("[EnQueue]enter value:"); scanf("%d",&val); enQueue(&Q,val); } else if(sel == ‘d‘){ deQueue(&Q,&val); printf("[DeQueue]value is %d\n",val); sleep(1); } else if(sel == ‘g‘){ getHead(Q,&val); printf("[HeadVal]value is %d\n",val); sleep(1); } } return 0; }
运行结果