数据结构----队列和栈

news2024/9/23 13:28:36

       小编会一直更新数据结构相关方面的知识,使用的语言是Java,但是其中的逻辑和思路并不影响,如果感兴趣可以关注合集。

       希望大家看完之后可以自己去手敲实现一遍,同时在最后我也列出一些基本和经典的题目,可以尝试做一下。大家也可以自己去力扣或者洛谷牛客这些网站自己去练习,数据结构光看不敲是学不好的,加油,祝你早日学会数据结构这门课程。

        如果不是天才,就请一步一步来。

目录

队列

     相关题目


队列

 概述

        计算机科学中,队列(queue)是以顺序的方式维护的一组数据集合,规定只能在一端添加数据,在另一端移除数据。习惯来说,添加的一端称为队尾,移除的一端称为队头,就如同生活中的排队买商品,后面来排队的人都要排在队尾,哪怕你是超雄也不许插队,前面的人排在队头准备结账,结账走了就好比移除操作。

  实现

        队列可以通过链表实现也可以通过数组来实现,这里我两个都实现一下。

        不管我用链表还数组来模拟实现队列,队列这种数据结构它所支持的操作是不变的,比如在队尾插入值,从队头删除值,获得队头的值还是检查队列是否为空等等,这些操作的性质和名称都是不变的,所以我们可以采用面向接口编程,这里先写好一个队列的接口,这样也方便我接下来的实现,接口也就定义了四个方法,都是队列所具备的基本操作,E是规定泛型,不局限于基本数据类型。

// 队列接口
public interface Queue<E> {
    //向队列尾插入元素
    boolean push(E value);

    // 从队列头获取值并移除
    // 如果队列为空则返回null
    E poll();

    // 获取队列头的值
    E peek();

    // 检查队列是否为空
    boolean isEmpty();
}
链表实现
    结构

        这里我们采用单向环形带哨兵节点的链表来模拟实现队列,选择环形链表是弥补上一篇文章留下的环形链表的实现,带哨兵节点是有利于我们处理一些队列为空时的特殊情况。

        我们首先来看一下单向环形链表的结构,节点类和之前都是一样的,由于是单向所以也就不需要prev指针。

// 节点类
private static class Node<E> {
        E value;
        Node<E> next;

        public Node(E value, Node<E> next) {
            this.value = value;
            this.next = next;
        }
    }

        接下来就是哨兵节点,我们需要设置一个哨兵节点head,但是我们还需要设置一个tail变量来指向链表的尾节点,因为这样可以使我们操作队列尾的时候更加方便,不需要从头遍历链表了。又因为是环形节点,一开始tail的next指针也要指向head,这些可以在构造函数中设置,因为哨兵节点随队列对象创建而创建。

// 链表实现队列
public class LinkedListQueue<E> implements Queue<E> {
    private static class Node<E> {
        E value;
        Node<E> next;

        public Node(E value, Node<E> next) {
            this.value = value;
            this.next = next;
        }
    }

    Node<E> head;
    Node<E> tail;

    public LinkedListQueue() {
        head = new Node<>(null, null);
        tail = head;
        tail.next = head;
    }
}
 添加元素

        添加元素我们直接就是完善接口中的push方法就好了,对于在单向环形链表中我们添加元素,由于是在尾部添加,所以我们只需要将哨兵尾节点的next指向新节点cur,然后将新节点cur赋给tail更新哨兵尾节点就好了。

        画的有点抽象,先看黑色再对着代码看红色的步骤。

        

    //向队列尾插入元素
    @Override
    public boolean push(E value) {
        // 1.先把cur的next指针指向head,构成环
        Node<E> cur = new Node<>(value, head);
        // 2.把tail节点和cur节点连起来
        tail.next = cur;
        // 3.更新cur节点为tail节点
        tail = cur;
        return true;
    }
遍历

        遍历队列实则就是遍历单向环形链表,链表的第一个节点从head的next节点开始,然后因为是环形,所以当我们再一次来到head节点是证明我们已经走完一圈了。简单直接上代码

    // 遍历
    public void forEach() {
       // 因为哨兵节点没有意义,真正的第一个节点是哨兵的后一个节点
        Node p = head.next;
        // 链表成环,再一次来到head节点证明已经走过一圈
        while (p != head) {
            System.out.println(p.value);
            p = p.next;
        }
    }

        实现完遍历后我们就可以测试我们的添加方法了。

    @Test
    public void test01(){
        LinkedListQueue<Integer> queue = new LinkedListQueue<>();
        queue.push(1);
        queue.push(2);
        queue.push(3);
        queue.push(4);
        queue.push(5);
        queue.forEach();
    }

         测试显示通过,打印与预期相同没有问题。

        由于队列只允许操作头和尾,所以也就没有什么根据索引插入删除之类的操作,实现起来也是简单了许多。

