双端队列,优先队列,单调队列

news2024/11/25 16:38:28

单调队列

单调队列是指一个队列内部元素具有单调性的数据结构

分为单调递增队列单调递减队列

单调队列满足三个性质:

  • 单调队列也是队列,满足先进先出
  • 单调队列必须满足从队头到队尾的单调性
  • 排在队列前面的元素比排在队列后面的元素要先进队

代码实现上的动作点:

  1. 维护队尾:保证单调性,及时排除不可能成为最优的决策。
  2. 维护队头:保证队内元素满足某种限制(比如区间的长度),确保决策集的合法性。

在这里插入图片描述

代码实现:

因为这是在头尾两端进行操作,所以用双端队列

class monoQueue{
    /*单调递减队列*/
public:
    // 在队尾添加元素
    void push(int val);
    // 队头元素如果是val,删除它
    void pop(int n);
     // 返回当前队列中的最大值--队头
    int max(){
        return dq.front();
    }
      //遍历元素
    void traverse(){
        for (int i = 0; i < dq.size();i++){
            cout << dq[i] << " ";//别忘了双端队列的下标访问
        }
        cout << endl;
    }
private:
    deque<int> dq;
};
void monoQueue::push(int val){
    //入队前,把小于x的元素出队
    while(!dq.empty()&& dq.back()<val){
        dq.pop_back();
    }
    dq.push_back(val);
}
void monoQueue::pop(int val){
    //判断队头元素,一定要判断队头存在性
    if(!dq.empty() && dq.front()==val){
        dq.pop_front();
    }
}

双端队列使用

  • push_front(val),pop_front()
  • push_back(val),pop_back()
#include<iostream>
#include<deque>//双端队列头文件
using namespace std;
int main(){
    deque<int> deq = {1, 2, 3};//初始化
    deq.push_front(11);
    deq.push_front(22);
    deq.push_back(33);
    deq.push_back(44);
    for(auto v:deq)
        cout << v << " ";//22 11 (1 2 3) 33 44
    deq.pop_front();
    deq.pop_back();
    cout << endl;
    for(auto v:deq)
        cout << v << " ";// 11 (1 2 3) 33 
     return 0;
}

可以用名称加下标对双端队列进行访问

deque<int> deq = {1, 2, 3};//初始化
    deq.push_front(11);
    deq.push_front(22);
    deq.push_back(33);
    deq.push_back(44);
    for (int i = 0; i < deq.size();i++)
        cout << deq[i] << " ";

deque存储特殊类型的元素

 struct student{
        int age;
        string name;
        student(int a,string b):age(a),name(b){}
    };
    deque<student> deq;
    student a(15, "daming");
    student b(20, "amy");
    student c(30, "alice");
    student d(33, "mary");
    deq.push_front(a);
    deq.push_back(b);
    deq.push_front(c);
    deq.push_back(d);
    for(auto [k,v]:deq){
        cout << k << "," << v << endl;
   }
30,alice
15,daming
20,amy
33,mary

迭代器

begin(),end() vs cbegin(),cend()-----区别就是c是const,不可修改值

deque<char> deq = {'a', 'b', 'c', 'd', 'e'};
     for (auto it = deq.begin(); it != deq.end();it++)
         (*it) += 1;
     for (auto it = deq.cbegin(); it != deq.cend(); it++)
         cout << (*it) << " ";
//cbegin()不可修改*it内容

rbegin(),rend() vs crbegin(),crend()-----区别就是r是reverse,c同const

deque<char> deq = {'a', 'b', 'c', 'd', 'e'};
     for (auto it = deq.rbegin(); it != deq.rend();it++){
         cout << *it << " ";
         (*it) += 1;
     }
     cout << endl;
     for (auto it = deq.crbegin(); it != deq.crend(); it++)
         cout << (*it) << " ";
  • front()和back()也就是队头和队尾

     deque<char> deq = {'b', 'a','b','b', 'c', 'b', 'e'};
         for (auto it = deq.begin()+1; it != deq.end();){
            if(*it==deq.front())//front();back()
                it = deq.erase(it);
            else
                it++;
         }
    
  • erase(it1,it2) [it1,it2)

deq.erase(deq.begin() + 1, deq.end() -1);

leecode:滑动窗口最大值

239. 滑动窗口最大值

法一:单调队列类解决

首先先看一下类中含有另一个类的对象用法

