【数据结构与算法】队列的实现

简介: 【数据结构与算法】队列的实现

👉队列的概念及结构👈


队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)的原则

入队列:进行插入操作的一端称为队尾


出队列:进行删除操作的一端称为队头

e542f9d29b154a15819ae5ae9e09fe41.png



队列的结构在生活中非常地常见,比如排队时的抽号机就是一个典型的队列结构。那队列如何实现呢?我们一起来看一下。


👉队列的实现👈


队列也可以数组和链表的结构实现,使用链表的结构实现更优一些。因为如果使用数组的结构,出队列在数组头上出数据,需要挪动数据,时间复杂度为O(N),效率会比较低。

abfb93a9a5d34dd4bcc8fa538a8cf32d.png


Queue.h


#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int QDataType;
typedef struct QueueNode
{
  QDataType data;
  struct QueueNode* next;
}QNode;
typedef struct Queue
{
  QNode* head; // 头指针
  QNode* tail; // 尾指针
  int size;    // 节点的个数
}Queue;
void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
bool QueueEmpty(Queue* pq);
int QueueSize(Queue* pq);


队列要实现的函数接口有:初始化队列、销毁队列、数据入队、数据出队、返回队头的数据、返回队尾的数据、判断队列是否为空以及队列中数据的个数。这些接口实现起来也不是很难,我们一起来看一下。


Queue.c


#include "Queue.h"
void QueueInit(Queue* pq)
{
  assert(pq);
  pq->head = pq->tail = NULL;
  pq->size = 0;
}
void QueueDestroy(Queue* pq)
{
  assert(pq);
  QNode* cur = pq->head;
  while (cur)
  {
    QNode* del = cur;
    cur = cur->next;
    free(del);
  }
  pq->head = pq->tail = NULL;
  pq->size = 0;
}
void QueuePush(Queue* pq, QDataType x)
{
  assert(pq);
  QNode* newnode = (QNode*)malloc(sizeof(QNode));
  if (newnode == NULL)
  {
    perror("malloc fail");
    exit(-1);
  }
  else
  {
    newnode->data = x;
    newnode->next = NULL;
  }
  // 队列中没有节点
  if (pq->tail == NULL)
  {
    pq->head = pq->tail = newnode;
  }
  else
  {
    pq->tail->next = newnode;
    pq->tail = newnode;
  }
  pq->size++;
}
void QueuePop(Queue* pq)
{
  assert(pq);
  assert(!QueueEmpty(pq));
  // 队列中只有一个节点
  if (pq->head->next == NULL)
  {
    free(pq->head);
    pq->head = pq->tail = NULL;
  }
  else
  {
    QNode* del = pq->head;
    pq->head = pq->head->next;
    free(del);
    //del = NULL;
  }
  pq->size--;
}
QDataType QueueFront(Queue* pq)
{
  assert(pq);
  assert(!QueueEmpty(pq));
  return pq->head->data;
}
QDataType QueueBack(Queue* pq)
{
  assert(pq);
  assert(!QueueEmpty(pq));
  return pq->tail->data;
}
bool QueueEmpty(Queue* pq)
{
  assert(pq);
  return pq->size == 0;
  //return pq->head == NULL && pq->tail == NULL;
}
int QueueSize(Queue* pq)
{
  assert(pq);
  return pq->size;
}


初始化队列


头指针和尾指针都指向空,队列元素个数初始化为0

void QueueInit(Queue* pq)
{
  assert(pq);
  pq->head = pq->tail = NULL;
  pq->size = 0;
}


销毁队列


利用while循环将申请的节点一一释放掉,然后头指针pq->head和尾指针pq->tail指向空,栈的数据个数置为 0pq->size = 0


void QueueDestroy(Queue* pq)
{
  assert(pq);
  QNode* cur = pq->head;
  while (cur)
  {
    QNode* del = cur;
    cur = cur->next;
    free(del);
  }
  pq->head = pq->tail = NULL;
  pq->size = 0;
}


数据入队


1.申请新的节点newnode newnode->data = x,newnode->next = NULL

2.数据入队:当pq->tail == NULL时,队列中没有节点,那么头指针和尾指针都赋值为newnode pq->head = pq->tail = newnode;当pq->tail != NULL时,队列中有节点,那么尾部链接上新节点newnode,然后newnode成为新的尾结点。

3.队列数据个数加一pq->size++


