KMP算法实现next数组和nextVal数组笔记。

本人是个菜鸟,最近正在看大话数据结构,正好看到了KMP算法部分,看书中的解释刚开始是懵逼的,后来百度了一些博客,还是一知半解的状态,最后结合了阮一峰老师的讲解,算是搞明白了到底KMP算法next数组大概是怎么回事。下面附上连接:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html

由于本人是学的java,大话数据结构中的代码是c,看了两三天,于是动手讲c代码翻译成了java代码。

下面贴上代码:


public class KmpTest {

    public static void main(String[] args) {
        String S = "aaaabaax";
        String T = "aax";
        int i = indexOf(S, T);
        System.out.println(i);

        String aaaav = "ababaaaba";

        int[] nextVal = getNext(aaaav);

        for (int j :
                nextVal) {
            System.out.printf(j+",");
        }
    }


    private static int indexOf(String S, String T){

        char[] strs = S.toCharArray();
        char[] maths = T.toCharArray();
        int[] next = getNextVal(T);

        int i =0;
        int j =0;

        while (i< S.length() && j < T.length()){



            if (strs[i] == maths[j]){
                j++;
                i++;
            }else{
                if(j==0){
                    i++;
                    continue;
                }
                j = next[j-1];

            }

        }

        if(j == T.length()){
            return i - j;
        }


        return -1;
    }


    /**
     * 根据匹配串获取对应的获取next数组
     *
     * 这里的判断条件思路:
     *                     根据kmp算法。
     *                     next[0]一定是0,因为没有字符可以比较,由于int数组初始化时,数组中的每个数据都是0,我就省略了next[0]=0的代码。
     *                     当next[1]时,只有一个字符可以比较,所以next[1]=1,
     *
     *                     为什么比较的时候时比较chars[i-1] ===chars[j-1]呢
     *
     *                     假设当前的模式串为abcabd
     *                     根据next[0]=0,所以我的i是从1开始的。
     *                     在还没开始遍历前的变量值为 next:{0} i=0,j=0;
     *                     第一次进入循环,判断到j==0 所以就i++,j++操作,此时 i=1,j=1
     *                     next[1] = 1,此时变量的值分别为 next:{0,1} i=1,j=1;
     *                     第二次进入循环j不等于0了,就判断当前的字符串和上次计算出来的j位置的前一个位置的值进行比较。
     *                     这里就是关键,每次计算出一个next的值,就知道了之前的前后缀的相似度。只需要将当前char[i]的值一直和上次的j值的前一位进行比较
     *                     当比较不得不相同时,就回溯当前的j值,一旦回溯到了1,就不用回溯了。直接赋值为1了。
     * @param T
     * @return
     */
    private static int[] getNext(String T){


        char[] chars = T.toCharArray();



        int i = 0;

        int j = 0;

        // 根据字符串长度初始一个空的next数据
        int[] next = new int[chars.length];


        // 开始遍历字符串T
        while (i < chars.length-1){


            if (j==0 || chars[i] == chars[j-1]){
                i++;
                j++;
                next[i] = j;
            }else{
                j = next[j-1];
            }


        }


        return next;
    }

    /**
     * 因为kmp算法是有缺陷的,aaaaax的next数组为{0,1,2,3,4,5},匹配到x的时候失败了,会回到5,再回到4。。一直回到0,中间是可以省略的
     * 所以有的大佬想出了nextVal数组
     *
     * nextVal的实现基本跟上面的next差不多,只不过在赋值之前,先判断下次要判断逻辑,如果下一次判断的结果和这一次相同,那么就认为
     * 这个可能出现了aaaa的情况,所以本次的值为上一次计算的j值
     *
     * @param T
     * @return
     */
    private static int[] getNextVal(String T){


        char[] chars = T.toCharArray();



        int i = 0;

        int j = 0;

        int[] nextVal = new int[chars.length];

        while (i < chars.length-1){


            if (j==0 || chars[i] == chars[j-1]){
                i++;
                j++;


                if(chars[i] == chars[j-1]){

                    nextVal[i] = nextVal[j-1];
                }else{
                    nextVal[i] = j;

                }
            }else{
                j = nextVal[i];
            }


        }


        return nextVal;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值