class triangle{
public:
    triangle(double a, double b) : a(a), b(b) {}
    double area()
    { // 计算面积
        return (1.0 / 2) * a * b;
    }

private:
    double a, b;
};
class pyramid{
public:
    // 传参是类对象的多参数
    pyramid(double a, double b, double c) : height(a), tri(b, c) {}
    double volume()
    { // 计算体积
        return (1.0 / 3) * height * tri.area();
    }

private:
    triangle tri; // 类triangle对象
    double height;
};
int main(){
    pyramid tmp(6, 12, 24);
    cout << tmp.volume();
    return 0;
}

解题:

直接建立一个单调递减队列的数据结构,然后入队和出队操作就调用函数

只需要考虑移动时的窗口中的数据,注意:单调队列的数据和原数据并不是吻合的

所以原数据窗口需要用到数组下标来决定:

[0,1,2,3,4,…,k-1],所以i-队头+1=k即:窗口头部下标为:i-k+1

class monoQueue{
public:
    /*建立单调递减队列--队头是最大值*/
    //入队
    void push(int x){
        while(!dq.empty()&&x>dq.back()){
            dq.pop_back();
        }
        dq.push_back(x);
    }
    //删除指定大小的队头
    void pop(int x){
        if(!dq.empty()&&dq.front()==x){
            dq.pop_front();
        }
    }
    //队头是最大值
    int max(){
        if(!dq.empty())
            return dq.front();
        throw "dq is empty()";
    }
private:
    deque<int> dq;
};
class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> res;
        //从头开始遍历元素
        for(int i=0;i<nums.size();i++){
            //不足k个元素时,元素入队
            if(i<k-1){//0,..,k-2,k-1
               mo.push(nums[i]);
            }//已经装满k-1个元素
            else{
               mo.push(nums[i]);//移入新元素
               res.push_back(mo.max());
               mo.pop(nums[i-k+1]);
            }
        }
        return res;
    }
private:
    monoQueue mo;//单调队列成员
};
 vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> res;
        deque<int> dq;
        for(int i=0;i<nums.size();i++){
            if(i<k-1){
                while(!dq.empty() && nums[i]>dq.back()){
                    dq.pop_back();
                }
                dq.push_back(nums[i]);
            }
            else{
                while(!dq.empty() && nums[i]>dq.back()){
                    dq.pop_back();
                }
                dq.push_back(nums[i]);
                res.push_back(dq.front());
                if(dq.front()==nums[i-k+1]){
                    dq.pop_front();
                }
            }
        }
        return res;
    }

也可以在代码中表现出:单调队的性质

法二:用双端队列存下标

分析双指针,前缀和以及单调队列
  • 双指针:维护的信息的一个点或者多个点

  • 前缀和:维护的信息是一个区间

    [l,r]的信息可以通过[0,r]和[0,l-1]的信息推导出

    比如:

    1 5 3 2 -1 —1 5最大值5,1 5 3 2 -1最大值5,但是得不出3 2 -1 最大值3,

  • 单调队列:维护的信息是一个区间,一般与最值有关

 vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        //首先将[0,k-1]元素入栈,使得窗口大小为k
        deque<int> dq;//存下标,维护递减队列
        vector<int> res;
        for(int i=0;i<=k-1;i++){
            while(!dq.empty()&&nums[i]>nums[dq.back()]){
                dq.pop_back();
            }
            dq.push_back(i);
        }
        res.push_back(nums[dq.front()]);//存入第一个结果
        //接下来尝试前移窗口
        for(int i=k;i<nums.size();i++){
            while(!dq.empty()&&nums[i]>nums[dq.back()]){
                dq.pop_back();
            }
            dq.push_back(i);
            //合法性检查,判断当前单调队列队头是否在窗口内
            if(!dq.empty()&&i-dq.front()+1>k){
                dq.pop_front();
            }
            res.push_back(nums[dq.front()]);
        }
        return res;
    }

当然也可以合并成一个for,分为if,else

  • 窗口不足k,一直更新单调栈
  • 窗口大于k,每次加入一个新元素后,必须判断队头是否过期了
 vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        deque<int> dq; 
        vector<int> res;
        for (int i = 0; i < nums.size(); i++) {
            if (i <= k - 1) {
                while (!dq.empty() && nums[i] > nums[dq.back()]) {
                    dq.pop_back();
                }
                dq.push_back(i);
                if (i == k-1) {//注意k-1是第一个满足的
                    res.push_back(nums[dq.front()]);
                }
            }//if
            else {
                while (!dq.empty() && nums[i] > nums[dq.back()]) {
                    dq.pop_back();
                }
                dq.push_back(i);
                //合法性检查,判断当前单调队列队头是否在窗口内
                if (!dq.empty() && i - dq.front() + 1 > k) {
                    dq.pop_front();
                }
                res.push_back(nums[dq.front()]);
            }
        }
        return res;
    }