队列是否为空 

        接下来我们来实现isEmpty这个方法,就是判断队列是否为空,这个方法特别简单,因为我们设置了一个tail变量来表示链表尾节点,只有当链表为空时tail才与head相等

    // 判断队列是否为空
    @Override
    public boolean isEmpty() {
        return head == tail;
    }
获取队列头元素

        这个方法就是我们接口中的peek方法,这个方法要求我们返回队列头节点的值就行了,这也是非常节点,我们只要返回head的next指针指向的节点的值就行了。记得特殊处理队列为空的情况。

    //获取队列头元素
    @Override
    public E peek() {
        if (isEmpty()) {
        // 队列为空返回null
            return null;
        }
        return head.next.value;
    }

        测试一下也是没有问题的。 

删除队头元素

        poll方法与peek方法不同的是,poll方法还需要移除队头。删除一个链表的头节点相信你已经会了,head的next指针指向的就是待删除节点cur,我们只需要把head的next指向设置成cur的next指向的节点就好了,这样就把cur节点删除掉了。

        这时我们再考虑一下特殊情况,当队列中只有一个节点,那么cur的next指向就是head(因为是环形链表)这时我们删除也是没有问题的,但是这时我们要改变tail的值,因为只有一个节点删除之后我们要将tail设置成head,而其它情况的删除我们不用更改,因为删除第一个节点与tail指向的最后一个节点没有关系。

    //删除队列头元素
    @Override
    public E poll() {
        if (isEmpty()) {
            // 如果链表为空返回null
            return null;
        }
        // 待删除节点cur
        Node<E> cur = head.next;
        // 删除cur节点
        head.next = cur.next;
        // 如果队列中只有一个节点特殊处理
        if (cur == tail) {
            tail = head;
        }
        return cur.value;
    }

        测试一下,没有问题。 

        用链表模拟实现队列我们也就完成了,另外有些地方会给队列设置一个size大小属性和capacity容量属性来表示队列有没有满,这里我就不带大家实现了,大家有兴趣可以自己加上去,这并没有多困难,相信你一定可以实现的。

环形数组实现
   概述

       环形数组就是一个首尾相连的数组,以前我们的数组是线性的,想象一下抽取其中一部分出来首尾相连也就构成了一个环形数组。主要优点就是不会存在空间浪费,性能更佳等。底层我们还是用一个数组来实现的,只是通过代码程序控制让它变成环形数组。

   结构

        环形数组的底层还是数组,另外由于我们模拟队列实现,所以我们还需要额外设置两个指针一个指向队列头,一个指向队列尾。另外我们还可以提供一个带参数的构造函数,由外界自己设置环形数组的大小,当然这里也可以我们自己设置,这都不是重点。

public class ArrayQueue<E> implements Queue<E> {

    //环形数组
    private E[] array;
    //队列头指针
    private int head = 0;
    //队列尾指针
    private int tail = 0;

    //构造函数根据给的容量参数来创建数组
    public ArrayQueue(int capacity) {
        array = (E[]) new Object[capacity + 1];
    }

}
队列是否为空

        判断队列是否为空也是非常的简单,和链表实现一样,我们只需要判断head是否等于tail,因为只有当链表为空时head才等于tail。

    //判断队列是否为空
    @Override
    public boolean isEmpty() {
        return head == tail;
    }
队列是否满

        由于我们对外提供了一个设置容量的构造方法,所以我们在使用时也得注意不能当队列满了之后我们还继续添加元素。所以我们要判断一下队列是否满,在这之前我们要先学习一下环形数组如何求索引,非常简单我们在表示索引时都模上一个环形数组的长度就可以了,公式就是(index)%arr.length。接着我们来看看如何判断环形数组是否满,环形数组只有当tail指针的下一个索引为head指针时就表示环形数组已经满了。表示出来也就是判断表达式(tail+1)%arr.length == head。

    //判断队列是否满
    @Override
    public boolean isFull() {
        return (tail + 1) % array.length == head;
    }
