【基础篇】7 # 队列:队列在线程池等有限资源池中的应用

news2024/11/28 4:46:03

说明

【数据结构与算法之美】专栏学习笔记

什么是队列?

队列是一种操作受限的线性表数据结构,特点是先进先出,最基本的操作有:入队 enqueue(),放一个数据到队列尾部;出队 dequeue(),从队列头部取一个元素。

在这里插入图片描述

顺序队列和链式队列

  • 用数组实现的队列叫作顺序队列
  • 用链表实现的队列叫作链式队列

基于数组的队列实现方法

队列需要两个指针:

  • 一个是 head 指针,指向队头;
  • 一个是 tail 指针,指向队尾。

用 Java 语言实现:


// 用数组实现的队列
public class ArrayQueue {
  // 数组:items,数组大小:n
  private String[] items;
  private int n = 0;
  // head表示队头下标,tail表示队尾下标
  private int head = 0;
  private int tail = 0;

  // 申请一个大小为capacity的数组
  public ArrayQueue(int capacity) {
    items = new String[capacity];
    n = capacity;
  }

   // 入队操作,将item放入队尾
  public boolean enqueue(String item) {
    // tail == n表示队列末尾没有空间了
    if (tail == n) {
      // tail ==n && head==0,表示整个队列都占满了
      if (head == 0) return false;
      // 数据搬移
      for (int i = head; i < tail; ++i) {
        items[i-head] = items[i];
      }
      // 搬移完之后重新更新head和tail
      tail -= head;
      head = 0;
    }
    
    items[tail] = item;
    ++tail;
    return true;
  }

  // 出队
  public String dequeue() {
    // 如果head == tail 表示队列为空
    if (head == tail) return null;
    // 为了让其他语言的同学看的更加明确,把--操作放到单独一行来写了
    String ret = items[head];
    ++head;
    return ret;
  }
}

当 tail 移动到最右边,即使数组中还有空闲空间,也无法继续往队列中添加数据,针对这种情况,只需要在入队时,再集中触发一次数据的搬移操作。示意图如下:

在这里插入图片描述

基于链表的队列实现方法

  • 入队时:tail->next= new_nodetail = tail->next
  • 出队时:head = head->next

入队出队示意图:

在这里插入图片描述

/**
 * 基于链表实现的队列。
 *
 * Author: nameczz
 */

class Node {
    constructor(element) {
        this.element = element
        this.next = null
    }
}

export class QueueBasedOnLinkedList {
    constructor() {
        this.head = null
        this.tail = null
    }

    enqueue(value) {
        if (this.head === null) {
            this.head = new Node(value)
            this.tail = this.head
        } else {
            this.tail.next = new Node(value)
            this.tail = this.tail.next
        }
    }

    dequeue() {
        if (this.head !== null) {
            const value = this.head.element
            this.head = this.head.next
            return value
        } else {
            return -1
        }
    }
}
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>07.基于链表实现的队列</title>
    </head>
    <body>
        <script type="module">
            import { QueueBasedOnLinkedList } from './js/07/QueueBasedOnLinkedList.js';
            const newQueue = new QueueBasedOnLinkedList();
            // 元素入队
            newQueue.enqueue(1);
            newQueue.enqueue(2);
            newQueue.enqueue(3);
            console.log('入队--->', newQueue);
            // 获取元素
            let res = 0;
            console.log("-------获取dequeue元素------");
            while (res !== -1) {
                res = newQueue.dequeue();
                console.log(res);
            }
        </script>
    </body>
</html>

在这里插入图片描述

循环队列

循环队列就是普通队列首尾相连形成了一个环。

比如:下面队列的大小为 8,当前 head=4,tail=7。

在这里插入图片描述

当有一个新的元素 a 入队时,放入下标为 7 的位置。将 tail 更新为 0 ,而不是 8。

如何判断循环队列队空和队满呢?

  • 队空:队列为空的判断条件是 head == tail
  • 队满:当队满时,(tail + 1)%n = head

基于数组的循环队列实现方式

public class CircularQueue {
  // 数组:items,数组大小:n
  private String[] items;
  private int n = 0;
  // head表示队头下标,tail表示队尾下标
  private int head = 0;
  private int tail = 0;

