4.7.KMP算法(新版)
一.回顾:KMP算法基于朴素模式匹配算法优化而得来的
朴素模式匹配算法核心思想:把主串中所有长度与模式串长度相等的子串与模式串进行对比,直到找到第一个完全匹配的子串为止,如果当前尝试匹配的子串在某一个位置匹配失败,就立即进行下一个子串的匹配,而且是从下一个子串的头部开始一一匹配
例1:
模式串的最后一个字符与主串中第一个和模式串长度相等的子串匹配失败:
模式串与主串中第二个与模式串长度相等的子串比较,开始从2号字符开头的子串进行比较,之所以开始匹配2号字符开头的子串,且从2号字符开始比较,是因为在主串里的字符到底是什么无法得知,所以只能从主串里与模式串长度相等的子串的第一个字符依次往后匹配:
如果以2号字符开头的这个子串在某个字符上与模式串匹配失败,同理,由于主串里的字符未知,因此只能尝试匹配以3号字符开头的子串,并且要从3号字符开始依次往后与模式串进行对比,因为主串里包含的内容不得而知:
之后以此类推找主串中是否有要找的模式串。
换一种思路:
模式串的最后一个字符与主串中第一个和模式串长度相等的子串匹配失败,那么该子串中除了最后一个字符外都与模式串中除了最后一个字符外匹配成功,因此本例中模式串匹配到第6个字符才发现匹配失败,这种情况下就可以从模式串中得知主串中的前几个字符的内容,只有最后一个字符不知道,所以就要利用好此时主串中已知的字符:
根据朴素模式匹配算法的思想,如果当前的子串匹配失败,就要取下一个符合要求的子串与模式串进行对比,此时已经知道主串中前几个字符的信息,因此就会发现模式串的第一个字符就与此时要匹配的子串不匹配,所以当前的子串就没必要继续匹配下去,直接进行第三个符合要求的子串进行与模式串匹配:
现在的子串也是知道前几个字符的信息(本例中可以知道该子串前3个字符为aab),第一个字符可以和模式串第一个字符匹配,第二个字符就与模式串不匹配了,所以这个子串也没有必要继续匹配了:
同理,开始下一个子串的匹配,该子串的前两个字符是已知的,而且前两个字符匹配成功,但该子串里的第三个字符就不得而知了,所以对于现在的这个字符来说,前两个字符匹配成功,而第三个字符是否匹配成功暂时还不知道,因此一开始只需要从第三个字符开始往后检查匹配就可以了:
总结:
如本例中,模式串在与第一个子串进行匹配时,如果发现最后一个字符不匹配,那么就意味着前5个字符已得知,此时主串中以标记2为开头的子串和以标记3为开头的子串就无需匹配了,可以直接对比以标记4为开头的子串,而且在对比以标记4为开头的子串时,只需要从第三个字符开始检查即可,因为前两个元素已经确定和模式串匹配成功,这样就省去了大量的无效匹配:
KMP算法的思想:利用好模式串本身隐含的信息,要确定模式串的某一个元素发生匹配失败时接下来要如何处理,显然最终的结论并不依赖主串的内容,和匹配的主串的哪一个位置并没有关系,只和模式串的内容有关
例2:
主串中第一个符合要求的子串与模式串匹配时,在第5个字符上匹配失败:
此时主串中的前4个元素的具体信息是可以确定的,与模式串一致,从第5个元素开始后面的信息暂时不确定:
第一个子串匹配失败,开始下一个子串的匹配,显然匹配失败:
继续下一个子串的匹配,显然也不行:
继续下一个子串的匹配,已知的字符匹配成功,而未知的字符能否匹配成功暂时不得而知,所以本例中可以从该子串的第二个字符开始检查匹配:
例3:
主串中第一个符合要求的子串与模式串匹配时,在第4个字符上匹配失败:
此时主串中的前3个元素的具体信息是可以确定的,与模式串一致,从第4个元素开始后面的信息暂时不确定:
第一个子串匹配失败,开始下一个子串的匹配,显然匹配失败:
继续下一个子串的匹配,已知的字符匹配成功,而未知的字符能否匹配成功暂时不得而知,所以本例中可以从该子串的第二个字符开始检查匹配:
例4:
主串中第一个符合要求的子串与模式串匹配时,在第3个字符上匹配失败:
此时主串中的前2个元素的具体信息是可以确定的,与模式串一致,从第3个元素开始后面的信息暂时不确定:
第一个子串匹配失败,开始下一个子串的匹配,已知的元素当中匹配失败:
继续下一个子串的匹配,此时已知的元素全部用完:
例5:
主串中第一个符合要求的子串与模式串匹配时,在第2个字符上匹配失败:
此时主串中的第1个元素的具体信息是可以确定的,与模式串一致,从第2个元素开始后面的信息暂时不确定:
继续下一个子串的匹配,此时已知的元素全部用完:
例6:
主串中第一个符合要求的子串与模式串匹配时,在第1个字符上就匹配失败,此时就只能尝试匹配下一个符合要求的子串了:
前面的5个例子中都是主串指针不变,模式串指针变,本例中为了和前5个例子中的处理逻辑类似,可以先让模式串指针为0即指向模式串第一个元素的前一个位置,之后让主串指针和模式串指针都自增即可,这样就可以实现主串指针和模式串指针同时后移:
总结:
整合:
第一个子串与模式串在第6个字符上匹配失败,按照朴素模式匹配算法需要主串指针"回溯",模式串指针变为1:
按照刚才的过程即利用主串指针不"回溯",直接主串指针不变,修改模式串指针即可,省去了无效的对比:
进行此次的匹配,最终全部匹配成功,主串指针也无需"回溯",大大提高了查找效率
通常来说主串要比模式串长很多,因此用主串指针不"回溯"的方法是非常高效的。
例7:
最终会因为模式串指针超出指定范围而停止。
二.利用代码实现主串指针不"回溯"的查找算法:
可以利用数组,该数组记录当某个元素匹配失败时模式串指针应该指向的值,注:当第一个元素就匹配失败时,就要把模式串指针设为0:
-
next数组记录当某个元素匹配失败时模式串指针应该指向的值
-
i为主串指针,j为模式串指针
-
S为主串,T为模式串
-
例如:j为6代表此时匹配到模式串里的第6个字符,如果此时第6个字符匹配失败,那么根据j=next[j]此时j更改为3
-
利用next数组进行匹配(主串指针不"回溯")的代码:形参中S为主串,T为模式串,next数组记录当某个元素匹配失败时模式串指针应该指向的值,函数体中i为主串指针,j为模式串指针,i和j都从1开始即从头部开始匹配,S.length表示主串的长度,T.length表示模式串的长度,S.ch[i]==T.ch[j]表示此时主串的元素等于模式串的元素
三.朴素模式匹配算法 v.s. KMP算法:
KMP算法相比于朴素模式匹配算法多了一个next数组以及对模式串指针为0时的判断,有了next数组就不需要主串指针"回溯",只需要修改模式串的指针即可:
-
主串的长度为n,由于主串指针不"回溯",所以模式匹配过程最坏时间复杂度就是O(n)即把整个主串都走了一遍,最终算整个算法的时间复杂度时只需要相加即可
-
KMP算法最坏时间复杂度为O(m+n)
-
KMP算法在效率上要优于朴素模式匹配算法
四.求next数组(next数组记录当某个元素匹配失败时模式串指针应该指向的值):
注:next数组0索引上不存数据,从1索引开始
-
next数组的长度等于模式串长度加一,因为next数组存储数据的下标要和模式串的下标一一对应,此时模式串下标规定从1开始,而数组下标却从0开始,所以next数组的长度等于模式串长度加一,由上图也可知
-
比如next[1]代表模式串第一个字符,在next数组中next[1]的含义是当模式串的第一个字符发生匹配失败时模式串指针应该指向哪个位置
-
任何模式串都一样,第一个字符不匹配时,只能匹配主串里下一个符合要求的子串,因此,往后余生,next[1]都无脑写0
-
任何模式串都一样,第二个字符不匹配时,应尝试匹配模式串的第一个字符,因此,往后余生,next[2]都无脑写1
例一:
求next[1],若模式串的第一个字符匹配失败,根据之前的分析,此时模式串指针的值赋值为0,然后模式串指针和主串指针同时自增即开始匹配往后的模式串和主串里的子串,所以next[1]为0:
求next[2],若模式串的第二个字符匹配失败,意味着这时无法得知模式串的第二个字符所在的位置对应的主串里的该位置的字符,那么就只能让模式串往后滑动一位,也就是让模式串指针为1即next[2]为1:
求next[3],若模式串的第三个字符匹配失败,此时可以由模式串得知主串里的两个字符(如下图)即分界线左边的两个字符,在分界线的左边的前两个字符,一个一个往后移动进行比对,如果比对成功就进行下一个字符的比对,如果失败直接后移模式串比对。例如本例中先移动一个字符,发现不匹配,然后继续往后移模式串,此时整个模式串就全部移动到分界线的右边了,而在分界线的右边,主串的内容就不得而知了,因此就有必要把此时主串指针所指的元素和模式串指针所指的元素进行比对,因此当模式串第三个字符匹配失败时,可以直接让模式串指针的值为1即next[3]为1:
求next[4],若模式串的第四个字符匹配失败,此时可以在匹配失败的字符左边画一条分界线,主串中这条分界线左边的前三个字符可以确定,而分界线右边的字符就无法确定,接下来需要模式串一步一步往右移动来比对,根据题意,由于无法匹配成功最终模式串会全部移动到分界线右边,而且分界线右边的字符无法确定,所以就有必要把此时主串指针所指的元素和模式串指针所指的元素进行比对,所以当模式串第四个字符匹配失败时,可以让模式串指针的值为1即next[4]为1:
求next[5],若模式串的第五个字符匹配失败,此时可以在匹配失败的字符左边画一条分界线,主串中这条分界线左边的前四个字符可以确定,而分界线右边的字符就无法确定,接下来需要模式串一步一步往右移动来比对,一边移动一边比对,最终当分界线左边只剩下一个字符时开始匹配成功,由于分界线右边的字符未知,所以有必要开始模式串第二个字符的比对,因此当模式串第五个字符匹配失败时,可以让模式串指针的值为2即next[5]为2:
求next[6],若模式串的第六个字符匹配失败,此时可以在匹配失败的字符左边画一条分界线,主串中这条分界线左边的前五个字符可以确定,而分界线右边的字符就无法确定,接下来需要模式串一步一步往右移动来比对,一边移动一边比对,根据题意,由于无法匹配成功模式串最终会全部移动到分界线右边,而且分界线右边的字符无法确定,所以就有必要把此时主串指针所指的元素和模式串指针所指的元素进行比对,所以当模式串第六个字符匹配失败时,可以让模式串指针的值为1即next[6]为1:
到此,求出了字符串google的next数组。
应用例一中通过字符串google求出的next数组:
首先模式串的第六个字符匹配失败,根据求出来的next数组,模式串指针指向1:
此时模式串的第一个字符匹配失败,根据求出来的next数组,模式串指针指向0:
同时模式串指针和主串指针要自增,也就是开始匹配下一个子串:
此时模式串的第五个字符匹配失败,根据求出来的next数组,模式串指针指向2:
如下:
比对后最终匹配成功:
例二:
求next[3],若模式串的第三个字符匹配失败,此时可以在匹配失败的字符左边画一条分界线,主串中这条分界线左边的前两个字符可以确定,而分界线右边的字符就无法确定,接下来需要模式串一步一步往右移动来比对,一边移动一边比对,根据题意,由于无法匹配成功模式串最终会全部移动到分界线右边,而且分界线右边的字符无法确定,所以就有必要把此时主串指针所指的元素和模式串指针所指的元素进行比对,所以当模式串第三个字符匹配失败时,可以让模式串指针的值为1即next[3]为1:
求next[4],若模式串的第四个字符匹配失败,此时可以在匹配失败的字符左边画一条分界线,主串中这条分界线左边的前三个字符可以确定,而分界线右边的字符就无法确定,接下来需要模式串一步一步往右移动来比对,一边移动一边比对,当模式串移动到在分界线左边只剩下一个字符时开始匹配成功,由于分界线右边的字符无法确定,所以有必要开始模式串第二个字符的比对,因此当模式串第四个字符匹配失败时,可以让模式串指针的值为2即next[4]为2:
求next[5],若模式串的第五个字符匹配失败,此时可以在匹配失败的字符左边画一条分界线,主串中这条分界线左边的前四个字符可以确定,而分界线右边的字符就无法确定,接下来需要模式串一步一步往右移动来比对,一边移动一边比对,当模式串移动到在分界线左边剩下两个字符时开始匹配成功,由于分界线右边的字符无法确定,所以有必要开始模式串第三个字符的比对,因此当模式串第五个字符匹配失败时,可以让模式串指针的值为3即next[5]为3:
求next[6],若模式串的第六个字符匹配失败,此时可以在匹配失败的字符左边画一条分界线,主串中这条分界线左边的前五个字符可以确定,而分界线右边的字符就无法确定,接下来需要模式串一步一步往右移动来比对,一边移动一边比对,当模式串移动到在分界线左边剩下三个字符时开始匹配成功,由于分界线右边的字符无法确定,所以有必要开始模式串第四个字符的比对,因此当模式串第六个字符匹配失败时,可以让模式串指针的值为4即next[6]为4:
到此,求出了模式串T的next数组。
五.求next数组的总结:
注:next数组0索引上不存数据,从1索引开始
六.next数组的优化思路:利用之前已求出next数组的模式串T即abaabc
例一:
若此时在第三个字符匹配失败:
根据next数组此时模式串指针应指向1即j为1:
由于第三个字符匹配失败,所以主串指针所指的字符和模式串指针所指的字符是不相等的,既然不相等,又此时模式串指针所指的是模式串的第三个字符a,说明主串指针所指的第三个字符一定不是a,因此当第三个字符匹配失败时,接下来需要让模式串指针指向1,但这一次的匹配一定会失败,因为模式串指针此时所指的字符是第一个字符a,这是已知的,而此时主串指针所指的元素虽然未知,但它一定不是a,第一个字符匹配失败时需要模式串指针指向0,然后模式串指针和主串指针自增:
所以,一开始发现模式串第三个字符和主串第三个字符匹配失败时,又因为模式串里的第一个字符和第三个字符相等,所以模式串里的第一个字符和主串里的第三个字符也一定会匹配失败,因此,一开始发现模式串第三个字符和主串第三个字符匹配失败时就可以直接让模式串指针指向0,因为如果让模式串指针指向1时意味着接下来是让模式串第一个字符和主串第三个字符开始匹配,根据之前的分析,该匹配注定失败,当第一个字符匹配失败时,应该让模式串指针指向0,所以最好的处理方式就是直接让模式串指针指向0(这样就可以跳过多余的模式串第一个字符匹配主串第三个字符):
最终优化后,当第三个字符匹配失败时,直接让模式串指针指向0,然后模式串指针和主串指针自增,意味着跳过了多余的模式串第一个字符匹配主串第三个字符:
例二:
若此时在第五个字符匹配失败:
根据next数组此时模式串指针应指向2即j为2:
由于第五个字符匹配失败,所以主串指针所指的字符和模式串指针所指的字符是不相等的,既然不相等,又此时模式串指针所指的是模式串的第五个字符b,说明主串指针所指的第五个字符一定不是b,因此当第五个字符匹配失败时,接下来需要让模式串指针指向2,但这一次的匹配一定会失败,因为模式串指针此时所指的字符是第二个字符b,这是已知的,而此时主串指针所指的元素虽然未知,但它一定不是b,第二个字符匹配失败时需要模式串指针指向1:
最终优化后,当第五个字符匹配失败时,直接让模式串指针指向1,意味着跳过了多余的模式串第二个字符匹配主串第五个字符:
最终优化后演示:
例三:
若此时在第六个字符匹配失败,可以确定主串第六个字符一定不是c:
根据next数组此时模式串指针应指向3即j为3,模式串第三个字符为a,主串里的第六个字符一定不是c,但是否是a就无法确定了,所以此时就有必要进行匹配判断,因此当六个字符匹配失败时,让模式串指针指向3是有必要的,无需继续优化:
结论:当匹配失败时,判断模式串指针要指向的下一个模式串字符和原本失配的字符是否相等,如果这两个字符不相等,next数组的值保持不变,如果这两个字符相等,此时可以更改next数组的值实现优化
-
KMP算法的进一步优化本质是优化next数组
-
nextval数组其实就是next数组的优化,也可以把nextval数组理解为新的next数组,nextval数组可以命名为next数组
七.求nextval数组:nextval数组其实就是next数组的优化,也可以把nextval数组理解为新的next数组,nextval数组可以命名为next数组
注:nextval数组0索引上不存数据,从1索引开始,nextval数组1索引上的数据固定为0即nextval[1]=0(原理和next数组1索引上的数据固定为0的原理一样)从2索引开始就需要一步一步推导
练习1:
函数解读:
-
j为模式串指针,T.length为模式串的长度,T.ch[j]为模式串T在j索引上的字符
-
一般都是先求出next数组,再求nextval数组
-
j代表模式串指针当前所指的字符,next[j]代表模式串指针应更改为所指向的字符
-
next数组和nextval数组所包含的内容都是一样的即把当前模式串指针的值修改为下一次要指向的值
-
该函数中nextval数组存储的值都是从next数组得出的,也就是说nextval的元素是next[j]
-
如果当前j所指的字符和next[j]所指的字符不相等,那么就让nextval[j]=next[j],意味着nextval数组在j索引上的值等于next数组在j索引上的值。例如上述图片中求nextval[2],此时代表模式串第二个字符匹配失败且j等于2,其中j指向第二个字符即b,next[j](即next[2])等于1即模式串指针应该改为指向模式串第一个字符即a,由于字符a和b不相等,所以nextval[2]等于next[2]即nextval[2]=1
-
如果当前j所指的字符和next[j]所指的字符相等,那么就让nextval[j]=nextval[ next[j] ],nextval[ next[j] ]可以理解为next数组的嵌套,当j指针即模式串指针指向的字符匹配失败时需要指向next[j]所指的字符,根据题意,next[j]所指的字符注定会匹配失败,此时就需要把模式串指针改为next[ next[j] ]即nextval[ next[j] ]。例如上述图片中求nextval[3],此时代表模式串第三个字符匹配失败且j等于3,其中j指向第三个字符即a,next[j](即next[3])等于1即模式串指针应该改为指向模式串第一个字符即a,由于字符a和a相等,所以nextval[3]等于nextval[ next[3] ]即nextval[3]=0,其实不难理解,因为此时模式串第一个字符a和模式串第三个字符a相等,所以当模式串第三个字符匹配失败时,那么模式串第一个字符注定会匹配失败,所以没必要再对比模式串的第一个字符,而是直接考虑模式串第一个字符匹配失败后应该跳到哪个字符进行匹配
练习2:
八.next数组优化前后对比:
next数组未优化前:
模式串指针j指向的第四个字符和主串第四个字符匹配失败:
根据next数组,模式串指针指向3,此时模式串第三个字符和主串第四个字符匹配失败:
根据next数组,模式串指针指向2,此时模式串第二个字符和主串第四个字符匹配失败:
根据next数组,模式串指针指向1,此时模式串第一个字符和主串第四个字符匹配失败:
根据next数组,模式串指针指向0,然后模式串指针和主串指针都自增:
匹配后最终查找成功:
next数组优化后即nextval数组:
模式串指针j指向的第四个字符和主串第四个字符匹配失败:
根据next数组,模式串指针指向0,然后模式串指针和主串指针都自增:
匹配后最终查找成功:
显然省去了很多不必要的匹配过程。
相关文章:

