队列的定义:队列(Queue)是只允许在一端进行插入,在另一端进行删除。
队列的特点: 先进先出 FIFO(First in First Out)
队列的基本操作:
队列的实现(顺序) :
#define MaxSize 50
#define ElemType int
typedef struct
{
int front;//队首
int rear;//队尾
ElemType data[MaxSize];
}SqQueue;
队列的初始化:
void InitQueue(SqQueue &queue){
Q.rear =Q.front=0;
}
入队操作:
bool EnQueue(SqQueue &Q,ElemType x){
if(队列满){
return false;
}
Q.data[Q.rear] =x;
Q,rear=Q.rear+1;
return false;
}
出队操作:
bool DeQueue(SqQueue &Q,ElemType &x){
if(Q.front==Q.rear){
return false;
}
Q.front=(Q.front+1)%MaxSize;
x=Q.data[Q.front];
return true;
}
循环队列:不能用Q.rear==Q.Maxsize作为队列满的条件
循环队列判满的方法:
1牺牲一个单元来区分队空和队满
队尾指针的再下一个位置就是队头,即 (Q.rear+1)%MaxSize == Q.front
循环队列——入队:只能从队尾插入
bool EnQueue(SqQueue &Q, ElemType x){
if((Q.rear+1)%MaxSize == Q.front) //队满
return false;
Q.data[Q.rear] = x; //将x插入队尾
Q.rear = (Q.rear + 1) % MaxSize; //队尾指针加1取模
return true;
}
循环队列——出队:只能让队头元素出队
//出队,删除一个队头元素,用x返回
bool DeQueue(SqQueue &Q, ElemType &x){//
if(Q.rear == Q.front) //队空报错
return false;
x = Q.data[Q.front];
Q.front = (Q.front + 1) % MaxSize; //队头指针后移动
return true;
}
循环队列——获得队头元素
bool GetHead(SqQueue &Q, ElemType &x){
if(Q.rear == Q.front) //队空报错
return false;
x = Q.data[Q.front];
return true;
}
2不牺牲存储空间,设置size
定义size变量,用于记录队列此时记录数据元素的个数,
初始化size=0,进队成功size++,出队成功size--,根据size的值来进行判断队列的状态
队满条件:size == MaxSize
队空条件:size == 0
# define MaxSize 10;
typedef struct{
ElemType data[MaxSize];
int front, rear;
int size; //队列当前长度
}SqQueue;
//初始化队列
void InitQueue(SqQueue &Q){
Q.rear = Q.front = 0;
size = 0;
}
3不牺牲存储空间 ,设置tag
定义一个变量 tag,tag = 0 --最近进行的是删除操作;tag = 1 --最近进行的是插入操作;
每次删除操作成功时,都令tag = 0;只有删除操作,才可能导致队空;
每次插入操作成功时,都令tag = 1;只有插入操作,才可能导致队满;
队满条件:Q.front == Q.rear && tag == 1
队空条件:Q.front == Q.rear && tag == 0
# define MaxSize 10;
typedef struct{
ElemType data[MaxSize];
int front, rear;
int tag; //最近进行的是删除or插入
}SqQueue;
队列的链式存储:
typedef struct LinkNode{ //链式队列结点
ElemType data;
struct LinkNode *next;
}
typedef struct{ //链式队列
LinkNode *front, *rear; //队列的队头和队尾指针
}LinkQueue;
链式队列的基本操作——带头结点
初始化 & 判空
void InitQueue(LinkQueue &Q){
//初始化时,front、rear都指向头结点
Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
Q.front -> next = NULL;
}
//判断队列是否为空
bool IsEmpty(LinkQueue Q){
if(Q.front == Q.rear) //也可用 Q.front -> next == NULL
return true;
else
return false;
}
入队操作:
/新元素入队 (表尾进行)
void EnQueue(LinkQueue &Q, ElemType x){
LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode)); //申请一个新结点
s->data = x;
s->next = NULL; //s作为最后一个结点,指针域指向NULL
Q.rear->next = s; //新结点插入到当前的rear之后
Q.rear = s; //表尾指针指向新的表尾
}
出队操作:
//队头元素出队
bool DeQueue(LinkQueue &Q, ElemType &x){
if(Q.front == Q.rear)
return false; //空队
LinkNode *p = Q.front->next; //p指针指向即将删除的结点 (头结点所指向的结点)
x = p->data;
Q.front->next = p->next; //修改头结点的next指针
if(Q.rear == p) //此次是最后一个结点出队
Q.rear = Q.front; //修改rear指针
free(p); //释放结点空间
return true;
链式队列的基本操作——不带头结点
初始化 & 判空
void InitQueue(LinkQueue &Q){
//初始化时,front、rear都指向NULL
Q.front = NULL;
Q.rear = NULL;
}
//判断队列是否为空
bool IsEmpty(LinkQueue Q){
if(Q.front == NULL) //也可以用 Q.rear == NULL
return true;
else
return false;
}
入队操作:
//新元素入队 (表尾进行)
void EnQueue(LinkQueue &Q, ElemType x){
LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode)); //申请一个新结点
s->data = x;
s->next = NULL;
//第一个元素入队时需要特别处理
if(Q.front = NULL){ //在空队列中插入第一个元素
Q.front = s; //修改队头队尾指针
Q.rear = s;
}else{
Q.rear->next = s; //新结点插入到rear结点之后
Q.rear = s; //修改rear指针指向新的表尾结点
}
}
出队操作:
bool DeQueue(LinkQueue &Q,ElemType &x){
if(Q.front==NULL){
return false;//空队
}
LinkNode *p =Q.front;//
x=p->data;
Q.front =p->next;
if(Q.rear==p){
Q.front=NULL;
Q.rear=NULL;
}
free(p);
return true;
}
顺序存储:预分配存储空间
链式存储:一般不会队满,除非内存不足