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)逐渐成为后端开发的主流趋势。云原生后端不仅能够提高应用的灵活性和可扩展性,还能显著优化开发和运维流程。本文将围绕云原生后端的关键概念、当前热门技术及最佳实践,帮助…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...

超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...

力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

Linux部署私有文件管理系统MinIO
最近需要用到一个文件管理服务,但是又不想花钱,所以就想着自己搭建一个,刚好我们用的一个开源框架已经集成了MinIO,所以就选了这个 我这边对文件服务性能要求不是太高,单机版就可以 安装非常简单,几个命令就…...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...