基尔霍夫的猫 2019-06-28
队列(Queue)是一种只允许在序列两端进行操作的线性结构。和日常生活中排队等待买票的法则相似,排在队头的人先买到票并离开队列,而新来的人则加入队尾等候。因此很容易理解队列仅允许在队头出队,在队尾入队。
采用顺序存储结构的队列成为顺序队列,和顺序栈相同,我们也采用动态分配空间的方式来获取这个存储空间。那么何为循环队列呢?为什么我们需要循环队列呢?试想,我们在排队等候买票的时候是不是有这样的场景,前面的人买完票就离开队列,而这时后面的人是不是每个人都要往前挪动一个位置呢?那么如果我们以同样的方法来处理我们的队列,每当一个元素出队的时候,就必须把后面所有的元素往前挪动一个位置,这样必然导致算法效率变低。因此,我们想到了将队列的首位相连,构成了一个循环队列。
循环队列类型定义如下:
typedef struct { ElemType* base; //循环队列存储空间的基址 int front; //队头位标(指向队头元素的位置) int rear; //队尾位标(指向队尾元素的下一个位置) int maxSize; //队列的最大长度 } SqQueue;
我们采用循环队列解决了元素出队时需要移动全部元素的问题,但是出现了一个新问题,在我们判空的时候我们采用的是判断队头位标和队尾位标是否一致的方式,而放在循环队列里,因为队列已经首尾相接,于是我们会发现这时候如果队列满了,队头位标和队尾位标也是一致的,解决方式有很多,比如:
Q.front == (Q.rear + 1) % Q.maxSize
则认为队满。以下的实现中我们采用了第三种方式。
//函数结果状态代码 #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define OVERFLOW -1 typedef int Status; // 用作函数值类型,表示函数结果状态
数据结构的表示用类型定义(typedef
)描述。数据元素类型约定为ElemType,读者在使用该数据类型时自行定义,如int
、char
等简单类型。
为了便于算法描述,我们使用了 C++ 语言中的引用调用参数传递方式。
我们定义了关于循环队列操作的如下接口:
// 构造一个空队列 Q,最大队列长度为 size Status InitQueue_Sq(SqQueue &Q, int size); // 销毁队列 Q,Q不再存在 void DestoryQueue_Sq(SqQueue &Q); // 将队列置空 void ClearQueue_Sq(SqQueue &Q); // 判断队列是否为空,是返回 TRUE,否则返回 FALSE; Status QueueEmpty_Sq(Squeue Q); // 返回队列 Q 中元素个数,即队列长度 int QueueLength_Sq(SqQueue Q); // 取队头元素,用 e 返回,并返回 OK,若队列为空,返回 ERROR Status GetHead_Sq(SqQueue Q, ElemType &e); // 元素 e 入队,即在队尾插入元素 e Status EnQueue_Sq(SqQueue &Q, ElemType &e); // 队头元素出队,并用 e 返回 Status DeQueu_Sq(SqQueue &Q, ElemType &e);
Status InitQueue_Sq(SqQueue &Q, int size) { Q.base = (ElemType*)malloc(size * sizeof(ElemType)); if (NULL == Q.base) return OVERFLOW; Q.maxSize = size; Q.front = 0; Q.rear = 0; return OK; }
void DestoryQueue_Sq(SqQueue &Q) { free(Q.base); }
void ClearQueue_Sq(SqQueue &Q) { Q.front = 0; Q.rear = 0; }
Status QueueEmpty_Sq(SqQueue Q) { if (Q.front == Q.rear) return ERROR; }
int QueueLength_Sq(Squeue Q) { return (Q.rear - Q.front + Q.maxSize) % Q.maxSize; }
Status GetHead_Sq(SqQueue Q, ElemType &e) { if (QueueEmpty_Sq(Q)) return ERROR; e = Q.base[Q.front]; return OK; }
Status EnQueue_Sq(SqQueue &Q, ElemType e) { if ((Q.rear + 1) % Q.maxSize == Q.front) return ERROR; Q.base[Q.rear] = e; Q.rear = (Q.rear + 1) % Q.maxSize; return OK; }
Status DeQueue_Sq(SqQueue &Q, ElemType &e) { if (Q.front == Q.rear) return ERROR; e = Q.base[Q.front]; Q.front = (Q.front + 1) % Q.maxSize; return OK; }
《数据结构》(吴伟民,李小妹)