添加元素 

        往队列尾部新增元素其实我们只需要在当前尾指针tail指向的地方添加元素就行了,然后不要忘了更新尾指针,更新尾指针tail时由于是环形数组,我们+1后不要忘了模上一个数组的长度

    //队尾添加元素
    @Override
    public boolean push(E value) {
        // 队列已经满了,特殊处理
        if (isFull()) {
            return false;
        }
        array[tail] = value;
        tail = (tail + 1) % array.length;
        return true;
    }
遍历

        遍历队列实则就是遍历我们的环形链表,我们也是和之前遍历的套路一样从队头head开始然后一直往后走,直到与队尾指针tail相等那我们就可以停止了。每次向前走都要模上一个数组的长度这是防止索引越界。

    //遍历
    public void forEach() {
        int cur = head;
        while (cur != tail) {
            System.out.println(array[cur]);
            cur = (cur + 1) % array.length;
        }
    }

         我们在实现完遍历和添加元素后我们就可以测试一下了。 

    @Test
    public void test02(){
        ArrayQueue queue  =new ArrayQueue(10);
        queue.push(1);
        queue.push(2);
        queue.push(3);
        queue.push(4);
        queue.push(5);
        queue.forEach();
    }

 

        测试显示通过同时打印也是我们的预期结果。 

删除队头元素

        在头部删除节点我们只需要将头指针head向后移动一位就代表我们删除了队头元素。同时不要忘了更新head时模上一个数组长度。   

    //队头删除元素
    @Override
    public E poll() {
        // 队列为空,特殊处理
        if (isEmpty()) {
            return null;
        }
        E value = array[head];
        head = (head + 1) % array.length;
        return value;
    }

        测试一下也是没有问题的。

获取队列头部元素

        这个方法实现起来更是简单,我们只需要返回头指针指向的元素就行了。

    // 获取队头元素
    @Override
    public E peek() {
        if (isEmpty()) {
            return null;
        }
        return array[head];
    }

        测试一下没有问题。

     同样用环形数组去实现队列也可以去新增两个变量,一个size表示大小,一个capacity表示容量,然后来判断队列是否空是否满等等,这个大家可以自己去实现一下,其实大同小异。

   概述

        计算机科学中,栈stack是一种线性的数据结构,规定只能在其一端添加数据和移除数据。习惯来说,这一端称之为栈顶,另一端不能操作数据的称之为栈底,就如同生活中的一个杯子里面装满了球,只有先拿走上面的球才可以拿到下面的球。

           和队列一样我们会用链表和数组两种方式模拟实现队列,为了接下来的实现方便我们还是先定义一个栈接口,里面先定义好几个栈的基本方法。E是规定泛型,不局限于基本数据类型。

public interface Stack<E> {

    // 向栈顶添加元素
    boolean push(E value);

    // 从栈顶弹出元素并返回
    E pop();

    // 获取栈顶元素
    E peek();

    // 判断栈是否为空
    boolean isEmpty();

    // 判断栈是否满
    boolean isFull();
}
链表实现
      结构

        这里我们用带哨兵节点的单向链表来实现。那栈的结构也就包含了一个哨兵头节点head,同时这里我们再给它设置一个capacity变量表示容量,一个size变量表示大小,来补一下队列中留的作业。

public class LinkedListStack<E> implements Stack<E> {

    private int capacity; // 容量
    private int size; // 大小
    private Node<E> head; // 哨兵头节点

    public LinkedListStack(int capacity) {
        this.capacity = capacity;
        head = new Node<>(null, null);
    }

    static class Node<E> {
        E value;
        Node<E> next;

        public Node(E value, Node<E> next) {
            this.value = value;
            this.next = next;
        }
    }
}

        这里讲一下因为栈不同于队列,栈只可以操作栈顶这一端,所以我们不用像队列一样设置两两个哨兵节点。

 栈是否为空

        这个其实很简单,因为我们有了size变量去表示栈中元素的个数,所以当size == 0时栈就是空的,又或者是当我们哨兵节点head的next指针指向空也代表我们栈是空的。

    // 判断栈是否为空
    @Override
    public boolean isEmpty() {
        return size == 0;
    //    return head.next == null; 
    }
 栈是否满

        这个也简单,size变量是表示栈中元素的个数,capacity变量是代表我们栈的容量,也就是表示栈可以装多少个元素,所以当size == capacity 时栈就是满的

    // 判断栈是否满。
    @Override
    public boolean isFull() {
        return size == capacity;
    }