  // 申请一个大小为capacity的数组
  public CircularQueue(int capacity) {
    items = new String[capacity];
    n = capacity;
  }

  // 入队
  public boolean enqueue(String item) {
    // 队列满了
    if ((tail + 1) % n == head) return false;
    items[tail] = item;
    // 取余运算保证,数组队列的循环插入效果
    tail = (tail + 1) % n;
    return true;
  }

  // 出队
  public String dequeue() {
    // 如果head == tail 表示队列为空
    if (head == tail) return null;
    String ret = items[head];
    // 因为要保持一个环状,必须通过取余运算才能得到保障!
    head = (head + 1) % n;
    return ret;
  }
}

基于链表实现的循环队列

/**
 * 基于链表实现的循环队列。
 *
 * Author: nameczz
 */

class Node {
    constructor(element) {
        this.element = element
        this.next = null
    }
}

export class CircularQueue {
    constructor() {
        this.head = null
        this.tail = null
    }
	// 入队
    enqueue(value) {
        if (this.head === null) {
            this.head = new Node(value)
            this.head.next = this.head
            this.tail = this.head
        } else {
            const flag = this.head === this.tail
            this.tail.next = new Node(value)
            this.tail.next.next = this.head
            this.tail = this.tail.next
            if (flag) {
                this.head.next = this.tail
            }
        }
    }
	// 出队
    dequeue() {
        if(this.head == null) return -1

        if (this.head === this.tail) {
            const value = this.head.element
            this.head = null
            return value
        } else {
            const value = this.head.element
            this.head = this.head.next
            this.tail.next = this.head
            return value
        } 
    }

    display() {
        let res = 0
        console.log('-------获取dequeue元素------')
        while (res !== -1) {
            res = this.dequeue()
            console.log(res)
        }
    }
}
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>07.基于链表实现的循环队列</title>
    </head>
    <body>
        <script type="module">
            import { CircularQueue } from "./js/07/CircularQueue.js";

            const newCircularQueue = new CircularQueue();
            // 插入元素
            newCircularQueue.enqueue(1);
            newCircularQueue.enqueue(2);
            newCircularQueue.enqueue(3);
            console.log(newCircularQueue);
            // 获取元素
            newCircularQueue.display();
            newCircularQueue.enqueue(1);
            newCircularQueue.display();
        </script>
    </body>
</html>

在这里插入图片描述

阻塞队列

阻塞队列就是在队列基础上增加了阻塞操作。

  • 在队列为空的时候,从队头取数据会被阻塞。直到队列中有了数据才能返回
  • 如果队列已经满了,那么插入数据的操作就会被阻塞。直到队列中有空闲位置后再插入数据,然后再返回

可以使用阻塞队列实现一个生产者 - 消费者模型,有效地协调生产和消费的速度。

如何实现一个线程安全的队列呢?

线程安全的队列叫作并发队列。在多线程情况下,会有多个线程同时操作队列,这个时候就会存在线程安全问题,最简单的解决方式就是直接在 enqueue()、dequeue() 方法上加锁,但是锁粒度大并发度会比较低,同一时刻仅允许一个存或者取操作。

如何实现一个高效的并发队列:

  1. 基于数组的循环队列:避免数据搬移
  2. CAS原子操作:避免真正的去OS底层申请锁资源

队列的应用

基于链表的实现方式,可以实现一个支持无限排队的无界队列(unbounded queue),但是可能会导致过多的请求排队等待,请求处理的响应时间过长。所以,针对响应时间比较敏感的系统,基于链表实现的无限排队的线程池是不合适的。而基于数组实现的有界队列(bounded queue),队列的大小有限,所以线程池中排队的请求超过队列大小时,接下来的请求就会被拒绝,这种方式对响应时间敏感的系统来说,就相对更加合理。

队列可以应用在任何有限资源池中,用于排队请求,比如数据库连接池等。对于大部分资源有限的场景,当没有空闲资源时,基本上都可以通过队列这种数据结构来实现请求排队。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/345220.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

综合保税区快速发展,卖家抓紧瞄准跨境电商

