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. jar包部署到window系统服务器的办法

    1:把jar包和lib(如果打包出现有lib目录)放在同级目录 2:windows服务器安装jdk等 3:通过bat批处理命令或者 cmd命令启动jar包,其中之一就可以 3.1:bat命令如下: @ ...

  2. 54 (OC)* 网络七层架构

    一:TCP/IP协议 二:七层协议 1:物理层 物理层为设备之间的数据通信提供传输媒体及互连设备,为数据传输提供可靠的环境.  1.1:传输媒体和互连设备        物理层的媒体包括架空明线.平衡 ...

  3. Docker学习之Dockerfile

    通过编写简单的文件创建docker镜像 dockerfile 用来创建docker镜像. 格式 : FROM alpine:latest MAINTAINER XSW CMD echo "h ...

  4. idea 安装 lombok插件

    一,前言 lombok是什么?lombak是一个工具,主要用来简化,减少代码的编写.使代码看起来更清晰,简洁. 而且lombok只是一个工具,不会打包到war中,不会增加任何消耗.只是在编译期中帮助我 ...

  5. ajax发送PUT请求,使用HttpPutFormContentFilter过滤器接受办法

    相信在使用ajax发送put请求时候,肯定遇到过后端数据无法被接受到的405错误. 为什么会遇到这个问题? 1.首先查看Tomcat源码 关于如何将数据封装到Request public class ...

  6. hadoop之mapreduce详解(基础篇)

    本篇文章主要从mapreduce运行作业的过程,shuffle,以及mapreduce作业失败的容错几个方面进行详解. 一.mapreduce作业运行过程 1.1.mapreduce介绍 MapRed ...

  7. 手把手教你用最简便的方法免费安装SSL

    原文链接:小枫同学的个人博客 随时IT的发展,它几乎涵盖了世界发展中的任何一方面,几乎都和计算机挂钩,也有好多小伙伴想开一个自己的网站,分享一些知识,分享一些心情等等.但是随着IT的发展,网络安全也越 ...

  8. 基于python的scrapy环境搭建

    0.1安装python软件 32位机的电脑安装python-3.6.3.exe 64位机的电脑安装python-3.6.3-amd64.exe 0.1.1 python环境搭建 执行安装程序 选择Ad ...

  9. C# 事件 Event

    一.事件是什么 微软的定义:和委托类似,事件是后期绑定机制. 实际上,事件是建立在对委托的语言支持之上的.事件是对象用于(向系统中的所有相关组件)广播已发生事情的一种方式. 任何其他组件都可以订阅事件 ...

  10. for for in 给已有的li绑定click事件生成新的li也有click事件

    想要给已有的li元素绑定一个click事件,点击生成新的li元素,并且新的li元素也要有click事件 //不能用for循环给每个li绑定click事件 因为这样的话 后面新生成的li就没有click ...