C语言实现“队列“

简介: C语言实现“队列“

一、队列


1.1 队列的介绍:


队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表.


队列具有先进先出FIFO(First In First Out)


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


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



用顺序表还是用链表实现队列比较好呢?


结构 尾插 头插
顺序表 效率很高,不需要移动数据 效率极低,需要移动除首元素以外的所有数据
链表 效率较低,需要遍历链表找尾巴 效率高,改变头指针即可


  1. 对于链表的缺点,我们可以额外创建一个尾指针用于记录尾结点.这样效率就不是问题了,而顺序表的头插是硬伤.


  1. 链表不需要扩容,顺序表需要动态扩容/


综上,咱还是选择链表=实现队列吧!


typedef int QDatatype;
typedef struct QueueNode
{
  struct QueueNode* next;
  QDatatype data;
}QNode;
typedef struct Queue
{
  QNode* head;//记录队首
  QNode* tail;//记录队尾
  int size;//记录长度
}Queue;


图解:



1.2 "队列"的常见接口:


接口介绍:


//队列的初始化操作
void QueueInit(Queue* pq);
//队列的销毁
void QueueDestroy(Queue* pq);
//入队列
void QueuePush(Queue* pq, QDatatype x);
//出队列
void QueuePop(Queue* pq);
//队列的长度
int QueueSize(Queue* pq);
//队列是否为空
bool QueueEmpty(Queue* pq);
//取队头元素
QDatatype QueueFront(Queue* pq);
//取队尾元素
QDatatype QueueBack(Queue* pq);


二、接口的具体实现:


2.1 "队列"的"初始化"操作(QueueInit)


队列的结构是由两个结点指针,加一个记录长度的size变量组成.


队列的初始状态:


头指针=尾指针,长度为0.


代码:


//初始化"队列"操作
void QueueInit(Queue* pq)
{
  assert(pq);
  pq->head = NULL;
  pq->tail = NULL;
  int size = 0;
}


2.2 "入队"操作(QueuePush)


步骤:


  1. 申请一个结点,将数据域赋值为x(目标值),指针域指向NULL;


  1. 一般情况下,"入队"操作只影响尾指针.


  1. 链接:将尾指针的指针域指向新节点.


  1. 更新尾指针(令尾指针本身指向新节点).


特殊情况:


第一个元素入队时,头指针和尾指针都会收受到影响.需要将头指针和尾指针都指向新节点.



特殊情况:



代码:


//入队列
void QueuePush(Queue* pq, QDatatype x)
{
  assert(pq);
  QNode* newnode = (QNode*)malloc(sizeof(QNode));
  newnode->data = x;
  newnode->next = NULL;
  if (pq->head == NULL)//第一个元素入队列时,会影响头指针
  {
    pq->head = pq->tail = newnode;//将头指针和尾指针都指向新节点
  }
  else
  {
    pq->tail->next = newnode;
    pq->tail = newnode;//更新队尾
  }
  pq->size++;
  return 0;
}


2.3 "队列"判空(QueueEmpty)


如果头指针和尾指针都指向NULL则表示空队列


代码:


//队列是否为空
bool QueueEmpty(Queue* pq)
{
  assert(pq);
  //如果头指针和尾指针都指向NULL则表示空队列
  if (pq->head == pq->tail && pq->tail == NULL)
  {
    return true;
  }
  return false;
}


2.4 “出队”(QueuePop)


步骤:


  1. 对于删除元素的"出队"操作,我们首先要进行"判空"操作.空队列不允许删除.


  1. 创建一个结点指针(Delete ):用于记录待会要出队的原队首结点.


  1. 将队首结点向后移动一步.(即将队首指针指向第二个元素).


  1. 释放Delete 结点.


  1. 长度(size)减少1;



特殊情况:


剩下最后一个待出队元素时:


会影响头指针,需要将头指针和尾指针都置空NULL;


这里就不画图了,相信聪明的友友们可以理解.


代码:


//出队列
void QueuePop(Queue* pq)
{
  assert(pq);
  assert(!QueueEmpty(pq));
  QNode* Delete = pq->head;//记录原队首
  if (pq->head == pq->tail)//如果是最后一个元素出队列
  {
    pq->head = pq->tail = NULL;
  }
  else pq->head = pq->head->next;//更新队头指针
  free(Delete);//释放原队首
  pq->size--;
}


2.5 "队列"长度函数


这里采用了增加一个变量size用于记录队列的长度.所以直接返回size即可.


如果没有size就需要遍历.


//队列的长度
int QueueSize(Queue* pq)
{
  assert(pq);
  return pq->size;
}


2.6 取"队头"和"队尾"元素


在创建队列时,我们已经分析了链式队列的结构,队首=和队尾元素我们可以直接通过队首指针(head)和队尾指针(tail)访问其数据域即可.


//取队头元素
QDatatype QueueFront(Queue* pq)
{
  assert(pq);
  assert(pq->head);
  return pq->head->data;
}
//取队尾元素
QDatatype QueueBack(Queue* pq)
{
  assert(pq);
  assert(pq->tail);
  return pq->tail->data;
}


2.7 "队列"的销毁:


与链表的销毁类似:


步骤:


  1. 创建两个结点指针


(1):QNode* cur:从头指针开始,遍历整个队列


(2):QNode* next:用于记录下一个结点,方便cur被释放后,继续往下遍历.


  1. 释放cur指针指向的结点.


  1. 更新cur指针和next指针.


  1. 将队首指针(head)和队尾指针(tail)指向NULL.


  1. 将size置为0;


代码:


//队列的销毁
void QueueDestroy(Queue* pq)
{
  assert(pq);
  QNode* cur = pq->head;
  QNode* next = cur;
  while (next)
  {
    next = cur->next;
    free(cur);
    cur = next;
  }
  pq->head = pq->tail = NULL;
  pq->size = 0;
}


三、结语:


"栈"和"队列"都是很重要的一种数据结构,在计算机中有很多应用,后续会更新==“循环队列”==,和OJ题:用栈模拟队列,用队列模拟栈等.

目录
相关文章
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
215 9
|
7月前
|
C语言
顺序队列的初始化、进队和出队(C语言)
顺序队列的初始化、进队和出队(C语言)
56 1
|
7月前
|
Linux C语言
Linux系统下C语言的队列操作
Linux系统下C语言的队列操作
156 0
|
C语言
【C语言数据结构(基础版)】第四站:栈和队列
【C语言数据结构(基础版)】第四站:栈和队列
84 0
|
28天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
54 5
|
3月前
|
存储 C语言
数据结构基础详解(C语言): 栈与队列的详解附完整代码
栈是一种仅允许在一端进行插入和删除操作的线性表,常用于解决括号匹配、函数调用等问题。栈分为顺序栈和链栈,顺序栈使用数组存储,链栈基于单链表实现。栈的主要操作包括初始化、销毁、入栈、出栈等。栈的应用广泛,如表达式求值、递归等场景。栈的顺序存储结构由数组和栈顶指针构成,链栈则基于单链表的头插法实现。
544 3
|
6月前
|
C语言 C++
【数据结构】C语言实现:栈(Stack)与队列(Queue)
【数据结构】C语言实现:栈(Stack)与队列(Queue)
|
6月前
数据结构——队列(C语言版)
数据结构——队列(C语言版)
49 0
|
7月前
|
算法 C语言 容器
纯c语言模拟栈和队列(初学必看)
纯c语言模拟栈和队列(初学必看)
|
7月前
|
算法 C语言
【算法与数据结构】 C语言实现单链表队列详解2
【算法与数据结构】 C语言实现单链表队列详解