队列是一种特殊的线性表,它只允许在表的前端(front)进行删除操作,在表的后端(rear)进行插入操作。
特点
先进先出(First-IN First-OUT,FIFO)
基本操作
一般而言,队列是进队和出队,原则上来说从队列尾部进队,从队列头部出队
顺序队列
建立顺序队列结构必须为其静态分配或动态申请一片连续的存储空间,并设置两个指针进行管理。一个是队头指针front,它指向队头元素;另一个是队尾指针rear,它指向下一个入队元素的存储位置
1.每次在队尾插入一个元素是,rear增1;每次在队头删除一个元素时,front增1。随着插入和删除操作的进行,队列元素的个数不断变化,队列所占的存储空间也在为队列结构所分配的连续空间中移动。
2.当front=rear时,队列中没有任何元素,称为空队列。当rear增加到指向分配的连续空间之外时,队列无法再插入新元素,但这时往往还有大量可用空间未被占用,这些空间是已经出队的队列元素曾经占用过得存储单元。
顺序队列中的溢出现象:
(1) "下溢"现象:当队列为空时,做出队运算产生的溢出现象。“下溢”是正常现象,常用作程序控制转移的条件。
(2)"真上溢"现象:当队列满时,做进栈运算产生空间溢出的现象。“真上溢”是一种出错状态,应设法避免。
(3)"假上溢"现象:由于入队和出队操作中,头尾指针只增加不减小,致使被删元素的空间永远无法重新利用。当队列中实际的元素个数远远小于向量空间的规模时,也可能由于尾指针已超越向量空间的上界而不能做入队操作。该现象称为"假上溢"现象。
循环队列
在实际使用队列时,为了使队列空间能重复使用,往往对队列的使用方法稍加改进:无论插入或删除,一旦rear指针增1或front指针增1时超出了所分配的队列空间,就让它指向这片连续空间的起始位置。
在循环队列中,当队列为空时,有front=rear,而当所有队列空间全占满时,也有front=rear。为了区别这两种情况,规定循环队列最多只能有MaxSize-1个队列元素,当循环队列中只剩下一个空存储单元时,队列就已经满了。因此,队列判空的条件时front=rear,而队列判满的条件时 front=(rear+1)%MaxSize。
1.入队时队尾指针前进1:(rear+1) % MaxSize
2.出队时队头指针前进1:(front+1) % MaxSize
3.队列长度:(rear-front+MaxSize) % MaxSize
4.队满条件:(rear+1) % MaxSize == front
5.队空条件:front == rear
一、静态数组实现队列
#include<stdio.h>
#include<assert.h>
using namespace std;
#define QUEUE_SIZE 100
#define ARRAY_SIZE (QUEUE_SIZE+1)
#define QUEUE_TYPE int
void create_queue(size_t size);
void destory_queue();
void q_insert(QUEUE_TYPE value);
void q_delete(void);
QUEUE_TYPE first(void);
int isEmpty();
int isFull();
static QUEUE_TYPE queue[ARRAY_SIZE];
static size_t front = 1;
static size_t rear = 0;
void q_insert(QUEUE_TYPE value)
{
assert(!isFull());
rear = (rear + 1) % ARRAY_SIZE;
queue[rear] = value;
}
void q_delete()
{
assert(!isEmpty());
front = (front + 1) % ARRAY_SIZE;
}
QUEUE_TYPE first(void)
{
assert(!isEmpty());
return queue[front];
}
int isEmpty(void)
{
return (rear + 1) % ARRAY_SIZE == front;
}
int isFull(void)
{
return (rear + 2) % ARRAY_SIZE == front;
}
二、动态数组实现队列
#include<stdio.h>
#include<assert.h>
using namespace std;
#define QUEUE_TYPE int
static size_t QueueSize;
static QUEUE_TYPE *Queue;
static QUEUE_TYPE font=1;
static QUEUE_TYPE rear=0;
void create_queue(size_t size);
void destory_queue();
void q_insert(QUEUE_TYPE value);
void q_delete();
QUEUE_TYPE first();
int isEmpty();
int isFull();
void create_queue(size_t size)
{
assert(QueueSize==0);
QueueSize = size;
Queue = (QUEUE_TYPE*)malloc(QueueSize*sizeof(QUEUE_TYPE));
assert(Queue != NULL);
}
void destory_queue()
{
assert(QueueSize>0);
QueueSize = 0;
free(Queue);
}
void q_insert(QUEUE_TYPE value)
{
assert(!isFull());
rear = (rear + 1) % QueueSize;
Queue[rear] = value;
}
void q_delete()
{
assert(!isEmpty());
font = (font + 1) % QueueSize;
}
QUEUE_TYPE first()
{
assert(!isEmpty());
return Queue[font];
}
int isEmpty()
{
assert(QueueSize>0);
return (rear+1)%QueueSize==font;
}
int isFull()
{
assert(QueueSize>0);
return (rear + 2) % QueueSize == font;
}
三、链表实现队列
#include<stdio.h>
#include<assert.h>
using namespace std;
#define QUEUE_TYPE int
typedef struct STRUCT_NODE {
QUEUE_TYPE value;
QueueNode *next;
}QueueNode;
static QueueNode *front;
static QueueNode *rear;
void destroy_queue();
void qInsert(QUEUE_TYPE value);
void qDelete();
QUEUE_TYPE first();
int isEmpty();
int isFull();
void destroy_queue()
{
while (!isEmpty())
qDelete();
}
void qInsert(QUEUE_TYPE value)
{
QueueNode *new_node;
new_node = (QueueNode*)malloc(sizeof(QueueNode));
assert(new_node!=NULL);
new_node->value = value;
new_node->next = NULL;
if (rear == NULL)
front = new_node;
else
rear->next = new_node;
rear = new_node;
}
void qDelete(void)
{
QueueNode *next_node;
assert(!isEmpty());
next_node = front->next;
free(front);
front = next_node;
if (front == NULL)
rear = NULL;
}
QUEUE_TYPE first()
{
assert(!isEmpty());
return front->value;
}
int isEmpty()
{
return front == NULL;
}
int isFull()
{
return 0;
}