一篇带你速通差分算法(C/C++)

news2024/9/19 7:42:16

个人主页:摆烂小白敲代码

创作领域:算法、C/C++

持续更新算法领域的文章,让博主在您的算法之路上祝您一臂之力

欢迎各位大佬莅临我的博客,您的关注、点赞、收藏、评论是我持续创作最大的动力

差分算法是一种在计算机科学中常用的算法,特别是在处理序列数据时,它可以帮助我们快速计算出序列中相邻元素的差值。时间复杂度可以达到O(1),在C++中实现差分算法不仅可以提高程序的效率,还可以简化代码的复杂度。本文将详细介绍差分算法的原理、C++实现方法以及算法例题。 

算法原理

上一篇博客一篇带你速通前缀和算法(C/C++)-CSDN博客我们介绍了前缀和算法,这一篇文章就与前缀和算法相反为差分算法。

一维差分:

差分算法的核心思想是利用已有的数据序列,通过计算相邻元素之间的差值来生成一个新的序列。对于一个给定的序列 a=[a1​,a2​,...,an​],其差分序列 d 可以表示为:d[i]=a[i]−a[i-1]。差分数组长度一般为原定序列长度+1,即:len=n+1。其中,d[0] 通常被定义为0,或者根据具体应用场景进行特殊处理。我们设原数组序列为a=[3,1,5,4,2],下标从1开始,那么差分数组可以由d[i]=a[i]−a[i-1]求得,如下图所示。

一维差分在修改区间时效率非常高,时间复杂度可以达到 O(1),我们通过对差分数组的修改以达到修改原数组的目的,那么如何修改差分数组,比如在数组a的[l,r]区间上的数统一+c,转化为差分数组为d[l]+c,d[r+1]-c,这样我们再利用前缀和还原便可以得到原数组修改后的值。在还原时,只需要将前i位差分数组相加便可以得到原数组,比如还原第三位,a[3]=d[1]+d[2]+d[3],便可以还原其值,其还原的第n+1位一定是0。

我们设原数组序列为 a=[3,1,5,4,2],设d为差分数组,在[2,4]区间上的值统一+2,下面我们将模拟实现。

初始化:

差分实现: 

我们需要在[2,4]区间上的值统一+2,那么转换为差分数组d[l]+c,d[r+1]-c==d[2]+2,d[4+1]-2。我们代入到过程实现一下。

 原数组序列为 a=[3,1,5,4,2],在[2,4]区间上的值统一+2,我们将得到a=[3,3,7,6,2],与差分还原的来是一样的。


二维差分:

前面我们讲述的是一维差分,其数组为一维的,其模型可以抽象为线性的。那么有些时候需要我们使用二维差分,当题目出现矩阵时,说明就涉及到了二维差分,其模型可以抽象为矩阵,二维差分稍微比一维差分难一点,主要是在处理区间更新时。我们设d[i][j]为(1,1)点到(i,j)点的差分子矩阵(1<=x<=i,1<=y<=j),此时我们设a[i][j]=Σd[i][j](1<=x<=i,1<=y<=j),即a[i][j]=差分矩阵的和。

构造差分矩阵:

当我们需要构造差分数组实现修改区间的值时,此时的递推关系式不再是跟一维差分相同,由于是二维的,所以转化为在一个矩阵上+c,在一个矩阵上-c,那么如何确定这两个矩阵。假设我们在(x1,y1)->(x2,y2)这个矩阵统一加C,那么转化为差分矩阵的操作为

d[x1][y1]+C
d[x1][y2+1]-C
d[x2+1][y1]-C
d[x2+1][y2+1]+C

//上面操作等价于
for(int i=x1;i<=x2;i++)
  for(int j=y1;j<=y2;j++)
    a[i][j]+=C;

 在构造差分矩阵时,可以先初始化一个差分矩阵都为0,把自己的点,(x,y)->(x,y)插入到差分矩阵中,代码如下

void insert(int x1, int y1, int x2, int y2, int c)//构造差分矩阵
{
    b[x1][y1] += c;
    b[x2 + 1][y1] -= c;
    b[x1][y2 +1] -= c;
    b[x2 +1][y2+1] +=c;
}
构造差分矩阵解释 :

d[x1][y1]+C相当于原矩阵A矩阵(黄色)每个值都+C