添加元素        

        在栈顶添加元素,又因为我们是用链表模拟实现栈,所以就可以转换为在链表头添加元素的问题,相信这个问题对于你来说已经易如反掌了吧。我们只需要让原来哨兵头节点head的next的值赋给待添加节点cur的next,然后我们让head的next 指向cur就好了。不要忘了栈的大小+1。

    // 在栈顶添加元素
    @Override
    public boolean push(E value) {
        // 链表已满返回false 表示添加失败
        if (isFull()) {
            return false;
        }
        // 第一步让cur的next指向原来head的next
        Node cur = new Node<E>(value, head.next);
        // 第二步把head的next指向cur
        head.next = cur;
        // 不要忘了栈的大小+1
        size++;
        return true;
    }
移除元素   

        照着上面添加元素的思路,其实移除栈顶元素,我们不难想到就是移除链表头节点。我们只需要让哨兵节点的next指向链表头节点cur的next就可以实现对cur的删除,不要忘了栈的大小-1。

    // 移除栈顶元素
    @Override
    public E pop() {
        // 链表为空返回null
        if (isEmpty()) {
            return null;
        }
        // 第一步拿到链表头节点cur
        Node<E> cur = head.next;
        // 第二步让head的next指向cur的next实现删除节点cur。
        head.next = cur.next;
        // 不要忘了栈的大小-1
        size--;
        return cur.value;
    }
获取栈顶元素

         这个更是简单,我们只需要返回链表头元素的值就好了,也就是head.next.value。

    // 获取栈顶元素
    @Override
    public E peek() {
    // 链表为空,返回null
        if (isEmpty()) {
            return null;
        }
        return head.next.value;
    }
  遍历

        遍历栈我们是从栈顶遍历到栈底,那么也就是遍历整条链表,这对你来说也是简简单单好吧。   

    //遍历
    public void forEach() {
        Node<E> cur = head.next;
        while (cur != null) {
            System.out.println(cur.value);
            cur = cur.next;
        }
    }

        测试代码和测试结果就不贴了啊,你们自己敲完测试一下就行了。

数组实现
    结构

        用数组来模拟实现栈我们肯定是需要一个数组array的,接着呢我们还需要一个变量top表示我们的栈顶指针,这就相当于我们用链表实现的head,top在数组中的位置一直指向栈顶的后一位。  

public class ArrayStack<E> implements Stack<E> {

    private E[] array;
    private int top; // 栈顶指针

    public ArrayStack(int capacity) {
        this.array = (E[]) new Object[capacity];
    }
}
  栈是否为空

        因为栈顶指针一直指向我们的栈顶后一位,那当我们栈顶指针指向0时也就表示我们此时栈为空。    

    // 判断栈是否为空
    @Override
    public boolean isEmpty() {
        return top == 0;
    }
   栈是否满 

          这个其实也简单,当我们栈顶指针top与数组长度arr.length相等时就表示栈是满的

    // 判断栈是否满。
    @Override
    public boolean isFull() {
        return top == array.length;
    }
    添加元素

         现在我们使用的是数组模拟链表那我们添加元素就更简单了,我们只需要在数组arr中的top位置处赋上新元素的值接着让栈顶指针往后走一步,也就是+1就可以了

    // 在栈顶添加元素
    @Override
    public boolean push(E value) {
        // 链表已满返回false 表示添加失败
        if (isFull()) {
            return false;
        }
        array[top] = value;
        top++;
        return true;
    }
删除元素

        对于用数组模拟实现的栈,我们不用向链表一样去删除那个节点(那块内存),因为数组的内存是连续的我们没法去删除其中一块,我们只能实现值覆盖来达到删除的目的,我们可以把栈顶指针往前移动,这样在下一次添加其它元素时会自动覆盖原来的值,这样也就意味着实现了删除。

    // 移除栈顶元素
    @Override
    public E pop() {
        // 链表为空返回null
        if (isEmpty()) {
            return null;
        }
        // 拿到栈顶元素的值
        E value = array[top - 1];
        top--;
        return value;
    }
获取栈顶元素

        这个和我们删除栈顶元素大同小异,只不过不用把栈顶指针往后移动。

    // 获取栈顶元素
    @Override
    public E peek() {
        if (isEmpty()) {
            return null;
        }
        return array[top - 1];
    }
遍历 

        由于栈是从栈顶往栈底遍历,所以我们遍历时也是从数组右边往左边遍历就好了。 

    //遍历
    public void forEach() {
        for (int i = top - 1; i >= 0; i--) {
            System.out.println(array[i]);
        }
    }

        自己敲完测试一下就行了。 