综合保税区指的是我国设立在内陆地区的海关特殊监管区域&#xff0c;具有报税港区的功能&#xff0c;这是由海关参照有关规定对综合保税区进行管理&#xff0c;执行保税港区的外汇政策和税收&#xff0c;集合众多功能于一身&#xff0c;包括保税区、保税物流区、出口加工区、港…

JNI开发之-CMake方式调用第三方so

CMake方式调用第三方so背景CMake工程配置工程配置配置CMakeLists.txt配置build.gradle调用第三方so中的方法背景 最近一个项目是对接自研团队的个so库&#xff0c;因为之前都是用ndk来编译自己的so库&#xff0c;一直没有问题&#xff0c;但是用到这个自研的的so库一直有问题&…

usbmon+tcpdump+wireshark USB抓包

文章目录usbmon抓包及配合wireshark解析usbmon抓包及配合wireshark解析 usbmon首先编译为内核模块&#xff0c;然后通过modprobe usbmon加载到linux sys文件系统中 rootroot-PC:~# modprobe usbmon​ 而后 linux系统下安装 tcpdump rootroot-PC:~# apt-get install tcpdump​…

如何开发一个好用的公共组件

写在前面 当你对某一个业务场景有自己的理解&#xff0c;想提炼开发了一个很好用的组件&#xff0c;想开放给别的同学使用&#xff0c;或者甚至放在社区给任何一个人使用&#xff0c;你应该会产生以下疑问&#xff1a; 一个标准的组件是怎么样的&#xff0c;在开发过程中有哪…

android-java同步方法和异步方法

接口 Java接口是一系列方法的声明&#xff0c;是一些方法特征的集合&#xff0c;一个接口只有方法的特征没有方法的实现&#xff0c;因此这些方法可以在不同的地方被不同的类实现&#xff0c;而这些实现可以具有不同的行为&#xff08;功能&#xff09;。 两种含义&#xff1a…

中文编程发展不起来,无代码开发能否打个翻身仗

中文编程夹缝里生存众所周知&#xff0c;易语言开创了中文编写程序的先河&#xff0c;最早可追溯到2000年。当时易语言风靡一时&#xff0c;背后积攒了大批的用户&#xff0c;承载着那一代人的青春。也帮助了很多普通的初学者能够在短时间的入门。如今的易语言早已失去了往日的…

大咖说·图书分享|狼书(卷3):Node.js高级技术

Node.js都有哪些需要掌握的高级技术&#xff1f;前端为什么同样需要学习&#xff1f; Node.js未来的发展趋势究竟如何&#xff1f;本期大咖说&#xff0c;Node布道师桑世龙携新作《狼书(卷3)&#xff1a;Node.js高级技术》展开分享。 ● 嘉宾介绍 桑世龙&#xff1a;Node布道…

博客系统 SSM 超强硬核良心推荐之第一弹 - 预备工作

硬核 ! 从 0 到 1 完美实现 SSM 版本的博客系统 , 学会保准不吃亏!一 . SSM 版本相比于 Servlet 版本的亮点二 . 初始化数据库三 . 前端页面3.1 注册页面3.2 登录功能3.3 文章总列表页3.4 自己的文章列表页3.5 文章详情页3.6 编写博客页面大家好 , 这是新的专栏 , 博客系统 SSM…

嵌入式Linux学习经典书籍-学完你就是高手

很多刚入门的朋友一直都有人问我要学习资料&#xff0c;嵌入式实在太杂&#xff0c;网上很多人写的太不负责了&#xff0c;本书单综合了本人以及一些朋友多年的经验整理而成。 本人见识和阅读量有限&#xff0c;本书单可能有不对的地方&#xff0c;欢迎朋友指正&#xff0c;交…

SCI写作,一定要避开这些“雷点”!

SCI论文写作中&#xff0c;除了要符合各部分的写作要求&#xff0c;还有许多细节问题需要我们注意&#xff0c;不然可能一不小心就会“踩雷”。 今天我们就来和大家分享SCI各个部分写作时的注意事项。 下面就进入正题&#xff01; SCI写作注意事项 01 标题的拟定 1.避免使用无…