d[x2+1][y2+1]+C相当于整个矩阵A+B+C+D矩阵每个值都+C

此时A矩阵+2C,B矩阵+C,C矩阵+C,D矩阵+C,我们再设法把不需要的减掉。

d[x1][y2+1]-C相当于A+B矩阵(黄色+绿色)都-C

此时A矩阵+C,B矩阵+0,C矩阵+C,D矩阵+C,我们再设法把不需要的减掉。

d[x2+1][y1]-C相当于A+C矩阵(黄色+蓝色)都-C

此时A矩阵+0,B矩阵+0,C矩阵+0,D矩阵+C,达到了我们所需要的(x1,y1)到(x2,y2)加C的目的。

最后就是还原其值,利用前缀和的思想,如上图所示,要求(1,1)->(x2,y2)的值,那么可以转化为矩阵(1,1)->(x2,y2-1)与(1,1)->(x2-1,y2)的和减去(1,1)->(x2-1,y2-1)矩阵的值,最后再加上自身值d[x2][y2]。其递归式为d[i][j] += d[i - 1][j] + d[i][j - 1] - d[i - 1][j - 1]。

for (int i = 1; i <= n; i++)//二维前缀和还原
    {
        for (int j = 1; j <= m; j++)
        {
            d[i][j] += d[i - 1][j] + d[i][j - 1] - d[i - 1][j - 1];
        }
    }
代码实现:
#include<iostream>
using namespace std;

const int N =1010;

int a[N][N],d[N][N];
int n,q;

void insert(int x1, int y1, int x2, int y2, int c)
{
    d[x1][y1] += c;
    d[x2 + 1][y1] -= c;
    d[x1][y2 +1] -= c;
    d[x2 +1][y2+1] +=c;
}

int main()
{
    scanf("%d%d", &n,&q);
    for(int i = 1;i <= n; i++){
    	for(int j = 1;j <= n; j++){
    		cin >> a[i][j];
    		insert(i, j, i, j, a[i][j]);
		}
	}
    while( q-- )
    {
        int x1, x2, y1, y2,c;
        cin >> x1 >> y1>> x2 >> y2 >> c ;
        insert(x1 ,y1, x2, y2, c);//修改区间
    }
    
    //求前缀和
    for(int i = 1; i<=n; i++){
    	for(int j = 1; j<=n; j++){
        	d[i][j] += d[i][j-1] + d[i-1][j] - d[i-1][j-1];
        printf("%d ", d[i][j]);
		}
		cout<<endl;
	}
    return 0;
}

算法例题 

AcWing 4262. 空调

Farmer John 的 N 头奶牛对他们牛棚的室温非常挑剔。

有些奶牛喜欢温度低一些,而有些奶牛则喜欢温度高一些。

Farmer John 的牛棚包含一排 N 个牛栏,编号为 1…N,每个牛栏里有一头牛。

第 i 头奶牛希望她的牛栏中的温度是 pi,而现在她的牛栏中的温度是 ti。

为了确保每头奶牛都感到舒适,Farmer John 安装了一个新的空调系统。

该系统进行控制的方式非常有趣,他可以向系统发送命令,告诉它将一组连续的牛栏内的温度升高或降低 1 个单位——例如「将牛栏 5…8 的温度升高 1 个单位」。

一组连续的牛栏最短可以仅包含一个牛栏。

请帮助 Farmer John 求出他需要向新的空调系统发送的命令的最小数量,使得每头奶牛的牛栏都处于其中的奶牛的理想温度。

输入格式

输入的第一行包含 N。

下一行包含 N 个非负整数 p1…pN,用空格分隔。

最后一行包含 N 个非负整数 t1…tN。

输出格式

输出一个整数,为 Farmer John 需要使用的最小指令数量。

数据范围

1≤N≤10^5
0≤pi,ti≤10000

输入样例:

5
1 5 3 3 4
1 2 2 2 1

输出样例:

5

样例解释

一组最优的 Farmer John 可以使用的指令如下:

初始温度     :1 2 2 2 1
升高牛棚 2..5:1 3 3 3 2
升高牛棚 2..5:1 4 4 4 3
升高牛棚 2..5:1 5 5 5 4
降低牛棚 3..4:1 5 4 4 4
降低牛棚 3..4:1 5 3 3 4

