1.队列
队列:一种先进先出的线性表,为什么是先进先出呢?因为它删除元素是在队头,而插入元素是在队尾,就像这样:
我们每插入一个数据,队尾指针就向后移一位,每删除一个数据队尾指针就向前移动一位,如我们删除一个数据就得到下图:
得到:
但是这样我们会发现这样每次删除数据的时间复杂度就是O(n),那么有没有什么好的方法让它变得更快一点呢?
这就出现了循环队列:
2.循环队列
循环队列不一样的地方就在于:
- 删除元素时不移动队尾指针,而是将队头指针向后移一位,这样大大提高了时间复杂度。
- 防止删除元素后前面空间的浪费,使用取模运算使队列抽象为循环队列,这里他不是存储空间链接起来,只是我们将它物理结构抽象为循环队列。
如下图,如果我们继续插入新的元素:
3.关键点
下面我将说明几个关键的代码实现,先引入两个指针:front指向队头,rear指向队尾,
1.判断队列为空和队列是否已满:
我们发现:当队列为空时:front和rear指向同一个位置,但是当队列已满的时候,还是一样的情况,这要怎么办呢?
这时就出现了一个巧妙的解决方法:空出一个单元区分队列满了和空的状态,如下图:
我们可以看到,上图中队列满了有两种情况,而队列空就可以用front和rear是否相等来判断。假设队列的最大容量为:MAXSIZE,我们就可以用:(rear+MAXSIZE-front)%MAXSIZE == 0
来判断队列是否已经满了。
代码
费了这么多话,下面就直接上代码了
头文件:
#define MAXSIZE 10
#define OK 1
#define ERROR 0
typedef int QElemType;
typedef struct {
QElemType data[MAXSIZE];
int front;
int rear;
}SqQueue;
int InitQueue(SqQueue* Q);//初始化操作,建立一个空队列
int DestroyQueue(SqQueue *Q);//若队列存在,则销毁他
int ClearQueue(SqQueue *Q);//将队列Q清空
int QueueEmpty(SqQueue *Q);//若队列为空,返回true,否则返回flase
int GetHead(SqQueue Q,QElemType *e);//若队列存在且非空,用e返回队列Q的队头元素
int EnQueue(SqQueue* Q, QElemType e);//若队列Q存在,插入新元素E到队列Q中并成为队尾元素
int DeQueue(SqQueue* Q, QElemType* e);//删除队列Q中队头元素,并用e返回其值
int QueueLength(SqQueue *Q);//返回队列Q的元素个数
放函数的文件(有几个函数的代码就交给你们完成啦(主要是懒得写了,狗头保命嘿嘿)):
#include "head.h"
int InitQueue(SqQueue* Q) {
Q->front = 0;
Q->rear = 0;
return OK;
}
int DestroyQueue(SqQueue* Q) {
return 0;
}
int ClearQueue(SqQueue* Q) {
return 0;
}
int QueueEmpty(SqQueue* Q) {
if (Q->front == Q->rear)
return OK;
return ERROR;
}
int GetHead(SqQueue Q, QElemType* e) {
return 0;
}
int EnQueue(SqQueue* Q, QElemType e) {
if ((Q->rear + 1) % MAXSIZE == Q->front) {
return ERROR;
}
Q->data[Q->rear] = e;
Q->rear = (Q->rear + 1) % MAXSIZE;
return OK;
}
int DeQueue(SqQueue* Q, QElemType* e) {
if (Q->front == Q->rear)
return ERROR;
*e = Q->data[Q->front];
Q->front = (Q->front + 1) % MAXSIZE;
return OK;
}
int QueueLength(SqQueue *Q) {
return (Q->rear + MAXSIZE - Q->front) % MAXSIZE;
}
主函数:
#include "head.h"
#include <stdio.h>
#include <stdlib.h>
int main(void) {
SqQueue Q;
QElemType data;
InitQueue(&Q);
scanf_s("%d",&data);
while (data) {
if (EnQueue(&Q, data) == ERROR) {
printf("\n队列已满!\n");
return -1;
}
scanf_s("%d", &data);
}
while (DeQueue(&Q, &data) == OK) {
printf("data:%d\n", data);
}
return 0;
}
这里就是一个简单的入队列出队列,当然怎么能少了测试结果呢:
大家可以看到:1是最先入队列的,1也是最先出队列的,这就是先进先出了
因为我们空出了一个单元,我们的MAXSIZE设置的是10,所以在进入第十个元素的时候就报错了。
总结
荒废了将近一个周,害,重新振作,重新加油吧,冲冲冲!