精华内容
下载资源
问答
  • 大多数据结构课本中,串涉及的内容即串的模式匹配,需要掌握的是朴素算法、KMP算法及next值的求法。在考研备考中,参考严奶奶的教材,我也是在关于求next值的算法中卡了一下午时间,感觉挺有意思的,把一些思考的...

    大多数据结构课本中,串涉及的内容即串的模式匹配,需要掌握的是朴素算法、KMP算法及next值的求法。在考研备考中,参考严奶奶的教材,我也是在关于求next值的算法中卡了一下午时间,感觉挺有意思的,把一些思考的结果整理出来,与大家一起探讨。

    本文的逻辑顺序为
    1、最基本的朴素算法
    2、优化的KMP算法
    3、应算法需要定义的next值
    4、手动写出较短串的next值的方法
    5、最难理解的、足足有5行的代码的求next值的算法
    所有铺垫为了最后的第5点,我觉得以这个逻辑下来,由果索因还是相对好理解的,下面写的很通俗,略显不专业…

    一、问题描述

    给定一个主串S及一个模式串P,判断模式串是否为主串的子串;若是,返回匹配的第一个元素的位置(序号从1开始),否则返回0;如S=“abcd”,P=“bcd”,则返回2;S=“abcd”,P=“acb”,返回0。

    二、朴素算法

    最简单的方法及一次遍历S与P。以S=“abcabaaaabaaacac”,P="abaabcac"为例,一张动图模拟朴素算法:

    在这里插入图片描述
    这个算法简单,不多说,附上代码

    #include<stdio.h>
    int Index_1(char s[],int sLen,char p[],int pLen){//s为主串,sLen为主串元素个数,p为模式串,pLen为模式串的个数
        if(sLen<pLen)return 0;
        int i = 1,j = 1;
        while(i<=sLen && j<=pLen){
            if(s[i]==p[j]){i++;j++;}
            else{
                i = i-j+2;
                j = 1;
            }
        }
        if(j>pLen) return i-pLen;
        return 0;
    }
    void main(){
        char s[]={' ','a','b','c','a','b','a','a','a','a','b','a','a','b','c','a','c'};//从序号1开始存
        char p[]={' ','a','b','a','a','b','c','a','c'};
        int sLen = sizeof(s)/sizeof(char)-1;
        int pLen = sizeof(p)/sizeof(char)-1;
        printf("%d",Index_1(s,sLen,p,pLen));
    }
    

    三、改进的算法——KMP算法

    朴素算法理解简单,但两个串都有依次遍历,时间复杂度为O(n*m),效率不高。由此有了KMP算法。
    一般的,在一次匹配中,我们是不知道主串的内容的,而模式串是我们自己定义的。
    朴素算法中,P的第j位失配,默认的把P串后移一位。
    但在前一轮的比较中,我们已经知道了P的前(j-1)位与S中间对应的某(j-1)个元素已经匹配成功了。这就意味着,在一轮的尝试匹配中,我们get到了主串的部分内容,我们能否利用这些内容,让P多移几位(我认为这就是KMP算法最根本的东西),减少遍历的趟数呢?答案是肯定的。再看下面改进后的动图:
    在这里插入图片描述

    这个模拟过程即KMP算法,若没有看明白,继续往下看相应的解释,理解需要把P多移几位,然后回头再看一遍这个图就很明了了。

    相比朴素算法:
    朴素算法: 每次失配,S串的索引i定位的本次尝试匹配的第一个字符的后一个。P串的索引j定位到1;T(n)=O(n*m)
    KMP算法: 每次失配,S串的索引i不动,P串的索引j定位到某个数。T(n)=O(n+m),时间效率明显提高

    而这“定位到某个数”,这个数就是接下来引入的next值。(实际上也就是P往后移多少位,换一种说法罢了:从上图中也可以看出,失配时固定i不变,令S[i]与P[某个数]对齐,实际上是P右移几位的另一种表达,只有为什么这么表达,当然是因为程序好写。)

    开——始——划——重——点!(图对逻辑关系比较好理解,但i和j的关系对后面求next的算法好理解!)

    • 比如,Pj处失配,绿色的是Pj,则我们可以确定P1…Pj-1是与Si…Si+j-2相对应的位置一一相等的
      在这里插入图片描述

    • 假设P1…Pj-1中,P1…Pk-1与Pj-k+1…Pj-1是一一相等的,为了下面说的清楚,我们把这种关系叫做“首尾重合”
      在这里插入图片描述

    • 那么可以推出,P1…Pk-1与Si…Si+j-2
      在这里插入图片描述

    • 显然,接下来要做的就是把模式串右移了,移到哪里就不用多说了:
      在这里插入图片描述

    • 为了表示下一轮比较j定位的地方,我们将其定义为next[j],next[j]就是第j个元素前j-1个元素首尾重合部分个数加一,当然,为了能遍历完整,首尾重合部分的元素个数应取到最多,即next[j]应取尽量大的值,原因挺好理解的,可以想个例子模拟一下,会完美跳过正确结果。在上图中就是绿色元素的next值为蓝色元素的序号。也即,对于字符串P,next[8]=4。如此,再看一下上面的动图是不是清楚了不少。

    • 最后,如果我们知道了一个字符串的next值,那么KMP算法也就很好懂了。相比朴素算法,当发生失配时,i不变,j=next[j]就好啦!接下来就是怎么确定next值了。

    四、手动写出一个串的next值

    我们规定任何一个串,next[1]=0。(不用next[0],与串的所有对应),仍是一张动图搞定问题:
    在这里插入图片描述
    这个扫一眼就能依次写出,会了这个方法,应付个期末考试没问题了。

    通过把next值“看”出来,我们再来分析next值,这就很容易得到超级有名的公式了,这个式子对后面的算法理解很重要!所以先要看懂这个式子,如果上面的内容通下来了,这个应该很容易看懂了:
    在这里插入图片描述

    五、求next的算法

    终于到了最后了~短的串的next值我们可以“看”出来,但长的串就需要借助程序了,具体算法刚接触的时候确实不容易理解,但给我的体验,把上面的内容写完,现在感觉简简单单了…先附上程序再做解释,(终于到了传说中的整整5行代码让我整理了一下午)。

    int GetNext(char ch[],int cLen,int next[]){//cLen为串ch的长度
        next[1] = 0;
        int i = 1,j = 0;
        while(i<=cLen){
            if(j==0||ch[i]==ch[j]) next[++i] = ++j;
            else j = next[j];
        }
    }
    
    • 还是先由一般再推优化:
      直接求next[j+1](至于为什么是j+1,是为了和下面的对应)
      根据之前的分析,next[j+1]的值为pj+1的前j个元素的收尾重合的最大个数加一。即需要满足两个条件,把它的值一步步“检验”出来。一是“个数最多”的,因此要从可能的最大值开始验;二是“首尾重合”,因此要一一对应验是否相等。
      不难理解,next[j+1]的最大值为j,所有我们从next[j+1]=j开始“验证”。有以下优先判断顺序:
      if(P1…Pj-1 == P2…Pj) => next[j+1]=j
      else if(P1…Pj-2 == P3…Pj) =>next[j+1]=j-1
      else if(P1…Pj-3 == P4…Pj) =>next[j+1]=j-2



      else if(P1P2 == Pj-1Pj) => next[j+1]=3
      else if(P1 == Pj-1) => next[j+1]=2
      else if(P1 != Pj-1) => next[j+1]=1

      每次前去尾1个,后掐头1个,直至得到next[j+1]

    • 再进一步想,next值是一个“工具”,我们单独的求next[j+1]是完全没有意义的,就是说要求next就要把所有j的next求出来。所有一般的,我们都是已知前j个元素的next值,求next[j+1],以此递推下去,求完整的next数组
      但是,上面的思考过程还是最根本的。所以问题变为两个:知道前j个元素的next的情况下,
      ①next[j+1]的可能的最大值是多少(即从哪开始验证)
      ②某一步验证失败后,需要“前去尾几个,后掐头几个?”(即本次验证失败后,再验证哪个值)
      看一下的分析:

    1、next[j+1]的最大值为next[j]+1。
    因为:
    假设next[j]=k1,则可以说明P1…Pk1-1=Pj-k1+1…Pj-1,且这是前j个元素最大的首尾重合序列。
    如果Pk1=Pj,那么P1…Pk1-1PK=Pj-k1+1…Pj-1Pj,那么k+1这也是前j+1个元素的最大首尾重合序列,也即next[j+1]的值为k1+1
    2、如果Pk1≠Pj,那么next[j+1]可能的次大值为next[next[j]]+1,以此类推即可高效求出next[j+1]
    这里不好解释,直接看下面的流程分析及图解

    开——始——划——重——点!
    从头走一遍流程
    ①求next[j+1],设值为m
    已知next[j]=k1,则有P1…Pk1-1 = Pj-k1+1…Pj-1
    如果Pk1=Pj,则P1…Pk1-1PK = Pj-k1+1…Pj-1Pj,则next[j+1]=k1+1,否则
    已知next[k1]=k2,则有P1…Pk2-1 = Pk1-k2+1…Pk1-1
    ⑤第二第三步联合得到:
    P1…Pk2-1 = Pk1-k2+1…Pk1-1 = Pj-k1+1…Pk2-k1+j-1 = Pj-k2+1…Pj-1 即四段重合
    ⑥这时候,再判断如果Pk2=Pj,则P1…Pk2-1P~k2 = Pj-k2+1…Pj-1Pj,则next[j+1]=k2+1;否则再取next[k2]=k3…以此类推

    上面几步,耐心看下来,结合那个式子很容易看懂。最后,再加一个图的模拟帮助理解:
    1、要求next[k+1] 其中k+1=17
    在这里插入图片描述
    2、已知next[16]=8,则元素有以下关系:
    在这里插入图片描述
    3、如果P8=P16,则明显next[17]=8+1=9
    4、如果不相等,又若next[8]=4,则有以下关系

    在这里插入图片描述
    又加上2的条件知
    在这里插入图片描述
    主要是为了证明:
    在这里插入图片描述
    5、现在在判断,如果P16=P4则next[17]=4+1=5,否则,在继续递推
    6、若next[4]=2,则有以下关系
    在这里插入图片描述
    7、若P16=P2,则next[17]=2+1=3;否则继续取next[2]=1、next[1]=0;遇到0时还没出结果,则递推结束,此时next[17]=1。最后,再返回看那5行算法,应该很容易明白了!

    展开全文
  • KMP入门级别算法详解--终于解决了(next数组详解)

    万次阅读 多人点赞 2017-08-16 22:55:36
    对于正常的字符串模式匹配,主串长度为m,子串为n,时间复杂度会...KMP算法用到了next数组,然后利用next数组的值来提高匹配速度,我首先讲一下next数组怎么求,之后再讲匹配方式。 next数组详解 首先是理解KMP...

    对于正常的字符串模式匹配,主串长度为m,子串为n,时间复杂度会到达O(m*n),而如果用KMP算法,复杂度将会减少线型时间O(m+n)。

     

    设主串为ptr="ababaaababaa";,要比较的子串为a=“aab”;

     

    KMP算法用到了next数组,然后利用next数组的值来提高匹配速度,我首先讲一下next数组怎么求,之后再讲匹配方式。

     

    next数组详解

    首先是理解KMP算法的第一个难关是next数组每个值的确定,这个问题困恼我很长时间,尤其是对照着代码一行一行分析,很容易把自己绕进去。

    定义一串字符串

    ptr = "ababaaababaa";

     

    next[i]i从1开始算)代表着,除去第i个数,在一个字符串里面从第一个数到第(i-1)字符串前缀与后缀最长重复的长度。(这里看不懂继续往下看就行)

     

    什么是前缀

    在“aba”中,前缀就是“ab”,除去最后一个字符的剩余字符串。

    同理可以理解后缀。除去第一个字符的后面全部的字符串。

     

    在“aba”中,前缀是“ab”,后缀是“ba”,那么两者最长的子串就是“a”;

    在“ababa”中,前缀是“abab”,后缀是“baba”,二者最长重复子串是“aba”;

    在“abcabcdabc”中,前缀是“abcabcdab”,后缀是“bcabcdabc”,二者最长重复的子串是“abc”;

     

    这里有一点要注意,前缀必须要从头开始算,后缀要从最后一个数开始算,中间截一段相同字符串是不行的。

     

    在next数组中,有两种定义方式:(定义方式可以先不用管,继续往下看,看懂了再回来看)

    第一种是next[1]=-1,next[2]=-1。这里的-1代表没有匹配,1代表匹配了1位。

    第二种是规定next[1]=0,next[2]=1。(第二种方法之后会讲)这里0与1是规定,后面的匹配中,如果1位匹配,则规定next值为2(就是匹配的位数+1)。

     

    先看第一种规定方法:

    再回到next[i]的定义,对于字符串ptr = "ababaaababaa";

    next[1] = -1,字符串“a”,要进行next数组运算,也就是代表着除了第一个元素,它本身之前的 前缀 与 后缀 最长的重复子串,这里是空 ,即"",没有,我们记为-1,代表空。(0代表1位相同,1代表两位相同,依次累加)。

    next[2] = -1,字符串为“ab”,要进行计算的字符串为“a”(要扣除当前字符“b”,所以只剩下“a”),没有前缀与后缀,故最长重复的子串是空,值为-1;

    next[3] = -1,字符串为“aba”,要进行计算的字符串为“ab”(要扣除当前字符“a”,所以只剩下“ab”),前缀是“a”,后缀是“b”,最长重复的子串“”;

    next[4] = 1,字符串为“abab”,要进行计算的字符串为"aba"(要扣除当前字符“b”,所以只剩下“aba”),前缀是“ab”,后缀是“ba”,最长重复的子串“a”;next数组里面就是最长重复子串字符串的长度

    next[5] = 2,字符串为“ababa”,要进行计算的字符串为"abab"(要扣除当前字符“a”,所以只剩下“abab”),前缀是“aba”,后缀是“bab”,最长重复的子串“ab”;

    next[6] = 3,字符串为“ababaa”,要进行计算的字符串为"ababa"(要扣除当前字符“a”,所以只剩下“ababa”),前缀是“abab”,后缀是“baba”,最长重复的子串“aba”;

    next[7] = 1,字符串为“ababaaa”,要进行计算的字符串为"ababaa"(要扣除当前字符“a”,所以只剩下“ababaa”),前缀是“ababa”,后缀是“babaa”,最长重复的子串“a”;

    next[8] = 1,字符串为“ababaaab”,要进行计算的字符串为"ababaaa"(要扣除当前字符“b”,所以只剩下“ababaaa”),前缀是“ababaa”,后缀是“babaaa”,最长重复的子串“a”;

    next[9] = 2,字符串为“ababaaaba”,要进行计算的字符串为"ababaaab"(要扣除当前字符“a”,所以只剩下“ababaaab”),前缀是“ababaaa”,后缀是“babaaab”,最长重复的子串“ab”;

    next[10] = 3,字符串为“ababaaabab”,要进行计算的字符串为"ababaaaba"(要扣除当前字符“b”,所以只剩下“ababaaaba”),前缀是“ababaaab”,后缀是“babaaaba”,最长重复的子串“aba”;

    next[11] = 4,字符串为“ababaaababa”,要进行计算的字符串为"ababaaabab"(要扣除当前字符“a”,所以只剩下“ababaaabab”),前缀是“ababaaaba”,后缀是“babaaabab”,最长重复的子串“abab”;

    next[12] = 5,字符串为“ababaaababaa”,要进行计算的字符串为"ababaaababa"(要扣除当前字符“a”,所以只剩下“ababaaababa”),前缀是“ababaaabab”,后缀是“babaaaababa”,最长重复的子串“ababa”;

    所以字符串ptr = "ababaaababaa"的next数组为:-1,-1,-1,1,2,3,1,1,2,3,4,5

     

    第二种方法中:

    变化的只有下标,原理都一样。

    这里我们定义next[1] = 0 , next[1] = 1;

     

    再分析ptr字符串,ptr = "ababaaababaa";

    跟上一个的情况类似,

     

    next[1] = 0 ,事先定义好的

    next[2] = 1 ,事先定义好的

    next[3] = 1 ,最长重复的子串“”;1代表没有重复,2代表有一个字符重复。

    next[4] = 2 ,最长重复的子串“a”;追偿的长度加1,即为2.

    next[5] = 3 ,以下都跟之前的一样,这种方法是最长的长度再加上一就可以了。

    next[6] = 4

    next[7] = 2

    next[8] = 2

    next[9] = 3

    next[10] = 4

    next[11] = 5

    next[12] = 6

     

    以上是next数组的详细解释。next数组求值 是比较麻烦的,剩下的匹配方式就很简单了。

    next数组用于子串身上,根据上面的原理,我们能够推出子串a=“aab”的next数组的值分别为0,1,2.(按照我说的第二种方式算的)。

    首先开始计算主串与子串的字符,设置主串用i来表示,子串用j来表示,如果ptr[i]与a[i]相等,那么i与j就都加1

    prt[1]与a[1]相等,i++,j++:

    用代码实现就是

    if( j==0 ||  ptr[i]==a[j])
    {
        ++i;
        ++j;
    }

     

    ptr[2]与a[2]不相等

    此时ptr[2]!=a[2],那么令j = next[j],此时j=2,那么next[j] = next[2] = 1.那么此时j就等于1.这一段判断用代码解释的话就是:

    if( ptr[i]!=a[j])
    {
          j = next[j];
    }

    加上上面的代码进行组合:

    在对两个数组进行比对时,各自的i,j取值代码:

    while( i<ptr.length && j< a.length)
    {
         if( j==0 || ptr[i]==a[i] )
        {
              ++i;
              ++j;
              next[i] = j;
        }
        else
        {
              j = next[j];
        }
    }

     

    此时将a[j]置于j此时所处的位置,即a[1]放到j=2处,因为在j=2时出现不匹配的情况。

    此时再次计算是否匹配,可以看出来a[1]!=ptr[2],那么j = next[j],即此时j = next[1] = 0;

    根据上面的代码,当j=0时,执行++i;++j;

    此时就变为:

    此时ptr[3] = a[1],继续向下走,下一个又不相等了,然后“aab”向后挪一位,这里不再赘述了,主要的思想已经讲明白了。到最后一直到i = 8,j=3时匹配成功,KMP算法结束。整个过程就结束了。

    展开全文
  • 如何利用KMP的next求字符串的循环节

    万次阅读 2017-05-23 20:19:36
    利用KMP算法中的next值可以求出字符串的循环节,如ababab的循环节为ab,abcd的循环节为abcd,具体做法如下:假设字符串的长度为len,next[len]为字符串的最后一个字符的下一个字符的next值(下标从0开始),如果len ...

    利用KMP算法中的next值可以求出字符串的循环节,如ababab的循环节为ab,abcd的循环节为abcd,具体做法如下:假设字符串的长度为len,next[len]为字符串的最后一个字符的下一个字符的next值(下标从0开始),如果len % (len - next[len]) == 0,那么循环节的循环次数为len / (len - next[len]),否则为1,为什么呢?详细说明如下:

    首先,对于给定的长度为len的字符串str,根据next的定义可知,str[0~(next[j]-1)] = str[(j-next[j])~(j-1)],且next[j]为满足该条件的值当中的最大那一个,令循环次数为k,则

    当k = 1时,根据next的意义可知next[len] = 0,所以len / (len - next[len]) = 1,结论正确;

    当k = 2时,如abcdabcd,如果最后一个d后面还有字符的话,那么它的next的值应该指向第二个a,为4,len % (len - next[len])= 8 % (8 - 4) = 0,循环次数为2,结论正确;

    当k >= 3时,有len = k * (len - next[len])(x >= 3),next[len] = (1 - 1 / k) * len > (1 / 2) len,即next[len]位于字符串的中间位置之后,如图1所示,且黄色部分与蓝色部分一样,

    如何利用KMP的next求字符串的循环节   图1

     

    所以,在图2中,紫色部分跟绿色部分也一样(假设二者长度一样),

    如何利用KMP的next求字符串的循环节   图2

     

    由于黄色部分跟蓝色部分是一样,且蓝色部分结尾的两段(紫色跟绿色)是一样的,因而黄色部分在结尾部分也应该有两段一样的,即绿色跟它前面相同长度的一段,假设为红色,此时红色部分是蓝色部分的倒数第三段,且跟前两段一样,这也将导致黄色部分也将产生倒数第三段,这样,蓝色部分的倒数第k段永远是是黄色部分的倒数第k-1段,只要证明蓝色跟黄色的公共部分是紫色部分的整数倍,那么就可以说该公共部分是由n个紫色部分组成,由于蓝色部分跟黄色部分长度一样,二者又有公共部分,所以图2中红色部分跟紫色部分长度一样,又因为整个字符串长度是紫色部分的整数倍(>= 3),所以公共部分的长度也是紫色部分的整数倍(>= 1),如此一来,公共部分部分是由n个紫色部分组成(n >= 1),从而红色部分跟紫色部分也必然一样(红色部分是黄色部分的跟紫色长度相同的第一部分),所以,整个字符串是由n个紫色部分组成的(n >= 3),结论正确。

    综上所述,结论的充分性得证,另外,由next的意义可以很容易证明必要性。

    展开全文
  • 最近因为next()遇到了不少问题,在这里记录一下 首先是路由守卫,是不是感觉简简单单 beforeEach((to, from, next) => { to //是要去的路由 from // 是当前路由 next() // 是放行的意思 } 但是在看别的项目时...

    最近因为next()遇到了不少问题,在这里记录一下

    首先是路由守卫,是不是感觉简简单单

    beforeEach((to, from, next) => {
    	to // 要去的路由
    	from // 当前路由
    	next() // 放行的意思
    }
    

    但是在看别的项目时常常能看到next('/logon') 、 next(to) 或者 next({ ...to, replace: true }) 这又是啥意思呢

    其实在路由守卫中,只有next()是放行,其他的诸如:next('/logon') 、 next(to) 或者 next({ ...to, replace: true })都不是放行,而是:中断当前导航,执行新的导航

    可以这么理解:

    next() 是放行,但是如果next()里有参数的话,next()就像被重载一样,就有了不同的功能。

    而对于上面说的中断当前导航,执行新的导航打个比方:

    现在我有一个守卫,在守卫中我使用next('/logon'),肯定有同学认为是会直接跳转到/logon路由:

    beforeEach((to, from, next) => {
      next('/logon')
    }
    

    然而年轻人不讲武德,执行时需要这么看:

    beforeEach((to, from, next) => {
      beforeEach(('/logon', from, next) => {
      	 beforeEach(('/logon', from, next) => {
      	 	 beforeEach(('/logon', from, next) => {
      	 	 	beforeEac...  // 一直循环下去...... , 因为我们没有使用 next() 放行
     		}
     	 }
      }
    }
    

    如果把这个守卫改一下,当我在地址栏输入/home

    beforeEach((to, from, next) => {
       if(to.path === '/home') {
       	next('/logon')
       } else {
        // 如果要去的地方不是 /home , 就放行
       	next()
       }
    }
    

    我本来要去/home路由,因此执行了第一次 beforeEach((to, from, next)

    但是这个路由守卫中判断了如果要去的地方是'/home',就执行next('/logon')

    所以想要访问/home可以这么看

    beforeEach((to, from, next) => {
       beforeEach(('/logon', from, next) => {
         next()  // 现在要去的地方不是 /home , 因此放行
       }
    }
    

    注意:重点就在这,next('/logon')不是说直接去/logon路由,而是中断(不是CPU的那个中断!VUE中的中断就是此时不会执行router.afterEach(() => {})这一次路由守卫的操作,又进入一次路由守卫,就像嵌套一样,一层路由守卫,然后又是一层路由守卫,此时路由守卫进入到第二层时,to.path已经不是/home了,这个时候才执行next()放行操作。

    正以为如此很多人在使用动态添加路由addRoutes()会遇到下面的情况:

    addRoutes()之后第一次访问被添加的路由会白屏,这是因为刚刚addRoutes()就立刻访问被添加的路由,然而此时addRoutes()没有执行结束,因而找不到刚刚被添加的路由导致白屏。因此需要从新访问一次路由才行。

    该如何解决这个问题 ?

    此时就要使用next({ ...to, replace: true })来确保addRoutes()时动态添加的路由已经被完全加载上去。

    next({ ...to, replace: true })中的replace: true只是一个设置信息,告诉VUE本次操作后,不能通过浏览器后退按钮,返回前一个路由。

    因此next({ ...to, replace: true })可以写成next({ ...to }),不过你应该不希望用户在addRoutes()还没有完成的时候,可以点击浏览器回退按钮搞事情吧。

    其实next({ ...to })的执行很简单,它会判断:

    如果参数to不能找到对应的路由的话,就再执行一次beforeEach((to, from, next)直到其中的next({ ...to})能找到对应的路由为止。

    也就是说此时addRoutes()已经完成啦,找到对应的路由之后,接下来将执行前往对应路由的beforeEach((to, from, next) ,因此需要用代码来判断这一次是否就是前往对应路由的beforeEach((to, from, next),如果是,就执行next()放行。

    如果守卫中没有正确的放行出口的话,会一直next({ ...to})进入死循环 !!!

    因此你还需要确保在当addRoutes()已经完成时,所执行到的这一次beforeEach((to, from, next)中有一个正确的next()方向出口。

    因此想实现动态添加路由的操作的话,代码应该是这样的:

    router.beforeEach((to, from, next) => {
     const token = sessionStorage.getItem('access_token')
     // 存在 token 说明已经登录
     if (token) {
       // 登录过就不能访问登录界面,需要中断这一次路由守卫,执行下一次路由守卫,并且下一次守卫的to是主页'
       if (to.path === '/login') {
         next({ path: '/' })
       }
       // 保存在store中路由不为空则放行 (如果执行了刷新操作,则 store 里的路由为空,此时需要重新添加路由)
       if (store.getters.getRoutes.length || to.name != null) {
         //放行
         next()
       } else {
         // 将路由添加到 store 中,用来标记已添加动态路由
         store.commit('ADD_ROUTER', '需要添加的路由')
         router.addRoutes('需要添加的路由')
         // 如果 addRoutes 并未完成,路由守卫会一层一层的执行执行,直到 addRoutes 完成,找到对应的路由
         next({ ...to, replace: true })
       }
     } else {
       // 未登录时,注意 :在这里也许你的项目不只有 logon 不需要登录 ,register 等其他不需要登录的页面也需要处理
       if (to.path !== '/logon') {
         next({ path: '/logon' })
       } else {
         next()
       }
     }
    

    万一还是听不懂,也可以next()比作Java Filter里的chain.doFilter(req, resp)

    @WebFilter(filterName = "EncodingFilter", urlPatterns = "/*")
    public class EncodingFilter implements Filter {
    
        @Override
        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
            // 设置编码
            req.setCharacterEncoding("utf-8");
            resp.setContentType("text/html;charset=utf-8");
            chain.doFilter(req, resp);  // next()
        }
    
    }
    
    展开全文
  • KMP算法Next数组计算

    万次阅读 多人点赞 2012-10-31 21:18:29
    2次都是让求Next函数的序列(其实是)。先看看题吧。 (2011年下半年上午题) (2012年上半年上午题) 其实做这个题很简单,我先说说这个题里的各种概念。 给定的字符串叫做模式串T。j表示next函数的参数,其...
  • Please run next command `npm update` 按照提示操作,运行npm update也没有解决。 于是我查询了一下npm手册,得知是不能直接运行npm update的,必须带上包名,所以应该这样写命令: npm update caniuse-lite...
  • KMP算法的next数组实现

    万次阅读 2021-04-20 16:38:28
    KMP算法 for leetcode 实现strStr() 前不久打虎符CTF的qual时候做过一道redemption_...kmp的关键就是如何得到next数组,LeetCode里面的推导结合代码看的话会比较清楚。我在代码里加了注释,配合LeetCode的官方题解,
  • p->next=q与q=p->next区分

    万次阅读 多人点赞 2019-05-19 22:14:43
    p->next=q 将q 赋值给p->next,即p的下一个结点是q q=p->next 将p->next(t)赋值给q, 即q也指向t
  • li=[1,2,3,4] it=iter(li) print(next(it)) print(next(it)) print(next(it)) ...print(next(it)) next()完成后引发StopIteration异常 --------------------------------------------------------- for l in ...
  • next值计算

    千次阅读 2019-04-28 22:15:53
    一点都没有基础,看网上求next值的算法写得云里雾里的,这里总结一下自己的理解吧 next[j] = 0 当j=1时 next[j] = 1 当j之前的字符串首尾没有匹配的字符时 next[j] = 首尾的匹配数 + 1 当j之前的字符...
  • Next 值与 Nextval 值的计算

    万次阅读 多人点赞 2018-05-20 20:42:05
    KMP算法对模式串求解其Next值和Nextval值的计算方法 Next值的计算 方法一 方法二 Nextval值的计算 模式串S = “abaabcac” ,求其 Next 数值序列: 1 2 3 4 5 6 7 8 a b a a b...
  • 首先在将例子之前先说说这个next数组求解的思路:第一位的next的值是0,第二位的next的值为1,后面求解每一位的next的值时。首先将前一位与其next值对应的内容进行比较,如果相等,则该位的next值就是前一位的next值...
  • next数组求解详解

    万次阅读 多人点赞 2017-08-20 20:52:59
    next数组求解详解,以串'ababaaababaa'为例
  • 单链表里,如果p->next为NULL,那么引用 p->next->next 会报错吗?还是相当于NULL?
  • result.next() 进行读取结果集的下一条数据; while(result.next) 将rs全部进行读取;(ResultSet rs=.....) if(result.next) 进行读取一次,判断是否有数据。 next()方法返回的是boolean型,用来确认有没有数据,...
  • 算法:next数组的求法详解

    万次阅读 多人点赞 2019-01-27 16:26:48
    在牛客网刷题遇到了求next数组的题型,结果在学校学的没有牢记,做错了,还是要多刷题做总结啊。 我们先口述说明一下next数组的求解方法: 我们能确定next数组第一二位一定分别为0,1,后面求解每一位的next值时,...
  • c++的next

    千次阅读 2019-02-14 11:33:43
    在做关于深搜的题目时,用c的时候喜欢定义next数组来指明下一步方向,但有时老是出现编译错误的提示,从哪里也找不出错的感受,大家都懂。于是搜来答案,认真对比,就是数组名字不一样,大佬们都喜欢用dire,真是巧...
  • vue-next

    千次阅读 2019-10-24 12:54:42
    vue-next项目地址 git地址:链接 git clone git@github.com:vuejs/vue-next.git npm install npm run dev // 生成一个未压缩的状态vue文件 入门小案例 <!DOCTYPE html> <html lang="en"> <head>...
  • Nextcloud基本使用方法

    万次阅读 2019-12-05 14:37:23
    下载和安装 Nextcloud 客户端 客户端可以在这里下载https://nextcloud.com/install/,您可以选择 Desktop 或者 Mobile 。 如果您是 Windows 用户,可以直接点击这个链接...
  • nextcloud应用 如果写作是您工作或日常工作的一部分,您可能会发现Nextcloud开源文件同步和共享应用程序是非常有用的工具。 首先,它为您提供免费,安全且易于访问的云文件存储。 其次,它是完全可定制的,这意味...
  • NODE* next;}NODE;NODE a;NODE p;p-&gt;next = a;p-&gt;next-&gt;next 相当于 a-&gt;next 这是ok的;但当p-&gt;next = null,p-&gt;next-&gt;next 这是不存在的,null为空,又不是NODE...
  • Iterator主要有三个方法:hasNext()、next()、remove()详解

    万次阅读 多人点赞 2016-01-14 11:13:13
    一、Iterator的API 关于Iterator主要有三个方法:hasNext()、next()、remove() hasNext:没有指针下移操作,只是判断是否存在下一个元素 next:指针下移,返回该指针所指向的元素 remove:删除当前指针所指向的元素,...
  • Hexo博客优化之Next主题美化

    万次阅读 多人点赞 2019-01-26 21:42:19
    前言 有了前面几篇博客的介绍,我们就...Hexo博客支持很多主题风格,其中Next主题是Github上Star最多的主题,其一直在更新维护,支持非常多的外部插件和功能选项。我目前使用的是Next6.0版本,下面我会介绍基于Ne...
  • 步骤一 进入NexT文件目录 $ cd themes/next 步骤二 下载canvas-nest 我们把canvas-nest下载到next目录下的ource/lib目录里 $ git clone ...
  • C++中全排列函数next_permutation 用法

    万次阅读 多人点赞 2017-03-29 14:38:25
    全排列参考了两位的博客 感谢! ... 早就听说了了next_permutation 产生全排列的强大,一直到昨晚遇到一个对字符串产生全排列的问题才知道这个函数的强大,我们队是按照
  • Hexo主题推荐:butterfly、NeXT

    万次阅读 2021-01-12 11:56:20
    放两个我考虑使用的主题: https://butterfly.js.org/ http://theme-next.iissnan.com/
  • 我们通常在一些app 项目里面看到,koa使用中间件有时一个参数ctx, 有时2个参数,一个ctx, 一个next 什么时候用nextnext是相对于中间件middleware来用的, 建设这个函数模块,根本不是中间件,比如说 访问网页的...
  • 在gdb中,有next, nexti, step, stepi等指令来单步调试程序,他们功能各不相同,区别在于单步的“跨度”上。 next 单步到程序源代码的下一行,不进入函数。 nexti 单步一条机器指令,不进入函数。 step 单步到下一...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 432,122
精华内容 172,848
关键字:

next