单调队列模板
for 数组中的每个元素:
    1:while/if(队头过期) 删除队头----这里i和队头下标距离大于窗口k就是过期了
    
    2:while(队尾破坏单调性) 删除队尾
    加入新元素----单调队列的新元素一定会入队,所以一定先去掉破坏单调性的
    
    if(满足条件)  计算答案----这里的条件指的是:i超过k-1
    
    //1和2根据实际条件,可以颠倒
    
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> res;
        deque<int> dq;
        for(int i=0;i<nums.size();i++){
            //队头进行合法性检查
            while(!dq.empty() && nums[i]>nums[dq.back()]){
                dq.pop_back();
            }
            dq.push_back(i);
            if(!dq.empty()&&i-dq.front()+1>k){
                //dq.top()不在终点为i的窗口内了
                dq.pop_front();
            }
            //合法结果存入res
            if(i>=k-1){
                res.push_back(nums[dq.front()]);
            }
        }
        return res;
    }

颠倒

for(int i=0;i<nums.size();i++){
         //1
         while(!dq.empty()&&i-dq.front()+1>k){
             dq.pop_front();
         }
         //2
         while(!dq.empty() && nums[i]>nums[dq.back()]){
             dq.pop_back();
         }
         dq.push_back(i);
         //3
         if(i>=k-1){
             res.push_back(nums[dq.front()]);
         }
     }
用优先队列实现

注意堆一定要存值,但是堆中的下标有意义,单调队列中,一定程度上保证了有序性,也就是i-k+1的位置是队头,但是堆不是这样的。所以要存两个信息

vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        //定义大顶堆
        typedef pair<int,int> T;// using T=pair<int,int>;
        priority_queue<T> pq;
        vector<int> res;
        for(int i=0;i<=k-1;i++){
           pq.push(make_pair(nums[i],i));
        }
        res.push_back(pq.top().first);
        for(int i=k;i<nums.size();i++){
            pq.push(make_pair(nums[i],i));
            //判断堆头是否需要删除
            //注意用while,因为堆中可能多个元素在外面
            while(i-pq.top().second+1>k){
                pq.pop();
            }
            res.push_back(pq.top().first);
        }
        return res;
    }

因为堆中可能多个元素在外面,用while

​ while(i-pq.top().second+1>k)--------不可以用if

using 别名=类型;

优先队列

优先队列是以的形式来存储队列中的元素,并且每次在插入和删除数据时,会自动对数据进行排序

class PriorityQueue :public Heap{};

优先队列priority_queue在c++中的**#include**中

O(1)的时间内找到最值元素,并且能在在O(logn)的时间内插入和删除元素。

初始化

priority_queue<T, Container, Compare>//类型,容器,比较函数
priority_queue<T> //直接输入元素则使用默认容器和比较函数
  • T就是Type为数据类型

  • Container是容器类型

    Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list

    STL里面默认用的是vector

  • Compare是比较方法,类似于sort第三个参数那样的比较方式,可以自定义类型

//升序队列
priority_queue <int,vector<int>,greater<int> > q;//小顶堆,堆顶<其他
//降序队列
priority_queue <int,vector<int>,less<int> >q;//大顶堆,堆顶>其他
//greater和less是std实现的两个仿函数(就是使一个类的使用看上去像一个函数)

想象堆排序的原理:(大的下沉)

greater的第一个参数是当前元素,第二个参数是子节点,如果当前元素比子节点大,就下沉,所以是小顶堆。

常用函数

priority_queue<int> q;
//函数和栈常用函数类似
q.top();//取队列首元素,也就是堆顶元素
q.empty();//判断队列是否为空
q.size();//返回队列的元素个数
q.push(val);//向优先队列中插入一个元素
q.pop();//弹出队列头元素

例子

pair比较

先按照pair的first元素排序,first元素相等时,再按照second元素排序

