为什么80%的码农都做不了架构师?>>>
数据结构与算法 3.4 队列ADT
像栈一样,队列(queue)也是表。然而,使用队列时插入在一端进行而删除则在另一端进行。
3.4.1 队列模型
队列的基本操作是Enqueue(入队),它是在表的末端(或叫队尾(rear))插入一个元素,还有一个Dequeue(出队),它是删除(或返回)在表的开头(叫做队头(front))的元素。
图3-56显示一个队列的抽象模型:
+------------+Dequeue(Q) | | Enqueue(Q, X)
<---------- | Queue Q | <-------------| |+------------+图3-56 队列模型
3.4.2 队列的链表实现
我们讨论队列的链表实现,对于每一个队列数据结构,我们需要保留一个Front指针与一个Rear指针用于标记队头及队尾。 图3-57显示一个队列的双向链表实现示例:
+----------+ +---------+ +---------+ +---------+
|\0|Head|68|---> |58| A |88|---> |68| B |99|---> |88| C |\0|
+----------+ +---------+ +---------+ +---------+↑ ↑ +---------+ +---------+ | Front | | Rear | +---------+ +---------+图3-57 队列双向链表实现
头文件 - queue.h
#include <stdio.h>
#include <stdlib.h>
#include "../../fatal.h"typedef int ElementType;struct Node;
typedef struct Node *PtrToNode;
typedef PtrToNode Queue;
typedef PtrToNode Position;
typedef PtrToNode Front;
typedef PtrToNode Rear;// 创建队列
Queue CreateQueue(Queue);
// 入队
void Enqueue(Queue, ElementType);
// 出队
ElementType Dequeue(Queue);
// 输出队列
void PrintQueue(Queue);
源文件 - queue.c
#include "queue.h"// 创建新的节点
static Position NewNode(void);
// 是否空队列
static int IsEmptyQueue(Queue);
// 队列清空
static void MakeEmptyQueue(Queue);struct Node {ElementType Element;PtrToNode Next;PtrToNode Prev;
};// 队头Front
static Front QueueFront = NULL;
// 队尾Rear
static Rear QueueRear = NULL;/*** 创建新的节点* @return */
static Position NewNode() {return (Position)malloc(sizeof(struct Node));
}/*** 是否空队列* @param Q* @return */
static int IsEmptyQueue(Queue Q) {return Q->Next == NULL;
}/*** 队列清空* @param Q*/
static void MakeEmptyQueue(Queue Q) {Position P, Tmp;P = Q->Next;while (P != NULL) {Tmp = P->Next;free(P);P = Tmp;}Q->Next = NULL;QueueFront = Q;QueueRear = Q;
}/*** 创建队列* @param Q* @return */
Queue CreateQueue(Queue Q) {if (Q != NULL) {MakeEmptyQueue(Q);}Q = NewNode();if (Q == NULL) {FatalError("Out of memory!");}Q->Next = NULL;Q->Prev = NULL;QueueFront = Q;QueueRear = Q;return Q;
}/*** 入队* @param Q* @param */
void Enqueue(Queue Q, ElementType X) {Position TmpCell = NewNode();if (TmpCell == NULL) {FatalError("Out of memory!");}if (IsEmptyQueue(Q)) {QueueRear = TmpCell;} else {Q->Next->Prev = TmpCell;}TmpCell->Element= X;TmpCell->Next = Q->Next;TmpCell->Prev = Q;Q->Next = TmpCell;QueueFront= TmpCell;
}/*** 出队* @param Q* @return */
ElementType Dequeue(Queue Q) {if (IsEmptyQueue(Q)) {FatalError("Queue is empty!");}Position Prev = QueueRear->Prev;ElementType X = QueueRear->Element;Prev->Next= NULL;free(QueueRear);QueueRear = Prev;return X;
}/*** 输出队列* @param Q*/
void PrintQueue(Queue Q) {if (IsEmptyQueue(Q)) {FatalError("Queue is empty!");}Position P = Q->Next;while (P != NULL) {printf("|%x|%d|%x|", P->Prev, P->Element, P->Next);P = P->Next;if (P != NULL) {printf("-->");}}printf("\n");
}
调用示例
#include "ext/s16/queue.h"int main(int argc, char** argv) {Queue Q = CreateQueue(NULL);Enqueue(Q, 5);Enqueue(Q, 6);Enqueue(Q, 7);Enqueue(Q, 8);PrintQueue(Q);Dequeue(Q);PrintQueue(Q);Dequeue(Q);PrintQueue(Q);Dequeue(Q);PrintQueue(Q);return (EXIT_SUCCESS);
}