《大话数据结构》----串-----String字符串匹配算法---BF

串(String)是由零个或者多个字符组成的有序序列,又名叫字符串
空格串 :是只包含空格的串,注意它和空串的区别,空格串是有长度的,而且可以不止一个空格.
子串与主串,串中任意个数的连续字符组成的子序列称为该串的子串,相应地,包含子串的串称为主串
子串在主串的位置就是子串的第一个字符在主串中的序号

存储

数组和链表都能存
不过实际来看链表弊端很明显,一个字符对应一个节点,就会存在很大的空间浪费,若是存放多个字符,又考虑多少个问题,这都会影响串处理的效率,但是在连接串与串操作方便

总的来说:顺序存储灵活,性能比链表存储结构好

匹配BF算法

含义

BF (Brute Force) 的缩写,就是暴力算法,拆开字符一个个比较,通俗易懂,符合常理和第一反应,当然效率肯定慢啊,都暴力算法了.
截图君上场,简单介绍一下暴力算法,知道的可以直接忽略

《大话数据结构》----串-----String字符串匹配算法---BF_第1张图片
《大话数据结构》----串-----String字符串匹配算法---BF_第2张图片

时间复杂度

这个时间复杂度算起来也挺有意思的,故单独敲敲文字过一遍,主要查找的时候有特殊情况,会影响到时间复杂度的计算
设:主串为m,子串为n,

  1. 最好的情况:当然是一下就找到啊,字符串主串mabcdefg和子串nabc,查找的次数一轮就通过为3次,根据大O时间复杂度计算1(<—不知道点这个1脚注),即为O(n)
  2. 稍微差点的情况: 例如代码的例子,O(主串+子串),即O(m+n),因为所有字符都要一个个匹配,在遍历m的基础上,再加上n
  3. 最坏的情况: 例如000000000001001,这种情况,每个字符都要匹配3次,001三个长度,直到匹配第三个1的时候,才发现不是,所以时间复杂度是前面的匹配长度乘以后面的长度,这样一来时间复杂度O(n*(m-n+1)),一般实际使用时m >> n,所以可以认为趋近于O(m*n)

代码

package com.company;

/**
 * @Author: comfort
 * @Date: 2020/8/4
 */
public class StringTest {

    public static void main(String[] args) {
        String source = "abcdefghijklmn";
        String look = "jkl";
        System.out.println(BF(source, look));


    }
  
    /**
     * BF暴力检索
     * @param source  原字符串
     * @param lookupStr  要查找的字符串
     * @return  成功返回下标,否则-1
     */
    public static int BF(String source,String lookupStr){

		//初始化从0开始的下标
        int souIndex=0;
        int lookIndex=0;
        //转化char根据字符一一查找
        char[] sourceChar = source.toCharArray();
        char[] lookChar = lookupStr.toCharArray();

        //思路 :判断时,要已两个字符的下标长度为条件
        while (souIndex<sourceChar.length&&lookIndex<lookChar.length ){
            System.out.println(souIndex+" "+sourceChar[souIndex]+"  "+lookIndex+"  "+lookChar[lookIndex] );
            //两个字母相等
            if (sourceChar[souIndex] == lookChar[lookIndex]) {
                souIndex++;
                lookIndex++;
            }else{
                //找不到  回退
                //如果当前字符匹配不成功,则souIndex回溯到此次匹配最开始的位置+1处,也就是
                //souIndex = souIndex - lookIndex + 1
                souIndex=souIndex-lookIndex+1;
                lookIndex=0;
            }

        }
        if (lookIndex == lookChar.length) {
            return souIndex - lookIndex;
        }
        return -1;

    }
}

输出

0 a  0  j
1 b  0  j
2 c  0  j
3 d  0  j
4 e  0  j
5 f  0  j
6 g  0  j
7 h  0  j
8 i  0  j
9 j  0  j
10 k  1  k
11 l  2  l
9

当然,如果字符串不存在,一直会检索所有(13次)

比如我输入lmc时,主串一直从头运行到最后,最后返回-1

0 a  0  l
1 b  0  l
2 c  0  l
3 d  0  l
4 e  0  l
5 f  0  l
6 g  0  l
7 h  0  l
8 i  0  l
9 j  0  l
10 k  0  l
11 l  0  l
12 m  1  m
13 n  2  c
12 m  0  l
13 n  0  l
-1

收获

  • 第一次敲看着简单,撇到一边对着屏幕自己敲真有点费劲,敲过一遍就好多了
  • while循环条件和初始化index比较重要,书中写的是从1开始,故重置算法是i=i-j+2,看的我云里雾里,自己翻了资料,发现初始化index0开始比较符合思路.
  • 重置步骤i=i-j+1这行代码比较直接给出来了,其实自己找个纸画画,目的就是j=0时,让i变回上一次开始的位置,多举两三个例子,就发现了ij之间的关系.
  • 最后的返回下标,两个数字相减是可以倒推出来,也是看资料太直接了.最好动动脑.

其他:这篇有点水文字了…本来想和KMP算法写在一起,发现kmp篇幅太长,在kmp算法的基础,还是分开写.酱紫吧.

参考资料:

字符串模式匹配算法系列(一):BF算法


  1. 推导大O阶:1. 用常数1取代运算时间中的所有加法常数 2. 在修改后的运行数次中,只保留最高阶.3. 如果最高阶项存在且不是1,则去除与这个项的常数 ↩︎

你可能感兴趣的:(数据结构)