#include <iostream>
#include <queue>
using namespace std;
int main()
{
    priority_queue<pair<int, char>> pq; // pq是大顶堆,默认第一个元素排序
    vector<int> aa = {100, 400, 200, 900, 300, 600};
    vector<char> bb = {'w', 'g', 'l', 'i', 'p', 'q'};
    for (int i = 0; i < 6; i++){
        pq.push(make_pair(aa[i], bb[i]));
    }
    while (!pq.empty()){
        cout << pq.top().first << "," << pq.top().second << endl;
        pq.pop();
    }
    return 0;
}

900,i
600,q
400,g
300,p
200,l
100,w

priority_queue< pair<char, int>,vector<pair<char, int>>,greater<pair<char,int>> >pq; // pq是小顶堆 
    vector<int> aa =  {'w','d','u','z','a','f'};
    vector<char> bb = {1,9,8,5,3,7};
    for (int i = 0; i < 6; i++){
        pq.push(make_pair(aa[i], bb[i]));
    }
    while (!pq.empty()){
        cout << pq.top().first << "," << pq.top().second << endl;
        pq.pop();
    }

注意:priority_queue<T, vector, greater >—这里用pair<>代替T

a,3
d,9
f,7
u,8
w,1
z,5

重载<
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
class T{
public:
    int a, b, c;
    T(int a,int b,int c):a(a),b(b),c(c){}
    //自定义比较
};
 bool operator <(const T& t1,const T& t2){//>要与greater<T>匹配
        return t1.c < t2.c;
    }
int main()
{
    priority_queue<T> pq;
    pq.push(T(1, 4, 7));
    pq.push(T(8, 3, 17));
    pq.push(T(9, 1, 9));
    pq.push(T(2, 2, 18));
    while(!pq.empty()){
        cout << pq.top().a << "," << pq.top().b << "," << pq.top().c << endl;
        pq.pop();
    }
    return 0;
}

2,2,18
8,3,17
9,1,9
1,4,7

class T{
public:
 int a, b, c;
 T(int a,int b,int c):a(a),b(b),c(c){}
 //自定义比较
 bool operator <(const T& t) const{//成员函数必须const修饰
     return c < t.c;
 }
};
/*bool operator <(const T& t1,const T& t2){//>要与greater<T>匹配
     return t1.c < t2.c;
}*/

类内重载必须加上const,这是一个重写的标准写法

class T{
public:
    int a, b, c;
    T(int a,int b,int c):a(a),b(b),c(c){}
    //类内友元函数方式
    friend bool operator <(const T& t1,const T& t2){
        return t1.c < t2.c;
    }
};

类内友元函数方式

注意:类内函数要加const,类外函数需要两个比较对象

大顶堆在重载运算符<之后,就可以不带参数判断

<和大顶堆匹配(less),因为小的下沉,自然就是大顶堆了

priority_queue<node, vector, less> pq;----正确
priority_queue<node, vector, greater> pq;----错误,因为没有greater

struct node{
    int x, y;
    node(int x=0,int y=0):x(x),y(y){}
};
//重载operator
bool operator<(const node& a,const node& b){
    return a.x < b.x;
}
int main()
{
    priority_queue<node> pq;
    for (int i = 0; i < 6;i++){
        int tmp1 = rand() % 10;
        int tmp2 = rand() % 20;
        cout << tmp1 << "," << tmp2 << endl;
        pq.push(node(tmp1,tmp2));
    };
    cout << "******" << endl;
    while(!pq.empty()){
        cout << pq.top().x << ":" << pq.top().y << endl;
        pq.pop();
    }
    return 0;
}

重载operator>后就可以定义小顶堆了

//重载operator
bool operator>(const node& a,const node& b){
 return a.x > b.x;
}
priority_queue<node, vector<node>, greater<node>> pq;
重载operator()
class node{
public:
    int a, b;
    node(int a=0,int b=0):a(a),b(b){}
};
class cmp{
public:
    bool operator()(const node& aa,const node& bb){
        return aa.b > bb.b;
    }
};
int main()
{
    priority_queue<node, vector<node>, cmp> pq;
    pq.push(node(1, 2));
    pq.push(node(3, 6));
    pq.push(node(4, 5));
    while(!pq.empty()){
        cout << pq.top().a << "," << pq.top().b << endl;
        pq.pop();
    }
    return 0;
}

1,2
4,5
3,6

看:2 5 6,因为>,大的下沉了,就变成小的了

class cmp{
public:
 bool operator()(const node& aa,const node& bb){
     return aa.a < bb.a;
 }
};

4,5
3,6
1,2

看:4 3 1,因为<,小的下沉了,就变成大的了

