数据结构之串

文章介绍了串的定义,包括顺序存储结构和链式存储结构及其优缺点。重点讨论了串的模式匹配问题,提到了Brute-Force(BF)算法和KMP算法,详细阐述了这两种算法的工作原理和实现代码,并分析了它们的时间复杂度。
摘要由CSDN通过智能技术生成
1.串的基本概念

• 一个串是由n(n≥0)个字符组成的有限序列,记为s=“s0s1 ⋯ sn-1”,其
中,s是串名,双引号括起来的字符序列s0s1 ⋯ sn-1是串值。
• 一个字符在串中的位置称为该字符在串中的序号,约定串第一个字符
的序号为0。
• 由串s中任意连续字符组成的子序列称为s的子串,s称为主串。 空串是任意串的子串; 任意串都是它自身的子串;除自身外,串的其他子串称为其真子串。
• 子串的序号是指该子串首字符在主串中的序号。
• 两个串相等是指,串长度相同且对应位置上的字符也相同。

2.串的存储结构

(1) 串的顺序存储结构
采用字符数组将串中的字符序列依次存储在数组的相邻单元中。
在这里插入图片描述
顺序串具有随机存取特性,存取指定位置字符的时间复杂度为O(1);
缺点是插入、删除时需要移动数据元素,平均移动数据量是串长度
的一半,插入、删除操作的时间复杂度为O(n)。
(2)串的链式存储结构
串的链式存储结构有单字符链表和块链表两种,如下图所示。
在这里插入图片描述
链式存储的串,存取指定位置字符的时间复杂度为O(n);
单字符链表虽然插入删除操作不需要移动数据元素,但占用存储空间太
多;块链表的插入和删除操作需要移动元素,效率较低。

3.串的模式匹配

定义:设有两个串目标串target和模式串pattern,在目标串target中查找
与模式串pattern相等的一个子串并确定该子串位置的操作称为串的模式
匹配(Pattern Matching)。
匹配结果有两种:如果target中存在与pattern相等的子串,则匹配成
功,获得该子串在target中的位置;否则匹配失败,给出失败信息。

4.模式匹配算法

(1)Brute-Force(BF)算法
BF算法的基本思想是蛮力匹配,即从目标串target的每一 个字符开始依次与模式串pattern的字符进行比较。
(2)KMP算法
KMP算法是一种无回溯的模式匹配算法,它改进了BF算法,目标串不回溯。

5.BF算法描述与实现
 public int indexOf(MyString pattern, int begin) {
        int n = this.length(), m = pattern.length();
        if (begin < 0) //对begin容错,若begin<0,从0开始
            begin = 0;
        if (n == 0 || n < m || begin >= n) //若目标串空、较短或begin越界,不需比较
            return -1;
        int i = begin, j = 0; //i、j分别为目标串和模式串当前字符下标
        int count = 0; //记载比较次数
        while (i < n && j < m) {
            count++;
            if (this.charAt(i) == pattern.charAt(j)) //若当前两字符相等,则继续比较后续字符
            {
                i++;
                j++;
            } else //否则i、j回溯,进行下次匹配
            {
                i = i - j + 1; //目标串下标i,退回到下个匹配子串序号
                j = 0; //模式串下标j,退回到0
                if (i > n - m) //若目标串剩余子串的长度<m,不再比较
                    break;
            }
        }
    }
5.1BF算法算法分析

在这里插入图片描述

6.KMP算法描述与实现
 public static int indexOf(String target, String pattern, int begin)
    {
        int n=target.length(), m=pattern.length();
        if (begin<0) //对begin容错,若begin<0,从0开始
            begin = 0;
        if (n==0 || n<m || begin>=n) //若目标串空、较短或begin越界,不需比较
            return -1;
        next = getNext(pattern); //返回模式串pattern的next数组
        int i=begin, j=0; //i、j分别为目标串、模式串比较字符下标
        while (i<n && j<m)
        {
            if (j==-1 || target.charAt(i)==pattern.charAt(j))
            //若当前两字符相等,则继续比较后续字符
            {
                i++;
                j++;
            }
            else //否则,下次匹配,目标串下标i不回溯
            {
                j=next[j]; //模式串下标j退回到下次比较字符序号
                if (n-i+1<m-j+1) //若目标串剩余子串的长度不够,不再比较
                    break;
            }
        }
        if (j==m) //匹配成功
            return i-j; //返回匹配的子串序号
        return -1; //匹配失败
    }
6.1 计算next数组

KMP算法充分利用前一次匹配的比较结果,由next[j]逐个递推计算得到
next[j+1]。说明如下:
(1)约定next[0]=-1,-1表示下次匹配从ti+1与p0开始比较;有next[1]=0。
(2)如果pk=pj,即”p0…pk-1pk”=“pk-j…pj-1pj”,存在相同的前后缀子串,长度为k+1,则下一个字符pj+1的next[j+1]=k+1=next[j]+1。
例如:”abcabc”,已求得next[4]=1(j=4,k=1),此时p3=p0=‘a’,而p4=p1=‘b’,则”p3p4”=“p0p1”,所以next[5]=next[4]+1=2。
(3)如果pk≠pj,在”p0…pj”中寻找较短的前后缀子串,较短前后缀子串的长度为next[k],则k=next[k];再比较pj与pk,继续执行,寻找相同的前后缀子串。

在这里插入图片描述

 private static int[] getNext(String pattern) 
 //返回模式串pattern的next数组
    {
        int j=0, k=-1, next[]=new int[pattern.length()];
        next[0]=-1;
        while (j<pattern.length()-1)
            if (k==-1 || pattern.charAt(j)==pattern.charAt(k))
            {
                j++;
                k++;
                next[j]=k;
            }
            else k=next[k];
        return next;
    }
5.2 KMP算法分析

KMP算法的最好情况同BF算法,比较次数为m,时间复杂
度为O(m);
最坏情况,比较次数为n,算法的时间复杂度为O(n)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值