相关题目

        20. 有效的括号 - 力扣(LeetCode)

933. 最近的请求次数 - 力扣(LeetCode)

2073. 买票需要的时间 - 力扣(LeetCode)

234. 回文链表 - 力扣(LeetCode)

1614. 括号的最大嵌套深度 - 力扣(LeetCode)

150. 逆波兰表达式求值 - 力扣(LeetCode)

带着决心起床,带着满意入睡。

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

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

相关文章

【数据结构】六、图:2.邻接矩阵、邻接表(有向图、无向图、带权图)

二、存储结构 文章目录 二、存储结构❗1.邻接矩阵1.1无向图❗邻接矩阵-无向图代码-C 1.2有向图❗邻接矩阵-有向图代码-C 1.3带权图1.4性能分析1.5相乘 ❗2.邻接表2.1无向图2.2有向图❗邻接表-C 邻接矩阵VS邻接表邻接矩阵邻接表 ❗1.邻接矩阵 图的邻接矩阵(Adjacency Matrix) 存…

Transformer在量化投资中的应用

开篇 深度学习的发展为我们创建下一代时间序列预测模型提供了强大的工具。深度人工神经网络&#xff0c;作为一种完全以数据驱动的方式学习时间动态的方法&#xff0c;特别适合寻找输入和输出之间复杂的非线性关系的挑战。最初&#xff0c;循环神经网络及其扩展的LSTM网络被设…

云计算实训26——部署LVS负载均衡项目

LVS LVS是linux virtural server的简称——免费、开源、四层负载均衡 工作原理&#xff1a; 通过linux达到负载均衡好和linux操作系统实现高性能高可用的linux服务集群&#xff0c;具有良好的可靠性、可扩展性、可操作性、可扩展性、从而实现以低廉的成本实现最优的性能。LV…

VisionPro二次开发学习笔记10-使用 PMAlign和Fixture固定Blob工具检测孔

使用 PMAlign和Fixture固定Blob工具检测孔 这个示例演示了如何使用 PMAlign 工具和 Fixture 工具来夹持一个 Blob 工具。示例代码将检测支架右上角孔的存在。当点击运行按钮时&#xff0c;将读取新图像。PMAlign 工具运行并生成一个 POSE 作为输出。POSE 是一个六自由度的变换…

Mybatis(1)

一. Mybatis概述 原本是Apache的一个开源项目叫iBatis,2010年迁移到Google Code旗下,改名为Mybatis Mybatis是一款优秀的持久层框架,是对JDBC的封装Mybatis几乎避免了JDBC所有的手动设置参数以及手动获取结果的操作Mybatis可以使用注解或XML文件来配置和映射,将数据库中的数据…

springboot发送邮箱功能的安全与加密配置?

springboot发送邮箱设置的步骤&#xff1f;springboot发信优势&#xff1f; 为了确保邮件发送过程的安全性和隐私保护&#xff0c;我们需要对 SpringBoot发送邮箱功能进行适当的安全与加密配置。AokSend将详细探讨如何在 SpringBoot项目中实现这些配置&#xff0c;以保障邮件传…

大模型面试题集锦:揭秘阿里24k Star项目背后的争议,非常详细收藏我这一篇就够了

今天分享两个 Github 上开源的不错的项目&#xff0c;以及阿里空 Github 项目的趣闻。 一、开源大模型面试题 大致看了以下&#xff0c;面试题分门别类&#xff0c;还是挺全的。包含 LLM 基础&#xff0c;分布式训练&#xff0c;推理&#xff0c;强化学习等。 二、Awesome Co…

记录|Git工具——下载GitHub项目

目录 前言一、Step 1. 下载Git二、Step2. 用Git Bash 下载到本地更新时间 前言 参考文章&#xff1a; 1、如何使用Git将Github项目拉到本地 2、git 安装、创建仓库、上传项目、克隆下载、常用命令 – 一篇文章总结&#xff08;适用github / gitee&#xff09; 3、Git的使用【入…

2024网页设计教程:最新趋势与实用技巧

网页是每个人访问信息的载体&#xff0c;用户点击的按钮、浏览的导航栏和网页界面的视觉性能都与网页制作有关。良好的网页设计代表了友好的使用体验。个人网页、商业网页和社交媒体平台都应该吸引人们的注意&#xff0c;并提供令人印象深刻的客户体验。本文针对网页制作新手&a…