4.7.KMP算法(新版)
一.回顾:KMP算法基于朴素模式匹配算法优化而得来的 朴素模式匹配算法核心思想:把主串中所有长度与模式串长度相等的子串与模式串进行对比,直到找到第一个完全匹配的子串为止,如果当前尝试匹配的子串在某一个位置匹配失败…...

iOS AES/CBC/CTR加解密以及AES-CMAC
感觉iOS自带的CryptoKit不好用,有个第三方库CryptoSwift还不错,好巧不巧,清理过Xcode缓存后死活下载不下来,当然也可以自己编译个Framework,但是偏偏不想用第三方库了,于是研究了一下,自带的Com…...

错误报告:WebSocket 设备连接断开处理问题
错误报告:WebSocket 设备连接断开处理问题 项目背景 设备通过自启动的客户端连接到服务器,服务器将设备的 mac_address 和设备信息存入 Redis。前端通过 Redis 接口查看设备信息并展示。 问题描述 设备连接到服务器后,前端无法立即看到设…...

点云配准网络
【论文笔记】点云配准网络 PCRNet: Point Cloud Registration Network using PointNet Encoding 2019_pcr-net-CSDN博客 【点云配准】【深度学习】Windows11下PCRNet代码Pytorch实现与源码讲解-CSDN博客 【点云配准】【深度学习】Windows11下GCNet代码Pytorch实现与源码讲解_…...