解题思路:

一个数组转化到另一个数组,我们可以考虑利用差分,快速解决,在一个区间上所有的数加上一个数k或者减去一个数k,我们可以等价转化为差分数组在区间两端一个+k一个-k。题目中起始数组到目标数组,我们可以把这两个数组做差值,然后差值数组变为差分数组,等价为转化到全零数组。差分数组每个值加和必为0(此题必有解),因为我们每次只相当于在差分数组两个值上加减,一个加一个减,要到达0数组,那肯定小于0的每次+1,直到为0,大于0的每次-1,直到为0。

p数组:   1 5 3 3 4
t数组:   1 2 2 2 1
差值数组:0 3 1 1 3
差分数组:0 3 -2 0 2 -3
第一次:  0 2 -1 0 2 -3
第二次:  0 1  0 0 2 -3
第三次:  0 0  0 0 2 -2
第四次:  0 0  0 0 1 -1
第五次:  0 0  0 0 0  0
所以只需要统计大于0或者小于0的值即可

AC代码:
#include<iostream>
using namespace std;
const int N=1e5+5;
int n,ans;
int p[N],t[N];//p数组既作为p数组又作为差分数组
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>p[i];
	}
	for(int i=1;i<=n;i++){
		cin>>t[i];
		p[i]-=t[i];
	}
	//差分p[i]=p[i]-p[i-1],差分数组边界p[1]=p[1],p[n+1]=-p[n]
	for(int i=n+1;i>=1;i--){//因为i要先于i-1更新,所以逆序遍历
		p[i]-=p[i-1];
	}
	for(int i=1;i<=n+1;i++){//只要遍历大于0或者小于零的p[i]累加即可
		if(p[i]>0){
			ans+=p[i];
		}
	}
	cout<<ans<<endl;
	return 0;
}

AcWing 4862. 浇花

某公司养有观赏花,这些花十分娇贵,每天都需要且仅需要浇水一次。

如果某一天没给花浇水或者给花浇水超过一次,花就会在那一天死亡。

公司即将迎来 n 天假期,编号 1∼n。

为了让花能够活过整个假期,公司领导安排了 m 个人(编号 1∼m)来公司浇花,其中第 i 个人在第 [ai,bi] 天每天来公司浇一次花。

领导是按照时间顺序安排的浇花任务,保证了对于 1≤i≤m−1,均满足:bi≤ai+1。

给定领导的具体安排,请你判断,花能否活过整个假期,如果不能,请你输出它是在第几天死的,以及那一天的具体浇水次数。

输入格式

第一行包含两个整数 n,m。

接下来 m 行,每行包含两个整数 ai,bi。

输出格式

输出一行结果。

如果花能活过整个假期,则输出 OK

如果花不能活过整个假期,则输出两个整数 x,y,表示花是在第 x 天死的,这一天花被浇了 y 次水。

数据范围

前 4 个测试点满足 1≤n,m≤10。
所有测试点满足 1≤n,m≤10^5,1≤ai≤bi≤n。

输入样例1:

10 5
1 2
3 3
4 6
7 7
8 10

输出样例1:

OK

输入样例2:

10 5
1 2
2 3
4 5
7 8
9 10

输出样例2:

2 2

输入样例3:

10 5
1 2
3 3
5 7
7 7
7 10

输出样例3:

4 0

解题思路:

这道题其实一眼看上去是区间合并问题,这里我们讲解的差分算法,那么我们就用差分解决此题。员工在一个区间内浇水那么就可以视为区间修改,可以构造差分数组快速解决,这道题还一个条件就是花不能多浇水,这个实现也可以在差分数组之中,我们可以利用前缀和还原差分数组得到此朵花被浇了几次水,进而判断此花是否存活。


AC代码:
#include<iostream>

using namespace std;
const int N = 1e5 + 5;

int n,m;
int b[N];

int main(){
    cin >> n >> m;
    while(m--){
        int l,r;
        cin >> l >> r;
        b[l]++;//构造差分数组
        b[r + 1]--;
    }
    for(int i = 1;i <= n;i++){
        b[i] = b[i] + b[i - 1];//前缀和还原
        if(b[i] > 1 || b[i] < 1) {//超过一次浇水或者一次也没有浇水
            cout << i << ' ' << b[i] << endl;
            return 0;
        }
    }
    cout << "OK" << endl;
    return 0;
}

