队列---基本概念、顺序队列

一、基本概念

队列(Queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。

队列是一种先进先出(First In First Out)的线性表,简称FIFO。允许插入的一端称为队尾,允许删除的一端称为队头。

队列---基本概念、顺序队列_第1张图片

队列基本操作:

InitQueue()     ——初始化队列
EnQueue()        ——进队列
DeQueue()        ——出队列
IsQueueEmpty()   ——判断队列是否为空
IsQueueFull()    ——判断队列是否已满

队列可以由数组和链表两种形式实现队列操作。分别称为顺序队列和链队列。

顺序队列:顺序存储的队列。
链队列:链式存储的队列,长度没限制。

二、顺序队列

我们一直都是用数组来实现顺序存储的,顺序队列也不例外。所以我们可以定义一个数组int data[MAXSIZE] 来存储队列的元素。另外,我们还需要两个指针,来标记队头和队尾。

实现要点:

(1)顺序队列初始化:就是把队头和队尾都归0,也就是 Q->front=0; Q->rear=0;

每当插入新的队列尾元素时,“尾指针增1”;每当删除队列头元素时,“头指针增1”。因此,非空队列中,头指针始终指向队列头元素,而尾指针始终指向队列尾元素的下一位置。如图:

队列---基本概念、顺序队列_第2张图片

(2)入队的算法应该怎么写?队列是线性表,用数组实现,因此首先要判断队列是不是满的。

如何判断一个队列是否满的?
假设我们在军训中排队,每个人报数。一个队列只能站10个人,从1报到10,队就满了。后来呢,队头的两个人出队了,然后又补充了两个新队员,那么这时候的报数是3到12。这时队列也是满的。两种情况下判断队满的条件分别为:

(10 + 1) mod 10 = 1
(12 + 1) mod 10 = 3

所以队列满的条件就是 :

(Q->rear+1)%MAXSIZE == Q->front 

(3)如果队不满,我们就可以入队了。

思路就是,先给队尾元素赋值,然后再将队尾指针向后移动一位。

比如从空队列开始,此时 Q->front == Q->rear,这个时候插入元素的话,其实就是给 data[Q->rear] 赋值 e;然后队尾指针 Q->rear 向后移动一位重新赋值,使用

Q->rear = (Q->rear+1)%MAXSIZE; 

即可完成尾指针后移。入队操作:

/* 若队列未满,则插入元素e为Q新的队尾元素 */
Status EnQueue(SqQueue *Q,QElemType e)
{
    if ((Q->rear+1)%MAXSIZE == Q->front)    /* 队列满的判断 */
        return ERROR;
    Q->data[Q->rear]=e;         /* 将元素e赋值给队尾 */
    Q->rear=(Q->rear+1)%MAXSIZE;/* rear指针向后移一位置, */
                                /* 若到最后则转到数组头部 */
    return  OK;
}

(4)出队操作 。

首先,队列空的判断依据:Q->front == Q->rear

只要将队头指针向后移动一位就可以完成出队 Q->front=(Q->front+1)%MAXSIZE;
在这之前需要用 e 来保存出队的元素。出队函数如下:

/* 若队列不空,则删除Q中队头元素,用e返回其值 */
Status DeQueue(SqQueue *Q, QElemType *e)
{
    if (Q->front == Q->rear)            /* 队列空的判断 */
        return ERROR;
    *e=Q->data[Q->front];               /* 将队头元素赋值给e */
    Q->front=(Q->front+1)%MAXSIZE;  /* front指针向后移一位置, */
                                    /* 若到最后则转到数组头部 */
    return  OK;
}

(5)置空顺序队列。只要让队头指针与队尾指针相等即可。

/* 将Q清为空队列 */
Status ClearQueue(SqQueue *Q)
{
    Q->front=Q->rear=0;
    return OK;
}

(6)获取队列长度。可以使用模运算来获取队列的长度。具体算法:队尾指针 - 队头指针 + 数组长度的和再模数组长度即可。

/* 返回Q的元素个数,也就是队列的当前长度 */
int QueueLength(SqQueue Q)
{
    return  (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}

顺序队列实现代码如下:

#include 

using namespace std;

#define maxsize 20 /* 存储空间初始分配量 */
typedef int QElemType;
//循环队列顺序存储结构
typedef struct
{
    QElemType a[maxsize];
    int front;//队列头指针
    int rear;//队列尾指针,若队列不空,指向队列尾元素的下一个位置
}SqQueue;

//队列初始化函数
void InitQueue(SqQueue *q)
{
    q->front = q->rear = 0;
}
//判断队列是否为空
bool IsEmpty(SqQueue *q)
{
    return q->front == q->rear;
}
//判断队列是否已满
bool IsFull(SqQueue *q)
{
    return (q->rear + 1)%maxsize == q->front;
}
//获取队列长度
void QueueLength(SqQueue *q)
{
    int length = (q->rear - q->front + maxsize) % maxsize;
    cout<<"队列长度:"<//入队
void EnQueue(SqQueue *q, QElemType x)
{
    if(IsFull(q))
    {
        cout<<"队列已满!"<else
    {
        q->a[q->rear] = x;//先把入队值赋给队尾指针指向的地方(原队列队尾的下一位置)
        q->rear = (q->rear+1)%maxsize;//队尾指针后移
    }
}
//出队
void DeQueue(SqQueue *q)
{
    QElemType x;
    if(IsEmpty(q))
    {
        cout<<"队列已空!"<else
    {
        x = q->a[q->front];
        cout<<"delete x="<front = (q->front+1)%maxsize;
    }
}
//将队列清空
void ClearQueue(SqQueue *q)
{
    cout<<"请空队列!"<front = q->rear = 0;
}
//打印队列
void PrintQueue(SqQueue *q)
{
    if(IsEmpty(q))
    {
        cout<<"队列为空,无法输出!"<for(int i=q->front; i%maxsize < q->rear; i++)
    {//q->rear指向尾元素的下一位置!!!
        if(i == q->rear-1)
        {//遍历到尾元素
            cout<a[i]<else
        {
            cout<a[i]<<" ";
        }
    }
}
int main()
{
    SqQueue *q;
    InitQueue(q);

    EnQueue(q, 1);
    PrintQueue(q);
    EnQueue(q, 2);
    PrintQueue(q);
    EnQueue(q, 3);
    PrintQueue(q);
    EnQueue(q, 4);
    PrintQueue(q);

    QueueLength(q);

    DeQueue(q);
    PrintQueue(q);
    DeQueue(q);
    PrintQueue(q);

    QueueLength(q);

    ClearQueue(q);
    QueueLength(q);
    PrintQueue(q);

    return 0;
}

结果:

1
1 2
1 2 3
1 2 3 4
队列长度:4
delete x=1
2 3 4
delete x=2
3 4
队列长度:2
请空队列!
队列长度:0
队列为空,无法输出!

Process returned 0 (0x0)   execution time : 5.301 s
Press any key to continue.

你可能感兴趣的:(数据结构)