【数据结构】六、队列

目录

一、队列的基本知识 

1.队列是在表尾插入元素,在表头删除元素(头删尾插)。队列也分为顺序队列和链式队列。

2.队列的特点:先进先出。(排队问题就是先进先出)

3.队列的相关案例:舞伴问题

二、顺序队列

三、顺序循环队列的基本操作

1.顺序循环队列的定义

2.顺序循环队列的初始化

3.求顺序循环队列的长度

4. 顺序循环队列的入队

5.顺序循环队列的出队

6.取对头元素

四、链队列

 五、链队列的基本操作

1.链队列的定义

2.链队列的初始化

3.销毁链队列

4.链队列的入队

5.链队列的出队


一、队列的基本知识 

1.队列是在表尾插入元素,在表头删除元素(头删尾插)。队列也分为顺序队列和链式队列。

2.队列的特点:先进先出。(排队问题就是先进先出)

3.队列的相关案例:舞伴问题

二、顺序队列

(1) 入栈移动rear指针,出栈移动front指针

就算下面有空位置,也不可以入队了。

(2) 为了解决这个问题,我们可以将队列看作循环的顺序表,也就是循环队列,当rear指针达到最大值后又回到0。具体的,我们可以与表长取模%

(3) 但在循环队列里,队空和队满时,rear指针都等于front指针,这样就难以判断到底是队空还是队满,解决这个问题可以有三个办法

这里介绍第三种方法:

当rear指针+1就与front指针重合时,我们就看作已经队满了,这个位置就不能再放元素进去了。

空队仍保持rear等于front

三、顺序循环队列的基本操作

1.顺序循环队列的定义

typedef struct
{
    int *array;  //表示数组
    int front;  //头指针,虽然说是指针,但实际是用的数组的下标,所以是int,而不是int*
    int rear;  //尾指针
}SqQueue;

2.顺序循环队列的初始化

void initQueue(SqQueue &Q)
{
    Q.array = new int[MAXSIZE];  //给数组分配空间
    //如果分配失败
    if(!Q.array)
    {
        return;
    }

    Q.front = Q.rear = 0;
}

3.求顺序循环队列的长度

int QueueLength(SqQueue &Q)
{
    return ((Q.rear - Q.front + MAXSIZE) % MAXSIZE);
}

4. 顺序循环队列的入队

void inQueue(SqQueue &Q, int e)
{
    //先判断是否队满再入队
    //如果队满了
    if((Q.rear + 1) % MAXSIZE == Q.front)
    {
        return;
    }

    Q.array[Q.rear] = e;  //将新元素放到队尾的位置
    Q.rear = (Q.rear + 1) % MAXSIZE;  //循环队列的尾指针++
}

5.顺序循环队列的出队

void outQueue(SqQueue &Q, int e)
{
    //先判断队列里还有没有元素
    //如果队空了
    if(Q.rear == Q.front)
    {
        return;
    }

    e = Q.array[Q.front];
    Q.front = (Q.front + 1) % MAXSIZE;
}

6.取对头元素

int GetHead(SqQueue &Q)
{
    //先判断队列是否为空
    //如果队列不为空
    if(Q.rear != Q.front)
    {
        return Q.array[Q.front];
    }
}

四、链队列

如果无法知道队列所需要的长度,则可以用队列的链式表示

 五、链队列的基本操作

1.链队列的定义

typedef struct QueueNode
{
    int data;
    struct QueueNode *next;
}QueueNode;  //QueueNode表示一个结点
typedef struct QueueNode *QueuePtr;  //QueuePtr是front指针和rear指针的类型
typedef struct
{
    QueueNode *front;
    QueueNode *rear;
}LinkQueue;  //LinkQueue表示链队列

2.链队列的初始化

void initQueue(LinkQueue &Q)
{
    Q.front = Q.rear = new QueuePtr;
    Q.front->next = NULL;
}

3.销毁链队列

依次释放所有结点,队列本身还存在

void destroyQueue(LinkQueue &Q)
{
    while(Q.front != NULL)  //注意这里循环的条件不是Q.front->next != NULL
    {
        QueuePtr p = new QueuePtr;
        //这里就表示这是带头结点的链队列
        p = Q.front->next;
        delete Q.front;
        Q.front = p;
    }
}

或者不需要另外的指针p,直接用尾指针

void destroyQueue(LinkQueue &Q)
{
    while(Q.front != NULL)  //注意这里循环的条件不是Q.front->next != NULL
    {
        Q.rear = Q.front->next;
        delete Q.front;
        Q.front = Q.rear;
    }
}

4.链队列的入队

void inQueue(LinkQueue &Q, int e)
{
    QueuePtr p = new QueuePtr;
    p->data = e;
    p->next = NULL;
    Q.rear->next = p;
    Q.rear = p;
}

5.链队列的出队

void outQueue(LinkQueue &Q, int e)
{
    //先判断队列是否为空
    //如果是队空
    if(Q.front == Q.rear)
    {
        return;
    }
    QueuePtr p = new QueuePtr;
    p = Q.front->next;
    e = p->data;
    Q.front->next = p->next;  //注意这里不是Q.front = P->next,如果这样写,头结点就没了
    
    /*这里要注意,如果出队的是最后一个结点,而尾指针是指向最后一个结点的,那么在删除结点前要将尾指针改一下
    不然尾指针就成野指针了*/
    if(Q.rear == p)
    {
        Q.rear = Q.front;
    }
    delete p;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值