1、顺序串

实现的操作有:

  1. 构造串
  2. 判断空串
  3. 返回串的长度
  4. 返回位序号为i的字符
  5. 将串的长度扩充为newCapacity
  6. 返回从begin到end-1的子串
  7. 在第i个字符之前插入字串str
  8. 删除子串

  在实现返回位序号从begin到end-1的子串时,注意,此处串的起始位置为0,同时为了方便,我们再次没有新建一个变量,而是返回一个string,可以直接输出,在main函数中可以看到。

  通过string.indexof()函数将字符数组转化为字符串。

  同时在实现每个字符串的操作之前,先进行异常处理,避免出现越界现象。

curlen:表示当前字符串的长度

str:使用字符数组存放串值

 package Main;
/*串的操作
* */
public class Main{
public char[] str; //使用字符数组存放串值
public static int curlen; //当前字符串的长度
public Main()
{
str = new char[0];
curlen = 0;
}
//以字符串常量构造串
public Main(String string)
{
char[] a = string.toCharArray();
str = a;
curlen = a.length;
}
//以字符数组构造串
public Main(char [] astr)
{
str = new char[astr.length];
for(int i=0;i<astr.length;i++)
{
str[i] = astr[i];
}
curlen = str.length;
}
//将串变为空串
public void clear()
{
curlen = 0;
}
//判断是否为空串
public boolean isEmpty()
{
return curlen==0;
}
//返回串的长度
public int length()
{
return curlen;
}
//返回位序号为i的字符
public char charAt(int i)
{
System.out.println(curlen);
if(i<0 || i>=curlen)
throw new StringIndexOutOfBoundsException(i);
return str[i];
}
//将串的长度扩充为newCapacity
public void allocate(int newCapacity) {
char [] tmp = str;
str = new char[newCapacity];
for(int i=0;i<tmp.length;i++)
{
str[i] = tmp[i];
}
}
//返回位序号从begin到end-1的子串,注意,此处串的起始位置为0;
public String subString(int begin,int end)
{
if(begin<0||begin>=end||end>curlen)
throw new StringIndexOutOfBoundsException("the parameter is illegal!");
char []tmp = new char[end-begin];
for(int i=begin;i<end;i++)
{
tmp[i-begin] = str[i];
}
return String.valueOf(tmp);
} //在第i个字符之前插入字串str
public void insert(int i,String aString)
{
if(i<0||i>curlen)
throw new StringIndexOutOfBoundsException("the inserted location is illegal");
int len = aString.length();
int newcapacity = len + curlen;
allocate(newcapacity); //重新分配存储空间
for(int j=curlen-1;j>=i;j--) //移动数据元素
{
str[j+len] = str[j];
} for(int j=i;j<i+len;j++)
{
str[j] = aString.charAt(j-i);
} }
//删除操作
public void delete(int begin,int end)
{
if(begin<0||end>curlen||begin>=end)
throw new StringIndexOutOfBoundsException("the parameter is illegal!");
for(int i=begin;i<end-1;i++)
{
str[i] = str[i+end-begin];
}
curlen = curlen-end+begin;
}
//打印字符串
public void print()
{
for(int i=0;i<str.length;i++)
{
System.out.print(str[i]);
}
System.out.println();
}
public static void main(String[] args) {
Main aMain = new Main("hello world");
String aString = "thank you";
System.out.println(curlen);
System.out.println("if the string is empty:"+aMain.isEmpty());
System.out.println("the length of this string:"+aMain.length());
System.out.print("the character of the serial number betweent one and three is :");
System.out.println(aMain.subString(1, 4));
aMain.print();
aMain.insert(2, aString);
aMain.print(); }
}

2、BF算法

  属于暴力破解字符串匹配问题,将所有的情况遍历一边,所用的时间复杂度比较大,个人偏向于后面的KMP算法。

(1)外层一个循环指示主串的指针,内层一个for循环用于指示模式串,j作为模式串指针从零开始,至模式串的长度。

(2)分为两种情况:

  • 如果当前字符不匹配,则跳出循环,继续读取主串的下一个字符,即i++;
  • 如果匹配完毕,则j = len(模式串长度)-1,则输出结果
 public static void BF(String aString,String bString)
{
int i = 0,j = 0;
int len_a = aString.length();
int len_b = bString.length();
while(i<=len_a-len_b)
{
for(j=0;j<len_b;j++)
{
if(bString.charAt(j)!=aString.charAt(j+i))
{
i++;
break;
}else if(j==len_b-1){ System.out.println("BF algorithm:"+i);
return ;
}
}
}
System.out.println("matching failed!");
}

3、KMP算法

该算法的主要思想为当某次匹配失败时主串的开始比较位置不回退,而是利用部分字符匹配的结果将模式串向右移动较远的距离后再进行比较

算法分析:

