初阶数据结构(六)队列的介绍与实现

简介: 初阶数据结构(六)队列的介绍与实现

队列的介绍

队列的概念:

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

入队列:队列的插入操作叫做入队列,进行插入操作的一端称为队尾。

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

队列的结构:

队列的实现

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

创建队列

首先我们需要创建一个结点类型,类型包含了该结点的数据指向下一结点的指针。

typedef int QDataType;
typedef struct QListNode
{
  struct QListNode* next;               //指针域
  QDataType data;                       //数据域
}QListNode;

其次队列与普通链表又有所不同,普通链表只需要知道链表的头指针,而队列的信息包括了队头和队尾,所以我们需要再创建一个结构体用于存放队列的队头和队尾。

typedef struct Queue
{
  QListNode* head;//队头
  QListNode* tail;//队尾
}Queue;

初始化队列

我们需要一个初始化函数,对刚创建的队列进行初始化

//初始化队列
void QueueInit(Queue* pq)
{
  assert(pq);
  //起始时队列为空
  pq->head = NULL;
  pq->tail = NULL;
}

销毁队列

因为队列中的每一个结点所占用的内存空间都是动态开辟的,当我们使用完队列后需要及时释放队列中的每一个结点。

//销毁队列
void QueueDestroy(Queue* pq)
{
  assert(pq);
  QListNode* cur = pq->head;//接收队头
  //遍历链表,逐个释放结点
  while (cur)
  {
    QListNode* next = cur->next;
    free(cur);
    cur = next;
  }
  pq->head = NULL;//队头置空
  pq->tail = NULL;//队尾置空
}

队尾入队列

入队列,也就是说申请一个新结点并将其链接到队尾,然后改变队尾的指针指向

需要注意的是:若队列中原本无数据,那么我们只需让队头和队尾均指向这个新申请的结点即可。

//队尾入队列
void QueuePush(Queue* pq, QDataType x)
{
  assert(pq);
  QListNode* newnode = (QListNode*)malloc(sizeof(QListNode));//申请新结点
  if (newnode == NULL)
  {
    printf("malloc fail\n");
    exit(-1);
  }
  newnode->data = x;                                        //新结点赋值
  newnode->next = NULL;                                     //新结点指针域置空
  if (pq->head == NULL)                                     //队列中原本无结点
  {
    pq->head = pq->tail = newnode;                         //队头、队尾直接指向新结点
  }
  else                                                       //队列中原本有结点
  {
    pq->tail->next = newnode;                              //最后一个结点指向新结点
    pq->tail = newnode;                                    //改变队尾指针指向
  }
}

对头出队列

出队列,也就是释放队头指针指向的结点并改变队头指针的指向

若队列中只有一个结点,那么直接将该结点释放,然后将队头和队尾置空即可。

//队头出队列
void QueuePop(Queue* pq)
{
  assert(pq);
  assert(!QueueEmpty(pq));                            //检测队列是否为空
  if (pq->head->next == NULL)                         //队列中只有一个结点
  {
    free(pq->head);
    pq->head = NULL;
    pq->tail = NULL;
  }
  else//队列中有多个结点
  {
    QListNode* next = pq->head->next;
    free(pq->head);
    pq->head = next;                                 //改变队头指针指向
  }
}

获取队列头部元素

获取队列头部元素,就是返回队头指针指向的数据。

//获取队列头部元素
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->head == NULL;
}

获取队列中有效元素个数

队列中有效元素个数,也就是队列中的结点个数

我们只需遍历一下队列,统计队列中的结点数并返回即可。

//获取队列中有效元素个数
int QueueSize(Queue* pq)
{
  assert(pq);
  QListNode* cur = pq->head;                       //接收队头
  int count = 0;                                   //记录结点个数
  while (cur)                                      //遍历队列
  {
    count++;
    cur = cur->next;
  }
  return count;                                    //返回队列中的结点数
}

总结:

初阶数据结构(五)(六)讲的是栈和队列,它们都是特殊的线性表,只不过对插入和删除操作做了限制。

(stack)是限定仅在表尾进行插入和删除操作的线性表。

对列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线

性表。

它们均可以用线性表的顺序存储结构来实现,但都存在着顺序存储的一些弊端。因此它们各自有各自的技巧来解决这个问题。

对于栈来说,如果是两个相同数据类型的栈,则可以用数组的两端作栈底的方法来让两个栈共享数据,这就可以最大化地利用数组的空间。

对于队列来说,为了避免数组插入和删除时需要移动数据,于是就引入了循环队列,使得队头和队尾可以在数组中循环变化。解决了移动数据的时间损耗,使得本来插入和删除是O(n)的时间复杂度变成了O(1)。

它们也都可以通过链式存储结构来实现,实现原则上与线性表基本相同,如下图所示。

文章到这里就要告一段落了,有更好的思路或问题的,欢迎留言评论区。

相关文章
|
19天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
98 9
|
22天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
初步认识栈和队列
初步认识栈和队列
60 10
|
1月前
|
存储 算法 定位技术
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
这篇文章主要介绍了稀疏数组和队列的概念、应用实例以及如何使用数组模拟队列和环形队列的实现方法。
21 0
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
|
1月前
|
存储 安全 Java
【用Java学习数据结构系列】探索栈和队列的无尽秘密
【用Java学习数据结构系列】探索栈和队列的无尽秘密
30 2
|
1月前
【数据结构】-- 栈和队列
【数据结构】-- 栈和队列
17 0
|
1月前
探索数据结构:队列的的实现与应用
探索数据结构:队列的的实现与应用
|
1月前
|
存储 C语言
栈和队列题目练习
栈和队列题目练习
18 0
|
1月前
|
存储 算法 Java
【用Java学习数据结构系列】用堆实现优先级队列
【用Java学习数据结构系列】用堆实现优先级队列
31 0
|
1月前
|
C语言
数据结构------栈(Stack)和队列(Queue)
数据结构------栈(Stack)和队列(Queue)
20 0

热门文章

最新文章

下一篇
无影云桌面