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. 最大公共子序列(Runtime faster than 92.73% of Python3)

    其中的算法思想只是较为简单的动态规划,过去各种各样的考试写过很多次C/C++版本的,最近开始用Python做leetcode中的题目时遇到了该题目,很常规的做法竟然得到了意想不到的速度,但内存占用较差 ...

  2. Java面向对象程序设计第5章1-9

    1.面向对象的主要特征是什么? 三大特征是:封装.继承和多态. 封装:是指将某事物的属性和行为包装到对象中,这个对象只对外公布需要公开的属性和行为,而这个公布也是可以有选择性的公布给其它对象. 继承: ...

  3. Matlab 图论最短路问题模型代码

    最短路问题的基本内容 最短路问题研究的是,在一个点与点之间连接形成的网络图中,对应路径赋予一定的权重(可以理解为两点之间的距离),计算任意两点之间如何和走,路径最短的问题.在这里的距离可以理解成各种两 ...

  4. BOM之本地数据存储

    JavaScript中本地存储数据常用的,且兼容性较好的有两种方式,cookie和Storage.另外还可以使用location.hash临时存储少量关键信息. 一    location.hash ...

  5. thymeleaf自定义标签方言处理

    项目背景:springboot+thymeleaf thymeleaf两种方式处理自定义标签:AbstractAttributeTagProcessor 和 AbstractElementTagPro ...

  6. 代码审计之SQL注入及修复

    在新手入门web安全的时候,sql注入往往是最先上手的一个漏洞,它也是危害相当大的一个漏洞,存在此漏洞的话,将有被脱裤的风险. 以下所有代码都是我自己写的,可能有不美观,代码错误等等问题,希望大家可以 ...

  7. 删除pdf中的链接

    在Acrobat中打开pdf文件,然后:编辑→首选项→一般→自动从文本检测URL,把此处的对勾去掉,以后就不会变为食指按的形状了! 还有以下的方法 方法1:“高级(A)”→“链接(L)”→“删除文档中 ...

  8. ELK搭建实时日志分析平台

    ELK搭建实时日志分析平台 导言 ELK由ElasticSearch.Logstash和Kiabana三个开源工具组成,ELK平台可以同时实现日志收集.日志搜索和日志分析的功能.对于生产环境中海量日志 ...

  9. Hbase入门(三)——数据模型

    Hbase最核心但也是最难理解的就是数据模型,由于与传统的关系型数据库不同,虽然Hbase也有表(Table),也有行(Row)和列(Column),但是与关系型数据库不同的是Hbase有一个列族(C ...

  10. 站内搜索(ELK)之数据目录

    在使用elasticsearch建设站内搜索时,随着数据不断丰富,为了数据管理更加精细化,必须建立并实时维护“数据目录”(在程序设计中对应的叫法“数据字典”). 数据目录需要包含以下几个维度:数据名称 ...