CentOS7.6单机部署RabbitMQ消息队列——实施方案

1、前期环境准备 1.准备一台主机 IP地址主机名角色内存大小192.168.200.10 rabbitmq 消息队列 2G 2. 设置主机名 hostnamectl set-hostname 主机名suexit Ctrlr 3. 设置IP地址然后重启网卡 vim /etc/sysconfig/network-scripts/ifcfg-ens33systemctl restart network 4.…

【一图学技术】8.图解Git工作流程使用 git 解决团队协作中的冲突问题 git 进行版本控制的最佳实践Git 的高级功能

图解Git的工作流程 一、Git常见命令概述 以下是 Git 常用命令的详细作用、使用例子和使用场景&#xff1a; git add 作用&#xff1a;将工作目录中的更改添加到暂存区。暂存区是一个准备下一次提交的区域&#xff0c;它记录了你想要提交的更改。使用例子&#xff1a;git add …

【机器人】关于钉钉机器人如何进行自定义开发问答【详细清晰】

目标&#xff1a;当用户输入问题并钉钉机器人&#xff0c;钉钉机器人进行相应的回答&#xff0c;达到一种交互问答的效果 开发文档参考&#xff1a;https://open.dingtalk.com/document/orgapp/robot-overview 首先进行登录企业&#xff0c;后面如果没有进行登录&#xff0c;会…

html编写贪吃蛇页面小游戏(可以玩)

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>贪吃蛇小游戏</title><style>body {…

Hadoop,ActiveMQ,RabbitMQ,Springboot Actuator未授权访问漏洞(附带修复方法)

十.Hadoop Hadoop是⼀个由Apache基⾦会所开发的分布式系统基础架构&#xff0c;由于服务器直接在开放了Hadoop 机器 HDFS 的 50070 web 端⼝及部分默认服务端⼝&#xff0c;⿊客可以通过命令⾏操作多个⽬录下的数据&#xff0c;如进⾏删除&#xff0c;下载&#xff0c;⽬录浏览…

LSTM--概念、作用、原理、优缺点以及简单的示例代码

LSTM的概念 LSTM&#xff08;Long Short-Term Memory&#xff09;是一种特殊的递归神经网络&#xff08;RNN&#xff09;&#xff0c;最早由Sepp Hochreiter和Jrgen Schmidhuber在1997年提出。LSTM设计的主要目的是解决标准RNN中的长时依赖问题。RNN在处理长序列时&#xff0c…

机房防静电地板和架空网络地板有哪些区别

有好些人把机房防静电地板和网络地板混为一谈&#xff0c;觉的两个就是一样的东西&#xff0c;其实呢&#xff0c;虽说都是高架活动地板&#xff0c;但它们之间的区别大着呢&#xff01;下面和宜缘机房一起来看看防静电地板和网络地板两者都有哪些区别&#xff1f; 1、使用场景…

安全基础学习-RC4加密算法

这里仅仅记录一些基础的概念。后期有需求进一步扩展。 RC4 是一种对称流加密算法&#xff0c;由罗恩里维斯特&#xff08;Ron Rivest&#xff09;于1987年设计。RC4 的设计目的是提供一种简单且高效的加密方法。尽管 RC4 曾经广泛使用&#xff0c;但它的安全性在现代已受到质疑…

精通C++ STL(七):stack和queue的介绍及使用

目录 stack stack的定义方式 stack的使用 queue queue的定义方式 queue的使用 stack stack 是一种容器适配器&#xff0c;专门用于处理后进先出的操作场景。它仅允许在容器的一端进行元素的插入和提取操作。 stack的定义方式 方式一&#xff1a; 使用默认适配器定义栈。 sta…

Linux 进程调度(三)之进程的优先级

目录 一、概述二、进程的优先级1、基础概念2、优先级的意义3、查看优先级4、PRI 和 NI5、修改优先级6、控制进程的优先级的系统调用7、调整优先级的限制 一、概述 在 Linux 中&#xff0c;每个进程都有一个优先级。优先级决定了进程在系统资源分配中的先后顺序。Linux 中的进程…

gin框架中的中断请求c.Abort()方法的作用和使用细节说明

Abort()方法的作用 在gin框架中&#xff0c;如果我们希望中断后续的挂起的请求处理链&#xff08;HandlersChain&#xff09;的请求&#xff0c; 可以使用gin.Context中的这个Abort()方法。请注意&#xff0c;这不会停止当前处理程序。假设您有一个授权中间件&#xff0c;用于…