KMP快速字符串匹配

KMP匹配算法

1.简介

简单匹配算法虽然易于实现,但是时间复杂度比较高。Knuth、Morris和Pratt发明了快速字符串匹配算法,算法以这三个人的名字命名,即KMP算法。

KMP算法的想法是,设法利用这个已知信息,不要把"搜索位置"移回已经比较过的位置,继续把它向后移,这样就提高了效率。

2.match表

[1].举例:

字符串: bread

前缀:b,br,bre,brea

后缀:read,ead,ad,d

KMP快速字符串匹配_第1张图片

生成方式:

match[0] = -1;

从i = 1遍历数组到i = pattern.length - 1

每次遍历记录j = match[i-1]

让j = match[j],此处使用while循环,循环条件是j >= 0 && 字符 i != j+1

如果字符i == j+1,match[i] = ++j;

如果i != j ,match[i] = -1

匹配方式:

主串指针i,子串指针j

while(指针i和指针j没有越界)

如果指针i和指针j对应字符相等,i++,j++;

不相等时,如果指针j不在0的位置,j = match[j - 1] + 1

否则指针i后移

循环结束后,如果指针j == 子串长度,表示找到了子串

返回i - 子串长度,否则返回-1

public class KMP {
     
	/**
	 * match数组
	 */
	private  int [] match;
	
	/**
	 * 主串
	 */
	private  String mainStr;

	/**
	 * 子串
	 */
	private  String subStr;
	
	
	/**
	 * 构造器
	 * @param mainStr 主串
	 * @param subStr 子串
	 */
	public KMP(String mainStr,String subStr) {
     
		try {
     
			this.subStr = subStr;
			this.mainStr = mainStr;
			match = new int[subStr.length()];
			initMatch();//初始化match表
		}
		catch (Exception e) {
     
			// TODO: handle exception
			System.out.println("字符串非法!!!");
			System.exit(0);//终止运行
		}
	}
	
	/**
	 * 初始化match表中的值
	 */
	public void initMatch() {
     
		int len = subStr.length();
		
		match[0] = -1;
		for(int i = 1; i < len; i++) {
     
			//获得当前位置的前一个字符的部分匹配值
			int j = match[i - 1];
			
			while(j >= 0 && subStr.charAt(i) != subStr.charAt(j+1)) {
     
				j = match[j];
			}
			if(subStr.charAt(i) == subStr.charAt(j+1)) {
     
				match[i] = j + 1;
			}
			else {
     
				match[i] = -1;
			}
		}
	}
	
	/**
	 * 匹配字符串,找到子串,返回子串出现的位置
	 * 否则返回-1
	 * @return 
	 */
	public int getMatchResult() {
     
		try {
     
			int mainLength = mainStr.length();
			int subLength = subStr.length();
			//如果主串长度小于子串长度,不可能匹配到
			if(mainLength < subLength) {
     
				return -1;
			}
			
			int i = 0;//主串指针
			int j = 0;//子串指针
			while(i < mainLength && j < subLength) {
     
				if(mainStr.charAt(i) == subStr.charAt(j)) {
     
					i++;
					j++;
				}
				else if(j != 0) {
     
					j = match[j - 1] + 1;
				}
				else {
     
					i++;
				}
			}
			return (j == subLength) ? i - subLength : -1;
			
		}
		//如果捕捉到异常,参与比较的两个字符串不合法
		catch (Exception e) {
     
			System.out.println("参与比较的字符串非法!!!");
		}
		return -1;
	}
	
	/**
	 * 在主串中找到子串出现的所有位置,找到返回位置数组
	 * 否则返回null
	 * @return
	 */
	public int [] getMatchValueArray() {
     
		try {
     
			int mainLength = mainStr.length();
			int subLength = subStr.length();
			//如果主串长度小于子串长度,不可能匹配到
			if(mainLength < subLength) {
     
				return null;
			}
			
			int i = 0;//主串指针
			int j = 0;//子串指针
			while(i < mainLength && j < subLength) {
     
				if(mainStr.charAt(i) == subStr.charAt(j)) {
     
					i++;
					j++;
				}
				else if(j != 0) {
     
					j = match[j - 1] + 1;
				}
				else {
     
					i++;
				}
			}
		}
		//如果捕捉到异常,参与比较的两个字符串不合法
		catch (Exception e) {
     
			System.out.println("参与比较的字符串非法!!!");
		}
		return null;
	}
	
	public  int[] getMatch() {
     
		return match;
	}

	public  void setMatch(int[] match) {
     
		this.match = match;
	}

	public  String getMainStr() {
     
		return mainStr;
	}

	public void setMainStr(String mainStr) {
     
		this.mainStr = mainStr;
	}

	public String getSubStr() {
     
		return subStr;
	}

	public void setSubStr(String subStr) {
     
		this.subStr = subStr;
	}
}
	public void setMainStr(String mainStr) {
     
		this.mainStr = mainStr;
	}

	public String getSubStr() {
     
		return subStr;
	}

	public void setSubStr(String subStr) {
     
		this.subStr = subStr;
	}
}

你可能感兴趣的:(数据结构,笔记,算法,数据结构)