zoukankan      html  css  js  c++  java
  • 数据结构与算法(4)--串

    定义

    字符串简称串,是一种特殊的线性表,它的数据元素仅由一个字符组成。

    串(String)是由零个或多个字符组成的有限序列

    [s=' a_1a_2cdots a_n ' ]

    • 串的长度: 一字符串中,字符的个数
    • 空串: 长度为零的字符串
    • 空格串(blank string):由一个或多个空格组成的串
    • 串相等:是指两个串的长度相等且对应的字符都相等
    • 子串: –串中任意连续的字符组成的子序列称为该串的子串
    • 主串:包含子串的串称为该子串的主串
    • 模式匹配: 子串的定位运算又称为模式匹配,是一个求子串的队医给字符在主串中序号的运算。被匹配的主串称为目标串,子串称为模式。

    表示和实现

    因为串是数据元素类型为字符型的线性表,所以用于线性表的存储方式仍适合与串。但是由于串中的数据元素是单个字节,其存储方式又有其特殊之处。

    定长顺序存储

    类似于线性表,可以用一组地址连续的存储单元依次存放串中的各个字符序列,利用存储单元地址的顺序表示串中字符的相邻关系

    定长存储的C语言描述

    #define MAXLEN 10
    typedef struct
    {
    	char vec[MAXLEN];
    	int len;
    } Str;//可用Str来定义该类型的结构体变量
    

    特点:

    • 为串变量分配一个预定义、固定长度的存储区
    • 实际串长度保存在数组下标=0的位置
    • 表示串值的终结

    串的顺序结构示意图

    存储方式

    当计算机按字节(Byte)为单位便地址时,一个存储单元刚好存储一个字符,串中相邻的字符顺序地存储在地址相邻的存储单元中.

    当计算机按字(例如1字32位)为单位便地址时,一个存储单元可以有4个字节组成。此时顺序存储结构又有非紧凑格式紧凑格式两种存储方式。

    紧凑与非紧凑格式

    1)非紧凑格式

    S=“String Structure”,计算机字长为32位(4个Byte),使用非紧凑格式一个地址只能存储一个字符,如图5-1所示。优点是运算处理简单,但缺点是存储空间十分浪费。

    2)紧凑格式
    同样存储S=“String Structure”,使用紧凑格式格式一个地址能存四个字符,如图5-2所示。紧凑存储的优点是空间利用率高,缺点是对串中字符处理的效率低。

    块链存储

    对于长度不确定的字符串的输入,若采用定长字符串存储就会产生这样的问题:存储空间定的大,而实际输入字符串长度小,则造成内存空间的浪费,反之,存储空间定的小,而实际输入字符串长度大,则存储空间不够用。此时可采用链接存储的方法。

    用链表存储字符串,每个结点有两个域:一个是数据域(data)和一个指针域(next)。

    其中数据域(data)–存储串中的字符。指针域(next)–存放后继结点的地址

    以存储S=“String Structure” 为例,链式存储结构如图所示。

    链式存储字符串例子

    优缺点:

    • 链式存储的优点–插入、删除运算方法;
    • 链式存储的缺点==存储,检索效率较低。

    由于字符串的特殊性,用链表存作为字符串的存储方式也不太实用,因此使用较少。

    堆分配存储

    在实际应用中,往往要定义很多字符串,并且各字符串长度在定义之前又无法确定。在这种情况下,可以采用堆分配存储(也称为索引存储),这是一种动态存储结构。

    堆分配存储的方法

    1. 开辟一块地址连续的存储空间,用于存储各串的值,该存储空间称为"堆"(也称自由存储区)
    2. 另外建立一个索引表,用来存储串的名称(name),长度(length)和该串在"堆"中存储的起始地址(Start)。
    3. 程序执行过程中,每产生一个串,系统就从"堆"中分配一快大小与串的长度相同的连续的空间,用于存储该串的值,并且在索引表中增加一个索引项,用于登记该串的名称、长度、和该串的起始地址。

    索引存储的例子

    设字符串:

    A=“Red”
    B=“Yellow”
    C=“Blue”
    D=“White”
    

    用指针free指向堆中的未使用空间的首地址。索引表如图5-5所示

    字符串堆存储索引案例

    考虑到对字符串的插入和删除操作,可能引起字符串的长度变化,在“堆”中为串值的分配空间是,可预留适当的空间。这时,索引表的索引项应增加一个域,用于存储该串在“堆”中拥有的实际存储单元的数量。当字符串长度等于该串的实际存储单元时,就不能对串进行插入操作。

    带长度的索引表的C语言描述:

    #define MAXLEN 10
    typedef struct
    {
    	char name[MAXLEN];//串名
    	int length;//串长
    	char *Stradr;//起始地址
    } LNode 
    

    串的比较

    比较方式

    通过组成串的字符的编码进行比较。字符编码,即字符在对应字符集中的符号。

    串相等条件:

    1. 串长度相等
    2. 对应位置的字符相等

    常用计算机字符编码

    • 标准ASCII码:7位二进制=1个字符、可表示(2^7=128)个字符
    • 扩展ASCII码:8位二进制=1个字符、可表示(2^8=256)个字符
    • Unicode编码:16位二进制=1个字符、可表示(2^16)个字符、为了兼容ASCII码,Unicode码的前256个字符与ASCII码相同

    串的模式匹配

    子串的定位操作通常称作串的模式匹配(其中T称为模式串)

    朴素模式匹配算法

    朴素的意思就是最符合咱们朴素思维的算法,从主串的第一个字符开始与子串进行比对,如果相等则逐一比对后续字符;如果不等则从主串第二个字符开始匹配子串,直到发现全部相等的子串。

    KMP模式匹配算法

    KMP模式匹配算法详解

    核心思想:

    1. 利用已对比的主串&子串的信息,控制子串j值的变化
    2. 从而减少不必要的回溯 字符串的比对(i值不回溯,仅回溯j值),从而提高效率

    作用:

    • 避免了朴素模式匹配算法中没必要的循环回溯字符串的对比

    特点:

    • 由于i值不回溯,仅回溯j值,效率高
    • (总时间复杂度=O(m) + O(n) = O(m+n)) 比 朴素模式匹配算法好: (O((n - m + 1) * m))

    应用场景:

    • 当子串与主串存在较多"部分匹配"的情况下

    具体算法

    概念:字符串的前缀&后缀

    概念 定义 实例
    前缀 除了最后1个字符,一个字符串的全部头部组合 s="abcd" 前缀:’a‘, 'ab', 'abc'
    后缀 除了第1个字符外,一个字符串的全部尾部组合 s="abcd" 后缀:'b', 'bc', 'bcd'

    具体使用:

    1. 计算出子串(T串)各个位置的 j 值的变化
    2. 根据步骤1计算出的next数组,将子串与主串进行模式匹配

    KMP模式匹配算法

  • 相关阅读:
    django-替代为自定义的User model
    python *args 和 ** kwargs
    MySQL:性能优化
    MySQL:常用的数据模型
    MySQL:存储过程和函数
    MySQL:用户管理
    MySQL:索引
    MySQL:基础知识
    Linux:NFS配置
    Linux:Apache安装与启动
  • 原文地址:https://www.cnblogs.com/pankypan/p/13976262.html
Copyright © 2011-2022 走看看