(1)  K值的计算,即计算next[]值,此处作用于模式串本身,和主串无关

  • 初始时设next[0] = -1,next[1] = 0,k=0,j=1;
  • 设next[j] = k ,则p0p1p2....pk-1 = pj-kpj-k+1pj-k+2......pj-1,注意,此处直到k-1和j-1处,k为满足该等式的最大值,此时计算next[j+1]的值
    • 若pk = pj ,则存在p0p1p2....pk = pj-kpj-k+1pj-k+2......pj,此时next[j+1] = k+1;
    • 若pk ≠ pj,则把计算next[j]的值的问题看做新的模式匹配过程,主串为P,模式串为P的前缀子串
      • 出现不匹配时,应该将模式串的比较位置变为k' = next[k],若pj = pk',则next[j+1] = k'+1 = next[k] + 1
      • 否则继续执行上述步骤,直到pj = pk .或者当k=0且pj≠pk时,next[j+1] = 0;
 public int[] next(String p)
{
int []next = new int[p.length()]; //next[]数组
int k=0; //模式串指针
int j=1; //主串指针
next[0] = -1;next[1] = 0;
while(j<p.length()-1)
{
if(p.charAt(j)==p.charAt(k))
{
next[j+1] = k+1;
j++;
k++;
}else if (k==0) {
next[j+1] = 0;
j++;
}else
k = next[k];
}
return next;
}

(2)  KMP算法步骤

  • 计算模式串的next[]的值
  • i为主串的比较字符位序号,j为模式串的比较字符串位序号。当字符相等时,i,j分别加1后继续比较,否则i的值不变,j = next[j],继续比较
  • 特殊情况,当j = =0时,i++,主串字符位开始移动;
  • 重复步骤2,直到j等于模式串的长度是匹配成功,否则匹配失败
public int KMP(String s,String p)
{
int []next = next(p);
int j=0,i=0;
while(i<s.length()&&j<=p.length())
{
if(j==-1||s.charAt(i)==p.charAt(j))
{
i++;
j++;
}else if(j==0)
{
i++;
}else {
j = next[j];
}
if(j==p.length())
return i-p.length();
}
return -1;
}

(3)应用

主串为s = “abcabccabc” , 模式串为t = "bcc";

分别使用BF算法和KMP算法实现

 package Main;

 import java.util.Scanner;

 /*串的操作
* */
public class Main{
public char[] str;
public int cur;
public static void BF(String aString,String bString)
{
int i=0,j=0;
int len_a = aString.length();
int len_b = bString.length();
while(i<=len_a-len_b)
{
for(j=0;j<len_b;j++)
{
if(aString.charAt(i+j)!=bString.charAt(j)) //如果不匹配则跳出循环,继续读取原字符串的下一个字符
{
i++;
break;
}else if (j==len_b-1) //匹配完毕
{
System.out.println("BF algorithm:"+i);
return ;
}
}
}
System.out.println("The string matching failed!!");
}
//KMP算法第一步,求解next值
public static int[] next(String bString)
{
int []next = new int[bString.length()];
next[0] = -1;
next[1] = 0;
int k=0;
int j=1;
int len = bString.length();
while(j<len-1)
{
if(bString.charAt(k)==bString.charAt(j))
{
next[j+1] = k+1;
k++;
j++; }else if(k==0)
{
next[j+1] = 0;
j++;
}else {
k = next[k];
}
}
return next;
}
//KMP算法第二步,匹配位置
public static void KMP(String aString,String bString)
{
int []next = next(bString);
int i=0;
int j=0;
while(i<aString.length()&&j<bString.length())
{
if(j==-1||aString.charAt(i)==bString.charAt(j))
{
i++;
j++;
}else if(j==0)
{
i++;
}else {
j = next[j];
} }
if(j==bString.length())
{
System.out.println("KMP algorithm:"+(i-bString.length()));
}
} public static void main(String[] args) {
Scanner aScanner = new Scanner(System.in);
//可输入四次
int i=4;
String aString,bString;
while(i!=0) {
System.out.println("Please input the main String:");
aString = aScanner.next();
System.out.println("Please input a String to match:");
bString = aScanner.next();
BF(aString,bString);
KMP(aString,bString);
i--;
} }
}

