zoukankan      html  css  js  c++  java
  • 大话数据结构(十二)java程序——KMP算法及改进的KMP算法实现

    1、朴素的模式匹配算法

    朴素的模式匹配算法:就是对主串的每个字符作为子串开头,与要连接的字符串进行匹配。对主串做大循环,每个字符开头做T的长度的小循环,直到成功匹配或全部遍历完成为止。

    又称BF算法

    package com.alice.dataStructe5.bf;
    
    /**
     * 返回子串t在主串s中第pos个字符之后的位置,若不存在,则返回-1
     * @author Administrator
     *
     */
    public class BF {
         
       public  int index(String s,String t){
           
           char ch1[] =s.toCharArray();
           char ch2[] = t.toCharArray();
           int i = 0;//主串的pos位置开始
           int j = 0;//j用于子串开始的下表
           while(i<ch1.length && j<ch2.length){//若i小于s长度且j小于t长度时循环
               if(ch1[i]==ch2[j]){//两个字母相等则继续
                   i++;
                   j++;
               }else{//指针后退重新开始匹配
                   i = i-j+1;//i退回到上次匹配首位的下一个位置
                   j=0;//退回到子串t的首位
               }
           }
           if(j==ch2.length){
               return i-j+1;//返回子串t在主串s中第pos个字符之后的位置
           }else{
               return -1;//不存在,则返回-1
           }
           
           
       }
       
    
       public static void main(String args[]){
           BF bf = new BF();
    
           System.out.println(bf.index("hellolo", "lo"));
           System.out.println(bf.index("goooglegoogle", "goog"));
    
       }
       
    }
      

    2、KMP模式匹配算法

    这个算法,可以大大避免重复遍历的情况。

    在朴素的模式匹配算法中,主串的i值是不断回溯的。KMP 模式匹配算法就是为了让这种没有必要的回溯不发生。

    KMP模式匹配算法的重要点在于,寻找next数组。

    next数组:当模式匹配中T失配时,next数组对应的元素指定应用T串的哪个元素进行下一轮匹配。

    KMP模式匹配算法的实现代码:

    package com.alice.dataStructe5.kmp;
    
    import java.util.Arrays;
    
    public class KMP {
        public int[] getNext(char[] ch){
        	int i = 0;//后缀
        	int j = -1;//前缀
        	int[] next = new int[ch.length];
        	next[0] = -1;
        	while(i < ch.length-1){
        		if( j == -1|| ch[i]==ch[j]){//ch[i]表示后缀的单个字符,ch[j]表示前缀的单个字符
        			i++;
        			j++;
        			next[i] = j;
        		}else{
        			j = next[j];//若字符不相等,j值回溯
        		}
        	}
        	System.out.println(Arrays.toString(next));
        	return next;
        }
        public  void getNext1() {
            int j = 0, k = -1;
            String s="ababaaaba";
            char []c=s.toCharArray();
            int[] next1 = new int[c.length];
            next1[0] = -1;
            while (j < c.length - 1) {
                if (-1 == k || c[j] == c[k]) {
                    j++;
                    k++;
                    next1[j] = k;
                } else {
                    k = next1[k];
                }
            }
            System.out.println(Arrays.toString(next1));
            
    	}
        
        public int Index_KMP(String str, String sub) {
        	char[] ch1 = str.toCharArray();
        	char[] ch2 = sub.toCharArray();
        	int i = 0;
        	int j = 0;
        	int index = 0;
        	int[] nextArray = null;
        	nextArray = getNext(ch2);
        	while(i <ch1.length && j<ch2.length){
        		if(ch1[i] == ch2[j] || j==0){
        			i++;
        			j++;
        		}else{
        			j = nextArray[j];
        		}
        	}
        	if(j >= ch2.length){
        		index = i-ch2.length;
        	}else{
        		 index = -1;
        	}
        	return index;
        }
        public static void main(String args[]){
        	KMP kmp = new KMP();
    //    	kmp.Index_KMP("abcabx", "ab");
        	String str = "abcabx";
        	char[] ch = str.toCharArray();
        	kmp.getNext(ch);
        	int a=kmp.Index_KMP("aaaabcdefaaaaax", "aaaaax");
        	System.out.println("a的值为:"+a);
    //    	kmp.getNext1();
    //   	System.out.println(kmp.Index_KMP("goooglegoogle", "goog"));
        	System.out.println(kmp.Index_KMP("ababcabcacbab", "abcac"));
        }
    }
    

    KMP算法的时间复杂度为O(N+M),相对于模式匹配算法O((n-m+1)*m)来说,更好一些

    3、改进的KMP算法

    package com.alice.dataStructe5.kmp;
    
    import java.util.Arrays;
    
    public class KMPImproved {
    	
        /**
         * 改进的KMP算法中,得到nextval数组的方法,用于指导下个元素进行下一轮匹配
         * @param ch子串数组
         * @return
         */
        public int[] getNextval(char[] ch){
        	int j = -1;
        	int i = 0;
        	int[] nextval = new int[ch.length];
        	nextval[0] = -1;
        	while(i < ch.length-1){
        		if(j==-1 || ch[i] == ch[j]){//ch[i]表示后缀的单个字符,ch[j]表示前缀的单个字符
        			i++;
        			j++;
        			if(ch[i] != ch[j]){//若当前字符与前缀字符不匹配
        				nextval[i] = j;//则当前的j为nextval在i位置的值
        			}else{
        				nextval[i] = nextval[j];//如果与前缀字符相等,则将前缀字符的nextval赋值给nextval在i位置的值
        			}
        		}else{
        			j = nextval[j];
        		}
        	}
        	System.out.println(Arrays.toString(nextval));
        	return nextval;
        }
        public int getKMP(String s,String t){
        	char[] ch1 = s.toCharArray();//将字符串转为数组
        	char[] ch2 = t.toCharArray();//将字符串转为数组
        	int i = 0;
        	int j = 0;
        	int index = 0;
        	int[] nextval = getNextval(ch2);//定义数组nextval[],通过getNextval()方法得到
        	while(i < ch1.length && j < ch2.length){//若i小于ch1的长度且j小于ch2的长度,循环继续
        		if(j==0 || ch1[i] == ch2[j]){//两字符相等,则继续
        			i++;
        			j++;
        		}else{//指针后退重新进行下一轮匹配
        			j = nextval[j];//j值退回到合适的位置,i值不变
        		}
        	}
        	if(j >= ch2.length){
        	  index = i-ch2.length;//返回子串第一次出现在主串的位置
        	}else{
        	  index = -1;
        	}
        	return index;
        }
        public static void main(String args[]){
        	KMPImproved kmpImproved = new KMPImproved();
        	String  t = "ababaaaba";
        	kmpImproved.getNextval(t.toCharArray());
        	System.out.println(kmpImproved.getKMP("ababcabcacbab", "abcac"));;
        }
    }
    

      

  • 相关阅读:
    模拟实现ajax加载框
    京东晒单的js实现
    微信分享js代码(转载)
    css模拟实现selec下拉框
    网页端实现输入卡号四字隔开
    返回顶部的动态显示与隐藏
    js等比例缩放图片(转载)
    css模拟实现checkbox
    quartz的使用 Mr
    Spring声明式事务配置管理方法 Mr
  • 原文地址:https://www.cnblogs.com/snowwang/p/6094199.html
Copyright © 2011-2022 走看看