void QueuePush(Queue* pq, QDataType x)
{
  assert(pq);
  QNode* newnode = (QNode*)malloc(sizeof(QNode));
  if (newnode == NULL)
  {
    perror("malloc fail");
    exit(-1);
  }
  else
  {
    newnode->data = x;
    newnode->next = NULL;
  }
  // 队列中没有节点
  if (pq->tail == NULL)
  {
    pq->head = pq->tail = newnode;
  }
  else
  {
    pq->tail->next = newnode;
    pq->tail = newnode;
  }
  pq->size++;
}


数据出队


1.判断队列是否为空

2.数据出队:当pq->head->next == NULL时,队列中只有一个节点,释放该节点,头指针和尾指针都指向空;当pq->head->next != NULL时,释放让头指针指向当前节点的下一个节点,释放原来的头节点

3.队列数据个数减一pq->size--

d5705b2fe0f547b9b99ea9984978ecff.png


void QueuePop(Queue* pq)
{
  assert(pq);
  assert(!QueueEmpty(pq));
  // 队列中只有一个节点
  if (pq->head->next == NULL)
  {
    free(pq->head);
    pq->head = pq->tail = NULL;
  }
  else
  {
    QNode* del = pq->head;
    pq->head = pq->head->next;
    free(del);
    //del = NULL;
  }
  pq->size--;
}


返回队头数据


先判断队列是否为空,不为空时,返回队头数据。


QDataType QueueFront(Queue* pq)
{
  assert(pq);
  assert(!QueueEmpty(pq));
  return pq->head->data;
}


返回队尾数据


先判断队列是否为空,不为空时,返回队尾数据。


QDataType QueueFront(Queue* pq)
{
  assert(pq);
  assert(!QueueEmpty(pq));
  return pq->tail->data;
}


判断队列是否为空


判断队列是否为空有两种方式:1.判断pq->size等不等于 0;2.判断头指针pq->head和尾指针pq->tail是否等于空指针NULL


bool QueueEmpty(Queue* pq)
{
  assert(pq);
  return pq->size == 0;
  //return pq->head == NULL && pq->tail == NULL;
}


队列中数据的个数


直接返回队列数据的个数pq->size


int QueueSize(Queue* pq)
{
  assert(pq);
  return pq->size;
}


Test.c


以下为测试函数接口的代码,大家可以参考一下。需要注意的是,打印队列中的数据是通过打印队头数据、Pop掉队头数据的方式来实现的。


#include "Queue.h"
void QueueTest()
{
  Queue q;
  QueueInit(&q);
  QueuePush(&q, 1);
  QueuePush(&q, 2);
  QueuePush(&q, 3);
  printf("%d ", QueueFront(&q));
  QueuePop(&q);
  printf("%d ", QueueFront(&q));
  QueuePop(&q);
  QueuePush(&q, 4);
  QueuePush(&q, 5);
  QueuePush(&q, 6);
  while (!QueueEmpty(&q))
  {
    printf("%d ", QueueFront(&q));
    QueuePop(&q);
  }
  printf("\n");
  QueueDestroy(&q);
}
int main()
{
  QueueTest();
  return 0;
}

7d39aaddb5b04553815b9831cf497dd2.jpg


👉总结👈


本篇博客主要讲解了队列的实现,最重要的函数接口是数据入队和数据出队。在下一篇博客,本人将给大家带来几道 OJ 题,大家可以期待一下。以上就是本篇博客的全部内容了,如果大家觉得有收获的话,可以点个三连支持一下!谢谢大家啦!💖💝❣️



相关文章
|
1月前
|
算法
【优选算法专栏】专题十三:队列+宽搜(一)
【优选算法专栏】专题十三:队列+宽搜(一)
30 0
|
1月前
|
消息中间件 存储 搜索推荐
深入理解栈和队列(二):队列
深入理解栈和队列(二):队列
39 0
|
1月前
|
存储 算法 索引
【算法与数据结构】队列的实现详解
【算法与数据结构】队列的实现详解
159 0
|
4天前
栈与队列理解
栈与队列理解
10 1
|
4天前
|
存储 算法
数据结构与算法 栈与队列
数据结构与算法 栈与队列
10 0
数据结构与算法 栈与队列
|
5天前
|
C++
数据结构(顺序队列 循环队列
数据结构(顺序队列 循环队列
8 0
|
5天前
|
容器
【栈与队列】栈与队列的相互转换OJ题
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
10 0
|
8天前
|
C语言
猿创征文|栈和队列OJ刷题
猿创征文|栈和队列OJ刷题
[数据结构]~栈和队列(0-1)
[数据结构]~栈和队列(0-1)
|
13天前
|
存储
栈与队列练习题
栈与队列练习题