AcWing 503. 借教室

在大学期间,经常需要租借教室。

大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室。

教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样。 

面对海量租借教室的信息,我们自然希望编程解决这个问题。

我们需要处理接下来 n 天的借教室信息,其中第 i 天学校有 ri 个教室可供租借。

共有 m 份订单,每份订单用三个正整数描述,分别为 dj,sj,tj,表示某租借者需要从第 sj 天到第 tj 天租借教室(包括第 sj 天和第 tj 天),每天需要租借 dj 个教室。 

我们假定,租借者对教室的大小、地点没有要求。

即对于每份订单,我们只需要每天提供 dj 个教室,而它们具体是哪些教室,每天是否是相同的教室则不用考虑。 

借教室的原则是先到先得,也就是说我们要按照订单的先后顺序依次为每份订单分配教室。

如果在分配的过程中遇到一份订单无法完全满足,则需要停止教室的分配,通知当前申请人修改订单。

这里的无法满足指从第 sj 天到第 tj 天中有至少一天剩余的教室数量不足 dj 个。 

现在我们需要知道,是否会有订单无法完全满足。

如果有,需要通知哪一个申请人修改订单。

输入格式

第一行包含两个正整数 n,m,表示天数和订单的数量。 

第二行包含 n 个正整数,其中第 i 个数为 ri,表示第 i 天可用于租借的教室数量。 

接下来有 m 行,每行包含三个正整数 dj,sj,tj,表示租借的数量,租借开始、结束分别在第几天。 

每行相邻的两个数之间均用一个空格隔开。

天数与订单均用从 1 开始的整数编号。

输出格式

如果所有订单均可满足,则输出只有一行,包含一个整数 0。

否则(订单无法完全满足)输出两行,第一行输出一个负整数 −1,第二行输出需要修改订单的申请人编号。

数据范围

1≤n,m≤10^6
0≤ri,dj≤10^9
1≤sj≤tj≤n

输入样例:

4 3
2 5 4 3
2 1 3
3 2 4
4 2 4

输出样例:

-1
2

解题思路:

此题可用差分+二分或者线段树来解,由于博主能力限制这里会由易懂的差分+二分来讲解。这道题第一感觉应该就是差分了吧,修改区间的值,用差分效率更高一点。我们可以把申请人的需要转化成差分数组,利用前缀和还原,判断i个教室是否满足。如果我们只依靠差分是解决不了此题的,只利用差分时间复杂度为O(nm),大约10^12,肯定会超时,那么我们可以考虑把内层循环利用二分优化掉,具体咋优化呢,我们有了一个申请人编号的差分数组,从第一位申请单到最后一个申请单,越在前面的越容易借到教室,说明教室剩余够多,越到后面剩余可借教室会减少,因为会被前面的申请借去,那就说明第一个不满足的编号越往后概率越高,这样是不是感觉像是一个有序的序列,从头到尾,能满足的概率是由大到小的。那么我们利用二分去查到最后一个能满足的订单,+1即为不能满足的订单,上代码。


AC代码:
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const int N=1e6+5;
int n,m;
LL r[N],d[N],s[N],t[N],c[N];
bool cheak(int mid){//判断第mid个申请是否可以满足
	memset(c,0,sizeof(c));//每次都会有判断,防止上次的数据影响本次的判断
	for(int i=1;i<=mid;i++){//采用申请人由0到差分数组,所以直接差分操作即可
		c[s[i]]+=d[i];
		c[t[i]+1]-=d[i];
	}
	int ans=0;
	for(int i=1;i<=n;i++){//求前缀和,即还原数组
		c[i]+=c[i-1];
		if(c[i]>r[i]){//如果需要的教室大于所能提供的教室,则返回false
			return false;
		}
	}
	return true;
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>r[i];
	}
	for(int i=1;i<=m;i++){
		cin>>d[i]>>s[i]>>t[i];
	}
	int l=0,r=m;
	while(l<r){//实行二分查找最大能满足的申请人编号
		int mid=l+r+1>>1;//向上取整
		if(cheak(mid))l=mid;
		else r=mid-1;
	}
	if(r==m){//如果最大满足的编号等于m,说明所有订单均可满足
		cout<<0<<endl;
	}else{
		cout<<-1<<endl<<r+1<<endl;//前面定义的为能满足的最大编号,r+1即为第一个不能满足的编号
	}
	return 0;
}

