学习队列 总结
队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
结构如下图所示:
队列的抽象数据类型
定义如下:
ADT 队列(Queue)
Data
同线性表,元素有相同的类型,相邻元素有前驱和后继
Operation
InitQueue(*Q);
DestroyQueue(*Q);
ClearQueue(*Q);
QueueEmpty(*Q);
GetHead(Q, *e);
EnQueue(*Q, e);
DeQueue(*Q, *e);
QueueLength(Q);
顺序队列
顺序队列:顺序存储的队列
顺序队列结构体定义
typedef int QElemType;
// 顺序存储的结构(这里是循环队列)
typedef struct
{
QElemType data[MAXSIZE];
int front; // 头指针
int rear; // 尾指针,若队列非空,指向队列尾元素的下一个位置
}SqQueue;
顺序队列的初始化
int InitQueue(SqQueue* pQueue)
{
pQueue->front = 0;
pQueue->rear = 0;
return OK;
}
入队列
int EnQueue(SqQueue* Queue, QElemType Element)
{
// 循环队列满的操作
if (Q->front == (Q->rear + 1) % MAXSIZE)
{
return ERROR;
}
// 插入元素
Q->data[Q->rear] = Element;
Q->rear = (Q->rear + 1) % MAXSIZE;
return OK;
}
出队列
// 删除队列头元素
int DeQueue(SqQueue* Queue, QElemType* Element)
{
// 队列判空
if (Q->front == Q->rear)
{
return ERROR;
}
// 队列头元素出队列
*Element = Queue->data[Queue->front];
Queue->front = (Queue->front + 1) % MAXSIZE;
return OK;
}
顺序队列置空
int ClearQueue(SqQueue* Queue)
{
Queue->front = Queue->rear = 0;
return OK;
}
顺序队列判空
int QueueEmpty(SqQueue Queue)
{
if (Queue->front == Queue->rear)
{
return TRUE;
}
else
{
return FALSE;
}
}
获取队列长度
int QueueLength(SqQueue Queue)
{
return (Queue->rear - Queue->front + MAXSIZE) % MAXSIZE;
}
链式队列
链式队列大概是下面这样的:
当队列为空时, front 和 rear 都指向头结点.
链式队列的结构体定义
typedef int QElemType;
// 链式队列结点结构体定义
typedef struct QNode
{
QElemType data;
struct QNode* next;
}QNode, *QueuePtr;
// 链式队列链表结构体定义
typedef struct
{
QueuePtr front, rear;
}LinkQueue;
链式队列的初始化
int InitQueue(LinkQueue* Queue)
{
Queue->front = Queue->rear = (QueuePtr)malloc(sizeof(QNode));
if (!Queue->front)
// 异常;
Queue->front->next = NULL;
return OK;
}
返回队列头元素
int GetLinkQueueHead(LinkQueue Queue, QElemType* Element)
{
QueuePtr CurrentQNode;
// 若为空
if (Queue->front == Queue->rear)
{
return ERROR;
}
CurrentQNOde = Queue.front->next;
*ELement = CurrentQNode->data;
return OK;
}
链式队列的长度
int LinkQueueLength(LinkQueue Queue)
{
int num = 0;
QueuePtr CurrentQNode;
CurrentQNode = Queue.front;
while(CurrentQNode != Queue.rear)
{
num++;
CurrentQNode = CurrentQNode->next;
}
return num;
}
链式队列判空
int QueueEmpty(LinkQueue Queue)
{
if(Queue.front == Queue.rear)
{
return ERROR;
}
else
{
return OK;
}
}
链式队列置空
int ClearLinkQueue(LinkeQueue* Queue)
{
QueuePtr NewQNode, OldQNode;
Queue->front = Queue->rear;
NewQNode = Queue->front->next;
Queue->front->next = NULL;
while(NewQNode)
{
OldQNode = NewQNode;
NewQNode = NewQNode->next;
free(OldQNode);
}
return OK;
}
链式队列的销毁
int DestroyLinkQueue(LinkQueue* Queue)
{
while(Queue->front)
{
Queue->rear = Queue->front->next;
free(Queue->front);
Queue->front = Queue->rear;
}
return OK;
}
入队列操作
int EnQueue(LinkQueue* Queue, QElemType Element)
{
QueuePtr NewQNode = (QueuePtr)malloc(sizeof(QNode));
if (NULL == NewQNode)
{
//异常;
}
NewQNode->data = Element;
NewQNode->next = NULL;
Queue->rear->next = NewQNode;
Queue->rear = NewQNode;
return OK;
}
出队列操作
int DeQueue(LinkQueue* Queue, QElemType* Element)
{
QueuePtr CurrentQNode;
// 判空
if (Queue->front == Queue->rear)
{
// 异常;
}
CurrentQNode = Queue->front->next;
*ELement = CurrentQNode->data;
Queue->front->next = CurrentQNode->next;
if (CurrentQNode == Queue->rear)
{
Queue->front = Queue->rear;
}
free(CurrentQNode);
return OK;
}
顺序队列与链式队列的比较
用数组实现队列时,如果不移动,随着数据的不断读写,会出现假满队列的情况。即尾数组已满但头数组还是空的。循环队列也是一种数组,只是它在逻辑上把数组的头和尾相连,形成循环队列,当数组尾满的时候,要判断数组头是否为空,不为空继续存放数据,可以有效的利用资源。但是用循环队列有个小麻烦,不好判断数列是为空还是为满;
链队列就不存在上面的问题。“循环队列”最大优点就是节省空间和少分配空间,而链队列多了一点点地址存储开销。