比较优先队列和sort()

#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
class node{
public:
    int a, b;
    node(int a=0,int b=0):a(a),b(b){}
    //类内重载函数
    bool operator<(const node& x) const{//别忘了const
        return a < x.a;
    }
};
int main()
{
    node a(11, 33);
    node b(22, 44);
    node c(13, 25);
    node d(31, 16);
    vector<node> vec;
    vec.push_back(a);
    vec.push_back(b);
    vec.push_back(c);
    vec.push_back(d);
    priority_queue<node> pq;
    for(auto m:vec)
        pq.push(m);
    sort(vec.begin(), vec.end());//排序
    for(auto [k,v]:vec){//vec小的在前
        cout << k << "," << v << endl;
    }
    cout << endl;
    while(!pq.empty()){//pq小的下沉
        cout << pq.top().a << "," << pq.top().b << endl;
        pq.pop();
    }
    return 0;
}

在这里插入图片描述

sort算法和优先级队列的排序方式刚好相反:

同一个自定义排序函数,sort是从大到小,而priority_queue是从下到大。

  • 这是数据结构自身决定的顺序

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

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

相关文章

excel统计分析——多组数据的秩和检验

单因素资料不完全满足方差的基本假定时&#xff0c;可进行数据转换后再进行方差分析&#xff0c;但有时数据转换后仍不满足方差分析的基本假定&#xff0c;就只能进行秩和检验了。 多组数据秩和检验的主要方法为Kruskal-Wallis检验&#xff0c;也称为Kruskal-Wallis秩和方差分析…

分布式文件系统 SpringBoot+FastDFS+Vue.js【二】

分布式文件系统 SpringBootFastDFSVue.js【二】 六、实现上传功能并展示数据6.1.创建数据库6.2.创建spring boot项目fastDFS-java6.3.引入依赖6.3.fastdfs-client配置文件6.4.跨域配置GlobalCrosConfig.java6.5.创建模型--实体类6.5.1.FastDfsFile.java6.5.2.FastDfsFileType.j…

__attribute__ ---Compile

Section for attribute attribute_&#xff1f;嵌入式C代码属性怎么定义 https://www.elecfans.com/d/2269222.html section 属性的主要作用是&#xff1a;在程序编译时&#xff0c;将一个函数或者变量放到指定的段&#xff0c;即指定的section 中。 一个可执行文件注意由代…

STM32——菜单(二级菜单)

文章目录 一.补充二. 二级菜单代码 简介&#xff1a;首先在我的51 I2C里面有OLED详细讲解&#xff0c;本期代码从51OLED基础上移植过来的&#xff0c;可以先看完那篇文章&#xff0c;在看这个&#xff0c;然后按键我是用的定时器扫描不会堵塞程序,可以翻开我的文章有单独的定时…

BUGKU-WEB 矛盾

题目描述 进入场景看看&#xff1a; 代码如下&#xff1a; $num$_GET[num]; if(!is_numeric($num)) { echo $num; if($num1) echo flag{**********}; }解题思路 需要读懂一下这段PHP代码的意思明显是一道get相关的题目&#xff0c;需要提供一个num的参数,然后需要传入一个不…

【数据结构】顺序栈和链式栈的简单实现和解析(C语言版)

数据结构——栈的简单解析和实现 一、概念二、入栈&#xff08;push&#xff09;三、出栈&#xff08;pop&#xff09;四、顺序栈简单实现 &#xff08;1&#xff09;进栈操作&#xff08;2&#xff09;出栈操作 一、概念 本篇所讲解的栈和队列属于逻辑结构上的划分。逻辑结构…

GPDB - 高可用 - FTS机制(一):探测成功

GPDB - 高可用 - FTS机制&#xff08;一&#xff09;&#xff1a;探测成功 作为GreenPlum高可用的核心功能&#xff0c;FTS&#xff08;Fault Tolerance Server&#xff09;进程负责故障检测。该进程是master上的一个子进程&#xff0c;可以快速检测到primary或者mirror是否宕机…

PyTorch深度学习快速入门教程 - 【小土堆学习笔记】

小土堆Pytorch视频教程链接 声明&#xff1a; 博主本人技术力不高&#xff0c;这篇博客可能会因为个人水平问题出现一些错误&#xff0c;但作为小白&#xff0c;还是希望能写下一些碰到的坑&#xff0c;尽力帮到其他小白 1 环境配置 1.1 pycharm pycharm建议使用2020的&…