由此篇可见差分还是比较重要的,区间修改算法的效率也是非常高的,在算法竞赛中比较重要,希望对大家有所帮助,文章有错误的地方,恳请各位大佬指出。执笔至此,感触彼多,全文将至,落笔为终,感谢大家的支持。 

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

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

相关文章

C# 通过拖控件移动窗体

目录 引言一、通过控件事件移动窗体1、创建窗体界面2、添加控件事件3、添加代码 二、通过windowsAPI移动窗体1、 构建窗体和添加事件2、代码展示 引言 在C#Form窗体设计中&#xff0c;如果我们不需要使用默认边框设计自己个性化的窗体&#xff08;FromBorderStylenone时&#…

YOLOv8改进 | 模块缝合 | C2f 融合RFCAConv增强感受野空间特征 【二次融合 小白必备】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录 &#xff1a;《YOLOv8改进有效…

《师兄啊师兄年番2》震撼发布,玄机科技再铸国漫巅峰!

随着秋风送爽&#xff0c;9月6日的优酷动漫发布会无疑为所有动漫爱好者带来了一场视觉与心灵的双重盛宴。其中最引人瞩目的&#xff0c;莫过于《师兄啊师兄年番2》携其全新海报的惊艳亮相&#xff0c;不仅预示着这部备受期待的国漫巨制即将开启全新篇章&#xff0c;更以其独特的…

SpringBoot3.x+MyBatisPlus+druid多数据源配置

1 引言 本章主要介绍SpringBoot3.x多数据源配置&#xff0c;以及在此基础上配置分页拦截&#xff0c;自动填充功等功能&#xff0c;源码链接在文章最后。下面列出几个重要文件进行介绍。 2 项目结构 整体项目结构如下&#xff0c;主要介绍配置文件和配置类。 3 主要代码 …

IstoreOS内网域名解析 修改网页端口

设置了自定义DNS&#xff0c;解析到Istore的IP&#xff0c;安装了1Panel&#xff0c;想用1Panel做域名解析&#xff0c;但是需要80和443端口。 这俩端口被IstoreOS占用了&#xff0c;下面修改 修改网页端口 https://github.com/istoreos/istoreos/issues/47 opkg update opkg…

【每日刷题】Day112

【每日刷题】Day112 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 1137. 第 N 个泰波那契数 - 力扣&#xff08;LeetCode&#xff09; 2. 面试题 08.01. 三步问题 - …

Web

关于Web Web是基于HTTP协议进行交互的应用网络Web就是通过使用浏览器/APP访问的各种资源 一个请求对应一个响应 eg. 淘宝网 输入一个url&#xff0c;就会返回一个页面 简单的网站开发 简单代码 package mainimport ("fmt""net/http" )/*http.ResponseWr…

麒麟系统安装GPU驱动

1.nvidia 1.1显卡驱动 本机显卡型号:nvidia rtx 3090 1.1.1下载驱动 打开 https://www.nvidia.cn/geforce/drivers/ 也可以直接使用下面这个地址下载 https://www.nvidia.com/download/driverResults.aspx/205464/en-us/ 1.1.3安装驱动 右击&#xff0c;为run文件添加可…

【Sceneform-EQR】通过sceneform-eqr实现一个视频播放器(使用安卓MediaPlayer实现视频播放)