黑马Redis详细笔记(实战篇---短信登录)
目录 一.短信登录 1.1 导入项目 1.2 Session 实现短信登录 1.3 集群的 Session 共享问题 1.4 基于 Redis 实现共享 Session 登录 一.短信登录 1.1 导入项目 数据库准备 -- 创建用户表 CREATE TABLE user (id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT 用户ID,phone …...

51单片机俄罗斯方块整行消除函数
/************************************************************************************************************** * 名称:flash * 功能:行清除动画 * 参数:NULL * 返回:NULL * 备注: * 采用非阻塞延时࿰…...

Vue 3 30天精进之旅:Day 21 - 项目实践:打造功能完备的Todo应用
前言 经过前20天的学习,我们已经掌握了Vue 3的核心概念、组合式API、路由、状态管理等关键技术。今天将通过一个完整的项目实践——Todo应用,将所学知识融会贯通。我们将为Todo应用添加编辑、删除、过滤等进阶功能,并优化代码结构。 一、项目…...

32单片机学习记录1之GPIO
32单片机学习记录1之GPIO 前置 GPIO口在单片机中扮演着什么角色? 在单片机中,GPIO口(General Purpose Input/Output) 是一种通用输入/输出接口,扮演着连接单片机与外部设备的桥梁角色。具体来说,它在单片…...

AI 编程助手 Cline
Cline 是一款集成于 Visual Studio Code(VS Code)的 AI 编程助手,旨在提升开发者的编程效率和代码质量。 主要功能: 代码生成与补全:Cline 能根据开发者的输入,自动生成代码片段或完整的函数,减…...

YOLOv11-ultralytics-8.3.67部分代码阅读笔记-patches.py
patches.py ultralytics\utils\patches.py 目录 patches.py 1.所需的库和模块 2.def imread(filename: str, flags: int cv2.IMREAD_COLOR): 3.def imwrite(filename: str, img: np.ndarray, paramsNone): 4.def imshow(winname: str, mat: np.ndarray): 5.PyTorch…...

R语言LCMM多维度潜在类别模型流行病学研究:LCA、MM方法分析纵向数据
全文代码数据:https://tecdat.cn/?p39710 在数据分析领域,当我们面对一组数据时,通常会有已知的分组情况,比如不同的治疗组、性别组或种族组等(点击文末“阅读原文”获取完整代码数据)。 然而,…...

2025 年前端开发现状分析:卷疯了还是卷麻了?
一、前端现状:框架狂飙,开发者崩溃 如果你是个前端开发者,那么你大概率经历过这些场景: 早上打开 CSDN(或者掘金,随便),发现又有新框架发布了,名字可能是 VueXNext.js 之…...

RDK新一代模型转换可视化工具!!!
作者:SkyXZ CSDN:SkyXZ~-CSDN博客 博客园:SkyXZ - 博客园 之前在使用的RDK X3的时候,吴诺老师wunuo发布了新一代量化转换工具链使用教程,这个工具真的非常的方便,能非常快速的完成X3上模型的量化…...

JVM春招快速学习指南
1.说在前面 在Java相关岗位的春/秋招面试过程中,JVM的学习是必不可少的。本文主要是通过《深入理解Java虚拟机》第三版来介绍JVM的学习路线和方法,并对没有过JVM基础的给出阅读和学习建议,尽可能更加快速高效的进行JVM的学习与秋招面试的备战…...

C#中的序列化和反序列化
序列化是指将对象转换为可存储或传输的格式,例如将对象转换为JSON字符串或字节流。反序列化则是将存储或传输的数据转换回对象的过程。这两个过程在数据持久化、数据交换以及与外部系统的通信中非常常见 把对象转换成josn字符串格式 这个过程就是序列化 josn字符…...

xcode常见设置
1、如何使用cmake构建archs为$(ARCHS_STANDARD)的xcode项目 在cmake中使用如下指令 set(CMAKE_OSX_ARCHITECTURES "$(ARCHS_STANDARD)") cmake - nomadli的博客 | nomadli Blog...

PG高可用学习@2
目录标题 一、Patroni 支持在同步复制下备库故障时自动降级为异步复制?参考依据1. PostgreSQL 官方文档2. Patroni 官方文档3. 高可用和容错设计原则 二、patroni 是如何检测备库故障的?1. 心跳机制2. 监控数据库进程状态3. 查询系统视图4. 复制延迟监测5. 网络连接…...

centos 8和centos 9 stream x64的区别
以下是 CentOS 8 与 CentOS Stream 9 的主要区别,从技术架构、更新策略到适用场景等维度进行对比: AI产品独立开发实战营 联系我了解 1. 定位与更新策略 特性CentOS 8CentOS Stream 9定位原为 RHEL 8 的免费稳定复刻版RHEL 9 的上游开发分支ÿ…...

C++基础学习记录—类
1、面向对象的三大特征:封装、继承、多态 2、类和对象 2.1、类的概念 类:类是一个抽象的概念,用于描述同一类对象的特点。 对象:根据类的概念所创造的实体。 类中包含属性和行为 属性:描述类的数据,一…...

云原生时代的后端开发:架构、工具与最佳实践
随着云计算的迅猛发展,云原生(Cloud Native)逐渐成为后端开发的主流趋势。云原生后端不仅能够提高应用的灵活性和可扩展性,还能显著优化开发和运维流程。本文将围绕云原生后端的关键概念、当前热门技术及最佳实践,帮助…...

ARM Cortex-M3/M4 权威指南 笔记【一】技术综述
一、Cortex-M3/M4 处理器的一般信息 1.1 处理器类型 ARM Cortex-M 为 32 位 RISC(精简指令集)处理器,其具有: 32位寄存器32位内部数据通路32位总线接口 除了 32 位数据,Cortex-M 处理器(以及其他任何 A…...

12.项目结构
后端结构 ruoyi-admin 项目启动的入口 提供了两种启动方式 1.RuoYiApplication基于springboot,内置tomcat,直接运行。 2.RuoYiServletInitializer将springboot项目打成一个war包,用外置的servlet容器来运行。 通用功能的controller 后台登录相关的、权限控制相关的、数据字…...

保研考研机试攻略:python笔记(4)
🐨🐨🐨15各类查找 🐼🐼二分法 在我们写程序之前,我们要定义好边界,主要是考虑区间边界的闭开问题。 🐶1、左闭右闭 # 左闭右闭 def search(li, target): h = len(li) - 1l = 0#因为都是闭区间,h和l都可以取到并且相等while h >= l:mid = l + (h - l) // 2…...

高阶C语言|枚举与联合
💬 欢迎讨论:在阅读过程中有任何疑问,欢迎在评论区留言,我们一起交流学习! 👍 点赞、收藏与分享:如果你觉得这篇文章对你有帮助,记得点赞、收藏,并分享给更多对C语言感兴…...

【天梯赛】L1-104 九宫格(C++)
易忽略的错误:开始习惯性地看到n就以为是n*n数组了,实际上应该是9*9的固定大小数组,查了半天没查出来 题面 L1-104 九宫格 - 团体程序设计天梯赛-练习集 代码实现 #include<bits/stdc.h> using namespace std; //易错:开…...

现代C++多线程基础 -忆苦思甜pthread_mutex
c 老古董 文章目录 c 老古董pthread_mutex概念常用apipthread_mutex_initpthread_mutex_lockpthread_mutex_trylockpthread_mutex_unlockpthread_mutex_destroy 案例 pthread_mutex 概念 互斥锁 mutex是一种简单的加锁的方法来控制对共享资源的访问,mutex只有两种…...

soular基础教程-使用指南
soular是TikLab DevOps工具链的统一帐号中心,今天来介绍如何使用 soular 配置你的组织、工作台,快速入门上手。  1. 账号管理 可以对账号信息进行多方面管理,包括分配不同的部门、用户组等,从而确保账号权限和职责…...

网络安全网格架构(CSMA) 网络安全框架csf
CSRF:Cross Site Request Forgy(跨站请求伪造) 用户打开另外一个网站,可以对本网站进行操作或攻击。容易产生传播蠕虫。 CSRF攻击原理: 1、用户先登录A网站 2、A网站确认身份返回用户信息 3、B网站冒充用户信息而不是直接获取用…...

基于DeepSeek API和VSCode的自动化网页生成流程
1.创建API key 访问官网DeepSeek ,点击API开放平台。 在开放平台界面左侧点击API keys,进入API keys管理界面,点击创建API key按钮创建API key,名称自定义。 2.下载并安装配置编辑器VSCode 官网Visual Studio Code - Code Editing…...

【AI时代】Page Assist - 本地 AI 模型的 Web UI (谷歌浏览器) 本地DeepSeek启用联网功能
Page Assist - 本地 AI 模型的 Web UI 一、部署本地模型 参考教程:https://blog.csdn.net/Bjxhub/article/details/145536134二、安装插件 Page Assist 浏览器谷歌商店搜索 Page Assist ,安装该插件。 注意:需要一点科学的魔法。 三、使用…...