【C语言】指针的进阶篇,深入理解指针和数组,函数之间的关系

欢迎来CILMY23的博客喔&#xff0c;本期系列为【C语言】指针的进阶篇&#xff0c;深入理解指针和数组&#xff0c;函数之间的关系&#xff0c;图文讲解其他指针类型以及指针和数组&#xff0c;函数之间的关系&#xff0c;带大家更深刻理解指针&#xff0c;以及数组指针&#xf…

LeetCode Python - 16.最接近的三数之和

目录 题目答案运行结果 题目 给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数&#xff0c;使它们的和与 target 最接近。 返回这三个数的和。 假定每组输入只存在恰好一个解。 示例 1&#xff1a; 输入&#xff1a;nums [-1,2,1,-4],…

Vulnhub靶场 DC-6

目录 一、环境搭建 二、主机发现 三、漏洞复现 1、wpscan工具 2、后台识别 dirsearch 3、爆破密码 4、rce漏洞利用 activity monitor 5、rce写shell 6、新线索 账户 7、提权 8、拿取flag 四、总结 一、环境搭建 Vulnhub靶机下载&#xff1a; 官网地址&#xff1a…

凭证获取:Linux凭证获取

目录 shadow文件详解 1.Shadow文件的组成与作用 2.破解Shadow文件内容 利用strace记录密码 shadow文件 1.Shadow文件的组成与作用 在Linux中&#xff0c;/etc/shadow文件又被称为“影子文件”&#xff0c;主要用于存储Linux文件系统中的用户凭据信息。该文件只能由root权…

【日常聊聊】新年新征程:迎接学习的挑战

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;日常聊聊 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 结语 我的其他博客 前言 随着新的一年的到来&#xff0c;程序员们站在了全新的起点。这是一个充满机遇和挑战的时刻&#xff0…

【C++初阶:类和对象(下篇)】初始化列表 | static成员 | 友元

目录 一、构造函数构造函数体赋值&#x1f43e;初始化列表&#x1f43e;&#x1f4a6; explicit关键字 二、static成员&#x1f43e;概念**&#x1f4a6; 关于静态的特性** 三、友元&#x1f4a6; **友元函数**&#x1f4a6; **友元类** **四、内部类** 一、构造函数 构造函数…

Spring 事务原理总结四

作为一名认知有限的中国人&#xff0c;我对年的喜爱&#xff0c;胜过其他一切&#xff0c;因为它给了我拒绝一切的合理理由。每到这个时候&#xff0c;我都会用各种理由来为自己的不作为开脱&#xff0c;今年亦是如此。看着频频发出警报的假期余额&#xff0c;我内心的焦躁变得…

分布式文件系统 SpringBoot+FastDFS+Vue.js【一】

分布式文件系统 SpringBootFastDFSVue.js【一】 一、分布式文件系统1.1.文件系统1.2.什么是分布式文件系统1.3.分布式文件系统的出现1.3.主流的分布式文件系统1.4.分布式文件服务提供商1.4.1.阿里OSS1.4.2.七牛云存储1.4.3.百度云存储 二、fastDFS2.1.fastDSF介绍2.2.为什么要使…

详解CC++内存管理(new和delete)

文章目录 写在前面1. C&C内存分布2. C语言中动态内存管理方式&#xff1a;malloc/calloc/realloc/free3. C内存管理方式&#xff08;语法&#xff09;3.1 new/delete操作内置类型3.2 new和delete操作自定义类型 4. new和delete的实现原理4.1 operator new与operator delete…

【MySQL】学习外键约束处理员工数据

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-g4glZPIY0IKhiTfe {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

STM32—DHT11温湿度传感器

文章目录 一.温湿度原理1.1 时序图 二.代码 一.温湿度原理 1.1 时序图 (1).下图一是DHT11总的时序图。 (2).图二对应图一的左边黑色部分&#xff0c;图三对应图一的绿色部分&#xff0c;图四的左部分图对应图一的红色部分&#xff0c;图四的右部分对应图一的黄色部分。 (3)…

计算机组成原理(1)----主存储器

目录 1.基本半导体元件及原理 2.寻址 1.基本半导体元件及原理 一个主存储器可以分为存储器&#xff0c;MAR&#xff08;地址寄存器&#xff09;和MDR&#xff08;数据寄存器&#xff09;&#xff0c;这三个部件由在时序控制逻辑的控制下工作 其中存储体用来存放二进制数据0和…