队列概念
只允许在一端进行插入数据操作,在另一端进行删除数据操作的一种特殊线性表,进行插入操作的一端称为队尾(入队列),进行删除操作的一端称为队头(出队列)
队列具有先进先出的特征
顺序队列
类型一:队头不动,出队列时队头后所有元素向前移动
缺陷:如果出队列操作很多,要搬移大量元素
类型二:队头移动,出队列时队头向后移动一个位置
如果再有F、G进行入队操作,就会出现假溢出问题
缺陷:容易造成队列假溢出
假溢出:顺序队列因多次入队列和出队列操作后出现的尚有存储空间但不 能再进行入队列操作的溢出
真溢出::顺序队列最大存储空间已经存满而又要求进行入队列操作所引起 的溢出
循环队列
将头尾相接的顺序存储队列称为循环队列,循环队列可以解决假溢出现象
循环队列如何判断队列空和满呢?
- 少用一个存储单元
- 设置一个标记位
- 设置一个计数器
链式队列
特殊的单链表,只在单链表上进行头删和尾插操作
链式队列结构的定:
typedef int DataType;
typedef struct QueueNode //节点
{
DataType _data; //数据域
struct QueueNode* _next; //指针域,指向下一个节点
}QueueNode;
typedef struct Queue //队列
{
QueueNode* _head; //队头
QueueNode* _tail; //队尾
}Queue;
链式队列基本接口实现:
typedef int DataType;
typedef struct QueueNode
{
DataType _data;
struct QueueNode* _next;
}QueueNode;
typedef struct Queue
{
QueueNode* _head; //队头
QueueNode* _tail; //队尾
}Queue;
void QueueInit(Queue* q) //初始化
{
assert(q);
q->_head = q->_tail = NULL;
}
void QueuePush(Queue* q, DataType x) //入队列
{
assert(q);
QueueNode* newnode = new QueueNode;
assert(newnode);
newnode->_data = x;
newnode->_next = NULL;
if (q->_head == NULL)
{
q->_head = q->_tail = newnode;
return;
}
q->_tail->_next = newnode;
q->_tail = newnode;
}
void QueuePop(Queue* q) //出队
{
assert(q && q->_head != NULL);
QueueNode* cur = q->_head;
q->_head = cur->_next;
delete cur;
cur = NULL;
if (q->_head == NULL)
q->_tail = NULL;
}
DataType QueueFront(Queue* q) //查看队头元素
{
assert(q && q->_tail != NULL);
return q->_head->_data;
}
DataType QueueBack(Queue* q) //查看队尾元素
{
assert(q && q->_tail != NULL);
return q->_tail->_data;
}
size_t QueueSize(Queue* q) //求队中元素个数
{
assert(q);
size_t count= 0;
QueueNode* cur = q->_head;
while (cur) {
++count;
cur = cur->_next;
}
return count;
}
int QueueEmpty(Queue* q) //判断队列是否为空
{
assert(q);
return QueueSize(q); //空返回0,非空返回非零值
}
优先级队列
带有优先级的队列称为优先级队列
队列具有先进先出的特性,即最先进入队列的元素将被最先出队列,有时也需要把进入队列中的元素分优先级(比如线程调度),出队列时首先选择优先级最高的元素出队列(优先级高先被服务VIP),对于优先级相同的元素则按照先进先出的原则出队列,即优先级队列的出队列操作不是直接将队头元素出队列,而是把队列中优 先级最高的元素出队列