在前一篇文档中介绍了如何在AR\三维场景创建几种背景 【Sceneform-EQR】scenefrom-eqr中的几种背景实现(不仅用于AR、三维场景&#xff0c;在图片、视频播放器中也适用) 本文将侧重介绍如何使用安卓MediaPlayer实现视频播放。 ↓↓↓↓↓↓↓↓↓↓↓↓ 以下正文 ↓↓↓↓↓↓…

OFDM信号PARP的CCDF图

文章目录 引言代码代码疑难解答参考文献 引言 本书主要参考了文献1&#xff0c;但实际上该书中符号和表述的错误非常多&#xff08;只能说棒子是这样的&#xff09;&#xff1b;同时因为发表时间的关系&#xff0c;很多MATLAB代码进行了更新&#xff0c;原书提供的代码已经无法…

溜狗牵绳行为检测-目标检测数据集(包括VOC格式、YOLO格式)

溜狗牵绳行为检测-目标检测数据集&#xff08;包括VOC格式、YOLO格式&#xff09; 数据集&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1CwLEAKcdlh9hbcBNh_Awdw?pwdiu6b 提取码&#xff1a;iu6b数据集信息介绍&#xff1a; 共有 1980 张图像和一一对应的标注文件…

超声波清洗机哪个品牌比较好一点的?清洁力强的超声波清洗机品牌

随着生活水平的不断提升和幸福感的增强&#xff0c;珠宝、饰品和眼镜等物品已成为许多家庭的常备之物。然而&#xff0c;这些贵重细小的物件易于积聚微尘与隐形细菌&#xff0c;长此以往可能悄悄影响家人的健康&#xff0c;毕竟细菌是肉眼难以察觉的隐患。超声波清洗机应运而生…

域取证的日志分析

目录 介绍步骤横向移动行为分析 介绍 1、evtx文件是微软从 Windows NT 6.0(Windows Vista 和 Server 2008) 开始采用的一种全新的日志文件格式。在此之前的格式是 evt 。evtx由Windows事件查看器创建&#xff0c;包含Windows记录的事件列表&#xff0c;以专有的二进制XML格式保…

Kubernetes 之 kubelet 与 CRI、CNI 的交互过程

序言 当一个新的 Pod 被提交创建之后&#xff0c;Kubelet、CRI、CNI 这三个组件之间进行了哪些交互&#xff1f; Kubelet -> CRI -> CNI 如上图所示&#xff1a; Kubelet 从 kube-api-server 处监听到有新的 pod 被调度到了自己的节点且需要创建。Kubelet 创建 sandbo…

以太网--TCP/IP协议(二)

上文中讲述了IP协议&#xff0c;本文主要来讲一下TCP协议。 TCP协议 &#xff08;1&#xff09;端到端通信 直接把源主机应用程序产生的数据传输到目的主机使用这 些数据的应用程序中&#xff0c;就是端到端通信。 &#xff08;2&#xff09;传输层端口 公认端口&#xff0…

Feign入门讲解

1.引入 之前在讲解服务之间的远程调用的时候都是用RestTemplate来发送HTTP请求&#xff0c;但这种方式显得比较冗余&#xff0c;不方便维护&#xff0c;所以现在使用Feign来代替这种方式 Feign是一个声明式HTTP客户端&#xff0c;专门用来发送HTTP请求 2.快速入门 2.1.引入依赖…

万向轮[随动轮]介绍--偏心距

万向轮[随动轮]介绍 1 概述1.1 偏心距定义1.2 偏心距对回旋性能、力矩和寿命的影响1.3 车轮类型分类1.4 轮子特性要求【耐磨、减震、高载重、保护地面不留痕迹及抗静电】1.5 材质【橡胶、聚氨酯、尼龙、金属、酚醛树脂、MC尼龙】1.6 胎面纹路【咬花纹、人字纹、平面、咬花纹人字…

【Linux】读者写者问题与读写锁

终此一生&#xff0c;只有两种办法&#xff1a; 要么梦见生活&#xff0c;要么落实生活。 --- 勒内・夏尔 --- 读写锁和自旋锁 1 读者写者问题2 读写锁3 读写锁的两大特性 1 读者写者问题 读者写者是一种生产消费模型&#xff0c;所以就满足"321"原则&#xff1a…

Node.js和vue3实现GitHub OAuth第三方登录

Node.js和vue3实现GitHub OAuth第三方登录 前言 第三方登入太常见了&#xff0c;微信&#xff0c;微博&#xff0c;QQ…总有一个你用过。 在开发中&#xff0c;我们希望用户可以通过GitHub账号登录我们的网站&#xff0c;这样用户就不需要注册账号&#xff0c;直接通过GitHu…

mysql树形结构返回是否叶子节点

我们界面上展示树形结构的时候往往会用到懒加载&#xff0c;做懒加载需要知道哪个节点是叶子节点&#xff0c;这样叶子节点就不需要继续往下加载了&#xff0c;这种需求可以通过sql实现 先来看下表结构 方式一,通过sql语句直接获取leaf 什么是叶子节点&#xff1f;就是没有哪…