[Vivado那些事儿]将自定义 IP (HDL)添加到 Vivado 模块设计(Block Design)

绪论使用Vivado Block Design设计解决了项目继承性问题&#xff0c;但是还有个问题&#xff0c;不知道大家有没有遇到&#xff0c;就是新设计的自定义 RTL 文件无法快速的添加到Block Design中&#xff0c;一种方式是通过自定义IP&#xff0c;但是一旦设计的文件有问题就需要重…

短信链接跳转微信小程序

短信链接跳转微信小程序1 实现方案1.1 通过URL Scheme实现1.2 通过URL Link实现1.3 通过云开发静态网站实现2 实现方案对比3 实践 URL Schema 方案3.1 获取微信access_token3.2 获取openlink3.3 H5页面&#xff08;模拟短信跳转&#xff0c;验证ok&#xff09;4 问题小节4.1 io…

机器视觉_HALCON_示例实践_1.检测圆形

文章目录一、引言二、检测圆形三、总结一、引言 前面的文&#xff08;用户指南/快速向导&#xff09;差不多已经把HALCON的基本内容讲完了&#xff0c;并且在学习过程中还跑过一个简单示例——在单一背景下定位回形针。示例跑过&#xff0c;顿时觉得自己行了&#xff0c;但如果…

当make执行遇到 Arguments too long

1. 问题 Ubuntu20.04上make编译生成so的时候报错&#xff1a; make[1]:execvp:/bin/sh:Arguments too long对应makefile中的报错位置&#xff0c;仅仅是生成so的时候报错&#xff0c;伪代码如下 ${build_tool} -shared -fpic -o "$" ${OBJ_FILE} ${LDFLAGS}然而如…

Linux基础 - NTP时间同步

‍‍&#x1f3e1;博客主页&#xff1a; Passerby_Wang的博客_CSDN博客-系统运维,云计算,Linux基础领域博主 &#x1f310;所属专栏&#xff1a;『Linux基础』 &#x1f30c;上期文章&#xff1a; Linux基础 - DNS服务进阶 &#x1f4f0;如觉得博主文章写的不错或对你有所帮助…

IP地址在网络安全行业有哪些应用?

随着我国网络安全法律的颁布实施、制度的细化落实以及标准体系的制定&#xff0c;为我国产业数字化和数字产业化铺平了道路。近几年&#xff0c;数据将对网络安全行业产生巨大影响&#xff0c;包括行业数据的采集、共享&#xff0c;智能算法的演进以及算力资源的复用&#xff0…

ContextCapture Master 倾斜摄影测量实景三维建模技术应用

查看原文>>>https://mp.weixin.qq.com/s?__bizMzAxNzcxMzc5MQ&mid2247582483&idx3&sn38b94b4415ff29531e1619afe0c4df87&chksm9be29c03ac951515c28be526c987b19aedc1a5b3ad98ada5676e8c548f0f229665f495a0f281&token10630879&langzh_CN#rdCo…

Windows 11 绕过 TPM 方法总结,通用无 TPM 镜像下载 (2023 年 1 月更新)

在虚拟机、Mac 电脑和 TPM 不符合要求的旧电脑上安装 Windows 11 的通用方法总结 请访问原文链接&#xff1a;https://sysin.org/blog/windows-11-no-tpm/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;www.sysin.org 本文要解决的问题…

Qt 不规则窗口,不规则按钮,不规划控件 不规则界面

有一些特殊情况&#xff0c;需要使用不规则窗口或按钮&#xff0c;看起来非常炫酷。 类似&#xff1a; Qt 实现 不规则样式设置&#xff0c;不是视觉欺骗&#xff0c;是真正的不规则 &#xff0c;点击外面不会触发按钮的点击信号. Part1&#xff1a;不规则窗口 效果&#xf…

【软考——系统架构师】信息系统基础

&#x1f50e;这里是【软考——系统架构师】&#xff0c;关注我考试轻松过线 &#x1f44d;如果对你有帮助&#xff0c;给博主一个免费的点赞以示鼓励 欢迎各位&#x1f50e;点赞&#x1f44d;评论收藏⭐️ 文章目录&#x1f440;一、信息化概述&#x1f440;二、信息系统工程总…