队列的基本操作
InitQueue(&Q):初始化队列,构造一个空队列Q。
QueueEmpty(Q):判队列空,若队列Q为空返回true,否则返回false。
EnQueue(&Qx):入队,若队列Q未满,则将x加入使之成为新的队尾。
DeQueue(&Q&x):出队,若队列Q非空,则删除队头元素,并用x返回。
GetHead(Q&x):读队头元素,若队列Q非空则用x返回队头元素。
ClearQueue(&Q):销毁队列,并释放队列Q占用的内存空间。
常用的FIFO缓存其实就是队列。
顺序队列参考:顺序队列的基本操作-CSDN博客
队列(queue)是一中先进先出的(first in first out,缩写为FIFO)的线性表,它只允许在表的一端进行插入,而在另一端删除元素。这和我们日常生活中的排队是一致的,最早进入的元素最早离开。
在队列中,允许插入的一端叫做队尾(rear),允许删除的一端叫做队头(front)。
队列顺序存储的约定及说明
front指针指向队头元素
rear指针指向队尾元素的下一个位置
空队时:rear == front
队列初始化:rear = front = 0
入队:队未满时,先送值到队尾,再队尾指针加一
出队:队未空时,先取队头元素,再队头指针加一
当队列满的时候,我们就不能入队了,不过不能简单使用q->rear == MaxSize 判断队满,因为出队的过程中,数组的前面部分会有空闲,这时候入队会有上溢出,但是是假溢出。
注意:
假溢出:指队列进行多次入队与出队操作之后,队尾指针已经指向数组最后一个位置,但队列并没有被填满,如果再插入新的元素,就会超过数组的长度,这种溢出我们称为假溢出。
真溢出:指队列进行多次入队与出队操作之后,队尾指针已经指向数组最后一个位置,并且此时队列已经被填满,如果再插入新的元素,就会超过数组的长度,这种溢出我们称为真溢出。
为了改进假溢出的问题,可以将顺序队列想象为一个首尾相接的环状空间,以此逻辑来进行操作,这就是我们常说的循环队列。
顺序队列
顺序队列的定义
#include<stdio.h> #include<stdlib.h> #include<assert.h> #define ERROR 0 #define OK 1 #define TRUE 1 #define FALSE 0 #define QUEUESIZE 10 typedef int Status; typedef int QElemtype; typedef struct QNode{ QElemtype *base; int front; int rear; }SqQueue;
注意,这里的front和rear指的是数组的下标;
理解头和尾的关键是,明白队列的有效部分其实就是头和尾之间的部分。
顺序队列的初始化
void InitQueue(SqQueue *Q) { Q->base=(QElemtype*)malloc(sizeof(QElemtype)*QUEUESIZE); assert(Q->base!=NULL); Q->front=Q->rear=0; }
入队操作
Status EnQueue(SqQueue *Q,QElemtype e) { if(Q->rear==QUEUESIZE) { return ERROR; } Q->base[Q->rear]=e; Q->rear++; return OK; }
出队操作
Status DeQueue(SqQueue *Q,QElemtype *e) { if(Q->front==Q->rear) { return ERROR; } *e=Q->base[Q->front]; Q->front++; return OK; }
判断队列是否为空
Status QueueEmpty(SqQueue *Q) { if(Q->front==Q->rear) { return TRUE; } return FALSE; }
求队列长度
Status QueueLength(SqQueue Q) { return Q.rear-Q.front; }
获取队头元素
Status GetHead(SqQueue *Q,QElemtype *e) { if(Q->front==Q->rear) { return ERROR; } *e=Q->base[Q->front]; return OK; }
销毁队列
void DestoryQueue(SqQueue *Q) { if(Q->base) //队列Q存在 { free(Q->base); } Q->base=NULL; Q->front=Q->rear=0; }
清空队列
void ClearQueue(SqQueue *Q) { Q->front=Q->rear=0; }
遍历队列
void QueueTraverse(SqQueue Q,void(*visit)(QElemtype)) { int i=Q.front; while(i!=Q.rear) { visit(Q.base[i]); i++; } printf("\n"); } void Print(QElemtype e) { printf("%d ",e); }
主函数
int main() { QElemtype i,e,d; SqQueue Q; InitQueue(&Q); printf("请输入队列的%d个元素:\n",QUEUESIZE); for(i=0;i<QUEUESIZE;i++) { scanf("%d",&d); EnQueue(&Q,d); } printf("队列的元素为:"); QueueTraverse(Q,Print); printf("队列长度为:%d\n",QueueLength(Q)); int k=QueueLength(Q); printf("连续%d次由对头删除元素,队尾插入元素:\n",k/2); for(i=0;i<k/2;i++) { DeQueue(&Q,&e); printf("删除的队列的元素是:%d,请输入插入的元素:",e); scanf("%d",&d); EnQueue(&Q,d); } printf("新的队列元素为:\n"); QueueTraverse(Q,Print); int n=GetHead(&Q,&e); if(n)printf("对头元素为:%d\n",e); else { printf("队空!\n"); return -1; } ClearQueue(&Q); printf("清空队列后队列是否为空:%d\t(1:为空 ,0:不为空)\n",QueueEmpty(&Q)); DestoryQueue(&Q); printf("销毁队列后:\nQ.base=%u\tQ.front=%d\tQ.rear=%d\t\n",Q.base,Q.front,Q.rear); return 0; }
更多待补充。
ringbuffer
优秀的内存规划方法——环形缓冲区(ring buffer)-CSDN博客
【高阶】linux内核环形缓冲区ring buffer实现原理分析_linux ringbuffer-CSDN博客
ringbuffer其实就是一种循环队列。
基本操作如下:
typedef int ElemType #define MAXSIZE 1024 /*循环队列的顺序存储结构*/ typedef struct { ElemType data[MAXSIZE]; int front; //头指针 int rear; //尾指针 }SqQueue; /*初始化一个空队列*/ int Init_SeQueue(SeQueue *Q) { Q=(SeQueue *)malloc(sizeof(SeQueue)); if(Q!=NULL) { Q->front=0; Q->rear=0; } return 1; } /*求队列长度*/ int QueueLength(SeQueue *Q) { return (Q->rear-Q->front+MAXSIZE)%MAXSIZE; } /*判空*/ int SeQueue_Empty(SeQueue *Q) { return Q->rear==Q->front; } /*判满*/ int SeQueue_Full(SeQueue *Q) { return (Q->rear+1)%MAXSIZE==Q->front; } /*入队操作*/ int Enter_SeQueue(SeQueue *Q,ElemType e) { if(SeQueue_Full(Q)) { return 0; } Q->data[Q->rear]=e; Q->rear=(Q->rear+1)%MAXSIZE; return 1; } /*出队操作*/ int Delete_SeQueue(SeQueue *Q,ElemType e) { if(SeQueue_Empty(Q)) { return 0; } e=Q->data[Q->front]; Q->front=(Q->front+1)%MAXSIZE; return 1; }
更多待补充。
链队列
用链式存储实现的队列
typedef int ElemType /*结点结构*/ typedef struct QNode { ElemType data; struct QNode *next; }QNode,*QNodePtr; /*链队列结构*/ typedef struct { QNodePtr front,rear;//队头、队尾指针 }LinkQueue,*LinkQueuePtr; /*初始化一个空队列*/ int Init_LinkQueue(LinkQueuePtr Q) { Q=(LinkQueuePtr)malloc(sizeof(LinkQueue)); QNodePtr head=(QueuePtr)malloc(sizeof(QNode)); if(head!=NULL && Q!=NULL) { head->next=NULL; Q->front=head; Q->rear=head; } return 1; } /*判空*/ int LinkQueue_Empty(LinkQueuePtr Q) { return Q->front==Q->rear; } /*入队操作*/ int Enter_LinkQueue(LinkQueuePtr Q,ElemType e) { QNodePtr s=(QNodePtr)malloc(sizeof(QNode)); if(s==NULL){ return 0 } //初始化新结点 s->data=e; s->next=NULL; //建立新联系 Q->rear->next=s; Q->rear=s; return 1; } /*出队操作*/ int Delte_LinkQueue(LinkQueuePtr Q,ElemType *e) { QNodePtr p; if(LinkQueue_Empty(Q)){ return 0 } //保留删除结点的信息 p=Q->front->next; *e=p->data; //建立新联系 Q->front->next=p->next; if(Q->rear==p) { Q->rear=Q->front) } free(p); return 1; }
更多待补充。