数据结构4_java---顺序串,字符串匹配算法(BF算法,KMP算法)的更多相关文章

  1. 字符串匹配算法——BF、KMP、Sunday

    一:Brute force 从源串的第一个字符开始扫描,逐一与模式串的对应字符进行匹配,若该组字符匹配,则检测下一组字符,如遇失配,则退回到源串的第二个字符,重复上述步骤,直到整个模式串在源串中找到匹 ...

  2. 字符串匹配算法BF和KMP总结

    背景 来看一道leetcode题目: Implement strStr(). Returns the index of the first occurrence of needle in haysta ...

  3. 数据结构- 串的模式匹配算法:BF和 KMP算法

      数据结构- 串的模式匹配算法:BF和 KMP算法  Brute-Force算法的思想 1.BF(Brute-Force)算法 Brute-Force算法的基本思想是: 1) 从目标串s 的第一个字 ...

  4. 数据结构学习之字符串匹配算法(BF||KMP)

    数据结构学习之字符串匹配算法(BF||KMP) 0x1 实验目的 ​ 通过实验深入了解字符串常用的匹配算法(BF暴力匹配.KMP.优化KMP算法)思想. 0x2 实验要求 ​ 编写出BF暴力匹配.KM ...

  5. 字符串模式匹配算法--BF和KMP详解

    1,问题描述 字符串模式匹配:串的模式匹配 ,是求第一个字符串(模式串:str2)在第二个字符串(主串:str1)中的起始位置. 注意区分: 子串:要求连续   (如:abc 是abcdef的子串) ...

  6. 数据结构与算法--KMP算法查找子字符串

    数据结构与算法--KMP算法查找子字符串 部分内容和图片来自这三篇文章: 这篇文章.这篇文章.还有这篇他们写得非常棒.结合他们的解释和自己的理解,完成了本文. 上一节介绍了暴力法查找子字符串,同时也发 ...

  7. 算法 kmp算法

    kmp算法是改进后的字符匹配算法,它与bf算法的区别是,每次从串与主串匹配失败后,从串与主串匹配的位置不同. 下面具体说下这两种算法的区别: 主串:BABCDABABCDABCED 从串:ABCDAB ...

  8. 笔记-算法-KMP算法

    笔记-算法-KMP算法 1.      KMP算法 KMP算法是一种改进的字符串匹配算法,KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的.具体实现就是实现一 ...

  9. 值得花费一周研究的算法 -- KMP算法(indexOf)

    KMP算法是由三个科学家(kmp分别是他们名字的首字母)创造出来的一种字符串匹配算法. 所解决的问题: 求文本字符串text内寻找第一次出现字符串s的下标,若未出现返回-1. 例如 text : &q ...

  10. 经典算法 KMP算法详解

    内容: 1.问题引入 2.暴力求解方法 3.优化方法 4.KMP算法 1.问题引入 原始问题: 对于一个字符串 str (长度为N)和另一个字符串 match (长度为M),如果 match 是 st ...

随机推荐

  1. Android Studio 3.1.3填坑之路

      昨天编写程序的时候,遇到了一个非常令人头疼的BUG,如下图:   标题栏和里面的内容都消失了,这对于一个非常在乎排版的软件来说简直就是晴空霹雳,搞了好长时间,终于在今天找到解决方法,原来是升级搞的 ...

  2. 使用dbutils

    环境准备: 包结构: mysql导出sql脚本: //product CREATE TABLE `product` ( `id` int(10) NOT NULL AUTO_INCREMENT, `n ...

  3. redis的安装和pip连接

    一.首先说说我的环境.         操作系统:Ubuntu16.04         能联网(使用了桥接方式)   二.安装redis cd进一个文件夹. 控制台输入     weget http ...

  4. springboot之全局处理统一返回

    springboot之全局处理统一返回 简介 在REST风格的开发中,避免通常会告知前台返回是否成功以及状态码等信息.这里我们通常返回的时候做一次util的包装处理工作,如:Result类似的类,里面 ...

  5. Maven 梳理 - Maven中的dependencyManagement 意义

    1.在Maven中dependencyManagement的作用其实相当于一个对所依赖jar包进行版本管理的管理器. 2.pom.xml文件中,jar的版本判断的两种途径 1:如果dependenci ...

  6. java时间格式转换任意格式

    例如:20180918/120023转换成2018-09-18 12:00:23 //时间格式转换 public String getNomalTime(String oldTime){ String ...

  7. 架构——android架构演进概述

    随着业务的发展和技术的变更,Android开发也经历了以下几个发展阶段: 看似高大上的名词,其实遵循着最简单的原则:分而治之(如何划分就是"架构",简单的事情如何串在一起就是&qu ...

  8. Scala XML

    XML 直接在代码中使用 XML 字面量 val doc: Elem = <html><head><title>Test</title></hea ...

  9. php常用函数(第一版)

    1.array_slice 作用:数组分页函数 案例:$output  =  array_slice ( $input , - 2 ,  1 ); 2.array_column 作用:数组根据值取出一 ...

  10. java架构之路-(面试篇)JVM虚拟机面试大全

    下文连接比较多啊,都是我过整理的博客,很多答案都在博客里有详细说明,理解记忆是最扎实的记忆.而且我的答案不一定是最准确的,但是我的答案不会让你失望,而且几乎每个答案都是问题的扩展答案. 1.JVM内存 ...