数据结构与算法(5.2)队列(附源码)

在今天的学习中,将会介绍栈和队列的概念,以及其功能的实现,还有其应用场景


在这里插入图片描述

前言

队列是只允许再一端进行插入数据操作,另一端进行删除数据操作的特殊线性表,和栈不同的是,队列是先进先出的,进行插入的一端叫做队尾,出队列的一段叫做队头。

就像排队上公交车一样先排的肯定先进公交车,后来的就等着。
在这里插入图片描述
更简洁一点来说就是:
在这里插入图片描述

队列的实现

队列也是一种特殊的线性表,所以也可以用顺序表或者链表来实现,那么该选谁呢?这时候我们就要思考效率的问题,如果用顺序表的话,数组头就是队头,我要出队的话肯定是从数组头开始出,那么我后面的数据全要挪移,这复杂度就变成O(N)了,如果使用链表呢?用链表的话无论是入队还是出队,都只需要挪动前一个节点或者后一个节点的指向而已,所以我们选用链表来实现队列。
实现功能如下:

1.初始化队列

2.购买节点

3.入队

4.出队

5.检查队列是否为空

6.销毁队列

首先如果是链表的话,我们现要有一个节点的结构体:

typedef struct QListNode    
{                       
  struct QListNode* _next;    
  QDataType _data;    
}QNode;                   
                  
// 队列的结构           
typedef struct Queue         
{
  QNode* _front;         
  QNode* _rear;
}Queue; 

这里面有两个结构体,其中QNode是队列中每一个节点,Queue代表整个队列,其中存储队头和队尾。(有点头节点那意思了)

1.初始化队列

void QueueInit(Queue* q)
{
  q->_front = NULL;
  q->_rear = NULL;
}

2.购买节点

QNode * BuyQueueNode(QDataType x)
{
  QNode * cur = (QNode*)malloc(sizeof(QNode));
  cur->_data = x;
  cur->_next = NULL;
  return cur;
}

这是链表的节点,注意是队列的结构体存的结构体指针的类型,不是队列的类型

3.入队

void QueuePush(Queue* q, QDataType data)
{
  QNode * cur = BuyQueueNode(data);                                                                                                                                                       
  if(q->_front==NULL)
  {
      q->_front = q->_rear = cur;
  }
  else//有节点就在队列最后尾插,让rear后移一位 
  {
    q->_rear->_next = cur;
    q->_rear = cur;
  }
}

入队要分成两种情况,一种是队列中没有节点,一种是已经有节点了,没有节点的时候,我们直接让队头和队尾的指针都指向新节点就可以了,那有节点的时候呢?有节点的时候就和链表的尾插是一样的,但是要注意,此时rear存储的是队尾,我们尾插之后,要让rear后移一位成新队尾。
在这里插入图片描述
红色是我们新进队的节点,这时候队尾的指向就不对了,要指向新节点。

4.出队

void QueuePop(Queue* q)
{
    assert(q);//出队列就相当于链表的头删一样
    if(q->_front == NULL)
      return ;
    QNode *cur = q->_front->_next;
    free(q->_front);
    q->_front = cur;
}

出队就是头删,别忘了要把储存队头的指针后移一位。

检查队列是否为空

int QueueEmpty(Queue* q)
{
  if(q->_front == NULL)
    return 1;
  else return 0;
}

销毁链表

void QueueDestroy(Queue* q)
{
  if(q->_front == NULL)
    return ;
  while(q->_front)
  {
    QueuePop(q);
  }
}

销毁链表的时候就一直执行头删,删完为止。

应用:

有时候我们会用栈实现队列,队列实现栈,在实际应用中循环的队列是使用次数比较高的,在下一篇博客中将会介绍用队列实现栈,用栈实现队列,以及循环队列的写法。

源码

Queue.h

#include<stdio.h>      
#include<assert.h>    
#include<stdlib.h>    
typedef int QDataType;
// 链式结构:表示队列     
typedef struct QListNode
{
    struct QListNode* _next;
    QDataType _data;
}QNode;

// 队列的结构          
typedef struct Queue
{
    QNode* _front;
    QNode* _rear;
}Queue;

// 初始化队列     
void QueueInit(Queue* q);
// 队尾入队列     
void QueuePush(Queue* q, QDataType data);
// 队头出队列     
void QueuePop(Queue* q);
// 获取队列头部元素     
QDataType QueueFront(Queue* q);
// 获取队列队尾元素     
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数     
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0     
int QueueEmpty(Queue* q);
// 销毁队列     
void QueueDestroy(Queue* q);

Queue.c

#include"Queue.h"

// 链式结构:表示队列     
//typedef struct QListNode     
//{     
//  struct QListNode* _next;     
//  QDataType _data;     
//}QNode;              

// 队列的结构         
//typedef struct Queue     
///{                      
//  QNode* _front;          
//  QNode* _rear;      
//}Queue;                     

QNode* BuyQueueNode(QDataType x)
{
    QNode* cur = (QNode*)malloc(sizeof(QNode));
    cur->_data = x;
    cur->_next = NULL;
    return cur;
}
// 初始化队列     
void QueueInit(Queue* q)
{
    q->_front = NULL;
    q->_rear = NULL;
}
// 队尾入队列     
void QueuePush(Queue* q, QDataType data)
{
    QNode* cur = BuyQueueNode(data);
    if (q->_front == NULL)//相当于q._front ==NULL
    {
        q->_front = q->_rear = cur;
    }
    else//有节点就在队列最后尾插,让rear后移一位               
    {
        q->_rear->_next = cur;
        q->_rear = cur;
    }
}
// 队头出队列     
void QueuePop(Queue* q)
{
    assert(q);//出队列就相当于链表的头删一样
    if (q->_front == NULL)
        return;
    QNode* cur = q->_front->_next;
    free(q->_front);
    q->_front = cur;
}
// 获取队列头部元素     
QDataType QueueFront(Queue* q)
{
    return q->_front->_data;
}
// 获取队列队尾元素     
QDataType QueueBack(Queue* q)
{
    return q->_rear->_data;
}
// 获取队列中有效元素个数     
int QueueSize(Queue* q)
{
    QNode* cur;
    int cnt = 0;
    for (cur = q->_front; cur; cur = cur->_next)
    {
        cnt++;
    }
    return cnt;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0     
int QueueEmpty(Queue* q)
{
    if (q->_front == NULL)
        return 1;
    else return 0;
}
// 销毁队列     
void QueueDestroy(Queue* q)
{
    if (q->_front == NULL)
        return;
    while (q->_front)
    {
        QueuePop(q);
    }
}

Queuetest.c

#include"Queue.h"

int main()
{
    Queue q ;
    QueueInit(&q);
    QueuePush(&q, 1);
    QueuePush(&q, 1);
    QueuePush(&q, 1);
    QueuePush(&q, 1);
    QueuePush(&q, 1);
    QueuePush(&q, 1);
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值