一、队列
定义:队列是一种特殊的线性表,特殊之处在于它只允许在表的头端(front)进行删除操作,而在表的尾端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
(1)队列的顺序表示:与顺序栈类似,队列的顺序表示也是用数组来依次存储数据元素,用front指针指向队列的头元素,用rear指针指向队列的尾元素。
队列的顺序存储结构:
typedef struct{
char *base;
int front;
int rear;
}SqQueue;
(2)队列的基本操作:
1、队列的初始化
由于队列的顺序表示中的数据元素都储存在一个数组中,所以我们首先要开辟一个数组空间,并记录它的首地址,另外,为表示这是一个空队列,我们需要将头指针和尾指针都设置为0.
算法步骤:
a.开辟数组空间,记录首地址
b.令头、尾指针为0
define sqsize 50 //此处假设为50
Status InitQueue(SqQueue &Q){
Q.base=new char[sqsize];
if(!Q.base) return ERROR;
Q.front=0;
Q.rear=0;
return OK;
}
2、入队操作:
由于队列的顺序表示的数据存储空间有限,所以将新元素入队时需判断队列是否已满,若未满,再将新元素插在队尾。
算法步骤:
a.判断队列是否已满,根据(Q.rear+1)%sqsize==Q.front
b.将新元素插放入数组。
c.根据公式得出新的尾指针值
Status InitQueue(SqQueue &Q,char e){
if((Q.rear+1)%sqsize == Q.front) return ERROR;
Q.base[rear]=e;
Q.rear=(Q.rear+1)%sqsize;
return OK;
}
3、出队操作:
将元素出队,则需判断数组是否为空,因为出队遵循“先进先出”的原则,出队需先从对头开始,一个元素出队,头指针则加一。
算法步骤:
a.判断队列是否为空
b.用e保存Q.base[front]的值
c.头指针加一(根据公式得出新的头指针值)
Status OutQueue(SqQueue &Q,char e){
if(Q.front==Q.rear) return ERROR;
e=Q.base[front];
Q.front=(Q.front+1)%sqsize;
return OK;
}
(3) 队列的链式表示——链队
链队是使用链式存储的方式来存储数据元素,使用一个个结点将数据串连起来,数据之间的联系是注重逻辑上的有序,同时,也与队列的顺序表示一样,使用头指针指向对头,使用尾指针指向队尾,但是链队却多了一个头结点。
链队的存储结构:
typedef struct QNode{
char data;
struct QNode *next;
}QNode,*LinkQueue;
typedef struct{
int front; //队头指针
int rear; //队尾指针
}Queue;
(4)链队的基本操作
1、链队的初始化
链队的初始化即构造一个指针域为空的头结点,设置头指针和尾指针的指向。
算法步骤:
a.申请一个头结点的存储空间
b.将头指针的指针域设置为NULL
c.front 、rear都指向头结点
Status InitQueue(Queue &Q){
p=new QNode;
p->next=NULL;
Q.front=p;
Q.rear=p;
return OK;
}
2、入队操作:
在将新元素入队时,即直接在队尾插入一个新结点,将原队尾结点中的指针域进行修改即可。
算法步骤:
a.为新元素申请存储空间(新结点p)
b.使原队尾结点的指针域指向p
c.使rear指向p
Status IntoQueue(Queue &Q,char e){
p=new QNode;
p->next=NULL;
Q.rear->next=p;
Q.rear=p;
return OK;
}
3、出队操作:
由于链队满足先进先出的原则,所以在将元素出队时,直接将队头元素出队,同时为了节省内存,我们要将出队结点的存储空间释放,还要注意修改队头指针的指向。
算法步骤:
a.要使元素出队,首先需判断队列是否为空
b.用p记录待释放结点地址,用e记录待出队元素
c.修改头指针指向
d.释放内存
Status OutQueue(Queue &Q,char e){
if(Q.front==Q.rear) return ERROR;
QNode *p;
p=Q.front->next;
e=p->data;
Q.front->next=p->next;
if(Q.rear == p) Q.rear=Q.front; //若删除的是队尾结点,则需使队尾指针指向头结点
delete p;
return OK;
}