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. springboot之全局处理异常封装

    springboot之全局处理异常封装 简介 在项目中经常出现系统异常的情况,比如NullPointerException等等.如果默认未处理的情况下,springboot会响应默认的错误提示,这样对 ...

  2. 2019年研究生数学建模D题《汽车行驶工况构建》解析

    正在整理...

  3. 使用Spring中的PropertyPlaceholderConfigurer读取文件

    目录 一. 简介 二. XML 方式 三. Java 编码方式 一. 简介 大型项目中,我们往往会对我们的系统的配置信息进行统一管理,一般做法是将配置信息配置与一个cfg.properties 的文件 ...

  4. 排列组合算法的Java实现

    转载于:http://cgs1999.iteye.com/blog/2327664

  5. [Leetcode][动态规划] 第935题 骑士拨号器

    一.题目描述 国际象棋中的骑士可以按下图所示进行移动:                           我们将 “骑士” 放在电话拨号盘的任意数字键(如上图所示)上,接下来,骑士将会跳 N-1 步 ...

  6. 2019年十大开源WEB应用防火墙点评

    2019年十大开源WEB应用防火墙点评 随着WEB应用的爆炸式成长和HTTPS加密的普及,针对网络应用层的攻击,像SQL注入.跨站脚本攻击.参数篡改.应用平台漏洞攻击.拒绝服务攻击等越来越多,传统的防 ...

  7. 从ASP.Net Core Web Api模板中移除MVC Razor依赖项

    前言 :本篇文章,我将会介绍如何在不包括MVC / Razor功能和包的情况下,添加最少的依赖项到ASP.NET Core Web API项目中. 一.MVC   VS WebApi (1)在ASP. ...

  8. 如何增强VR的vection/self-motion?

    上一节讲到了vection是给玩家带来“移动感”的因素,它提供良好VR体验的关键之一.那么VR中我们一般用哪些方式来提供vection呢?1 首先来简单了解一下人体和空间相关的感知机制. 视觉线索 v ...

  9. Django学习之文件下载

    在实际的项目中很多时候需要用到下载功能,如导excel.pdf或者文件下载,当然你可以使用web服务自己搭建可以用于下载的资源服务器,如nginx,这里我们主要介绍django中的文件下载. 我们这里 ...

  10. 排坑日记之批量从库IO进程停止

    早上刚睁眼,看到了一堆数据库告警的短信,其中一个内容如下: Problem started at 05:02:58 on 2019.10.12 Problem name: Slave is stopp ...