常见数据结构-队列先进先出

简介: 常见数据结构-队列先进先出

一,概述

队列这个概念非常好理解。你可以把它想象成排队买票,先来的先买,后来的人只能站末尾,不允许插队。先进者先出,这就是典型的“队列”。

二,顺序队列和链式队列

队列和栈一样,也是一种抽象的数据结构,操作上具有“先进先出”的特性,队列只允许在"队首"进行删除操作,而在"队尾"进行插入操作。基于数组实现的顺序队列的C++代码如下:

// 用数组实现的队列
class ArrayQueue(){
    // 数组:items,数组大小:n
private:
    int n = 20;
    int head = 0;   // 队头下标
    int tail = 0;   // 队尾下标
public:
    // 带参数的构造函数:申请一个大小为 capacity 的数组
    ArrayQueue(int capacity){
        // items = new int[capacity];
        vector<int> items(capacity);
        n = capacity;
    }
    // 入队
    bool enqueue(int item){
        if(tail == n) return False;
        items[tail] = item;
        ++tail;
        return True;
    }
    // 时间复杂度为O(1)的入队操作
    bool enqueue2(int item){
        // tail == n,表示队列末尾没有空间了
        if(tail == n){
            // tail == n && head == 0,表示整个队列都占满了
            if(head == 0) return False;
            // 数据搬移
            for(i=head; i<tail; ++i){
                items[i-head] = items[i];
            }
            // 重新更新 head 和 tail
            tail = tail - head; // tail -= head
            head = 0;   // 队首位置
        }
        items[tail] = item;
        ++tail;
        return True;
    }
    // 出队
    bool dequeue(){
        // head == tail 表示队列为空
        if (head == tail) return null;
        int ret = items[tail];
        ++head;
        return ret;
    }
}
复制代码

入队时间复杂度为 O(1)。分析:大部分情况下入队操作时间复杂度为 O(1),只有在 tail 在末尾时( tail=n )才进行数据迁移,此时的入队操作时间复杂度为 O(n),根据均摊时间复杂度得到入队时间复杂度为 O(1)

三,循环队列

前面用数组实现队列,当 tail = n 时,会有数据搬移操作。循环队列首尾相连,用数组实现循环队列代码的关键在于判断队列满和空的条件。

  • 非循环队列:
  • 队满:tail = n
  • 队空:head = tail
  • 循环队列
  • 队满:(tail + 1) % n = head
  • 队空:head = tail

基于数组实现的循环队列的C++代码如下:

// 用数组实现的循环队列,关键在于创建队头和队尾下标
class CircularQueue(){
private:
    int n = 12;
    int items[];
    // head表示队头下标,tail表示队尾下标
    int head = 0;
    int tail = 0;
public:
    CircularQueue(int capacity){
        // items = new int[capacty];
        vector<int> items(capacity);
        n = capacity;
    }
    // 入队函数
    bool enqueue(int item){
        // 队列满了
        if((tail+1)%n = head) return False;
        items[tail] = item;
        tail = (tail + 1) % n
    }
    // 出队函数
    int dequeue(){
        // // 如果head == tail 表示队列为空
        if(head == tail) return null;
        int ret = items[head];
        head = (head + 1) % n;
        return ret;
    }
}
复制代码

四,阻塞队列和并发队列

  1. 阻塞队列就是入队、出队操作都可以阻塞,简单来说就是队列为空时,队首取数据会被阻塞,队列为满时,队尾插入数据会被阻塞,直到队列有空闲数据才允许在队尾插入数据。使用阻塞队列结构可以轻松实现“消费者-生产者模型”
  2. 并发队列就是队列的操作多线程安全。最简单直接的实现方式是直接在 enqueue()、dequeue() 方法上加锁,但是锁粒度大并发度会比较低,同一时刻仅允许一个存或者取操作。实际上,基于数组的循环队列,利用 CAS 原子操作,可以实现非常高效的并发队列。这也是循环队列比链式队列应用更加广泛的原因。

参考资料

《数据结构与算法之美》-队列



相关文章
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
165 9
|
2月前
|
缓存 算法 调度
数据结构之 - 双端队列数据结构详解: 从基础到实现
数据结构之 - 双端队列数据结构详解: 从基础到实现
85 5
|
2月前
|
存储 算法 搜索推荐
探索常见数据结构:数组、链表、栈、队列、树和图
探索常见数据结构:数组、链表、栈、队列、树和图
115 64
|
19天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
42 5
|
1月前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
2月前
初步认识栈和队列
初步认识栈和队列
61 10
|
2月前
|
存储 算法 定位技术
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
这篇文章主要介绍了稀疏数组和队列的概念、应用实例以及如何使用数组模拟队列和环形队列的实现方法。
26 0
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
|
2月前
|
存储 安全 Java
【用Java学习数据结构系列】探索栈和队列的无尽秘密
【用Java学习数据结构系列】探索栈和队列的无尽秘密
34 2
【数据结构】--- 栈和队列
【数据结构】--- 栈和队列
|
2月前
|
消息中间件 存储 Java
数据结构之 - 深入探析队列数据结构: 助你理解其原理与应用
数据结构之 - 深入探析队列数据结构: 助你理解其原理与应用
40 4