数据结构学习笔记——串

  • 串是一种特殊的线性表,数据元素之间呈线性关系
  • 串的数据对象限定为字符集(如中文字符、英文字符、数字字符、标点字符等

定义

顺序存储

静态存储

typedef struct {//静态存储
    char ch[MAXLEN];
    int len;
}SString;

ch赋值需要用strcpy

  strcpy(st.ch, "linjunjie");

动态存储

typedef struct {//动态存储
    char* ch;//按串的长度分配存储区,ch指向串的基地址
    int length;
}HString;

链式存储

低密度

typedef struct StringNode {//一个结点一个字符(低密度)
    char ch;
    struct StringNode* next;
}StringNode, * String;

高密度

typedef struct StringNode{//一个结点多个字符(高密度)
    char ch[4];
    struct StringNode* next;
}StringNode ,*String;

基本操作(串中首元素元素不存放字符)

求子串

bool SubString(SString &Sub,SString S,int pos,int len)//求子串。用sub返回串s的第pos个字符起长度为len的字串

bool SubString(SString &Sub,SString S,int pos,int len)//求子串。用sub返回串s的第pos个字符起长度为len的字串
{
    if (pos + len - 1 > S.len)return 0;//字串越界返回0
    for (int i = pos; i < pos + len; i++)
        Sub.ch[i - pos + 1] = S.ch[i];
    Sub.len = len;
    return 1;
}

比较操作

int StrCompare(SString S, SString T)//比较操作。若S>T 则返回值>0 若S=T则返回值=0 若S

//比较操作。若S>T 则返回值>0 若S=T则返回值=0 若S
int StrCompare(SString S, SString T)
{
    for (int i = 1; i < S.len && i < T.len; i++)
    {
        if (S.ch[i] != T.ch[i])
            return S.ch[i] - T.ch[i];
    }
    //扫描过的所有字符都相同 则长度长的串更大
    return S.len - T.len;
}

定位操作

int Index(SString S, SString T)//定位操作。若主串S中存在与T值相同的子串,则返回它在主串s中第一次出现的位置;否则函数值为0.

//定位操作。若主串S中存在与T值相同的子串,则返回它在主串s中第一次出现的位置;否则函数值为0.
int Index(SString S, SString T)
{
    int i = 1, n = S.len, m = T.len;
    SString sub;//用于暂存字串
    while (i <= n - m + 1)
    {
        SubString(sub, S, i, m);
        if (StrCompare(sub, T) != 0)i++;
        else return i;//返回子串在主串中的位置
    }
    return 0;//S中不存在与T相等的子串
}

朴素模式匹配算法

//朴素模式匹配算法(字符串空出首元素)
让主串的所有子串与模式串依次匹配,匹配成功返回位置

int Index(SString S,SString T)
{
    int k = 1;
    int i = k, j = 1;
    while (i <= S.len && j <= T.len)
    {
        if (S.ch[i] == T.ch[j])
        {
            i++;
            j++;
        }
        else
        {
            k++;
            i = k;
            j = 1;
        }
    }
    if (j > T.len)return k;
    else return 0;
}

KMP算法

解决朴素模式匹配算法模式串指针回溯问题

思想:“利用已经部分匹配这个有效信息,保持i指针不回溯,通过修改j指针,让模式串尽量地移动到有效的位置。”

//KMP算法(字符串首元素为空)
int Index_KMP(SString S, SString T, int next[])
{
    int i = 1, j = 1;
    while (i <= S.len && j <= T.len)
    {
        if (j == 0 || S.ch[i] == T.ch[i])
        {
            i++;
            j++;//继续比较后继字符
        }
        else
            j = next[j];//模式串向右移
    }
    if (j > T.len)return i - T.len;//匹配成功
    else return 0;
}

平均时间复杂度O(n+m) n为主串长度 m为模式串长度

求模式串的next数组

串的前缀:包含第一个字符,且不包含最后一个字符的子串
串的后缀:包含最后一个字符,且不包含第一个字符的子串

当第j个字符匹配失败时,由前1~j-1个字符组成的串记为s,则:
next[j]= s的前缀与后缀最长重复数k+1
别的,next[1]=0 `
前后缀不匹配next值为1

求模式串next数组代码

//求模式串的next数组
void get_next(SString T, int next[])
{
    int i = 1, j = 0;
    next[1] = 0;
    while (i < T.len)
    {
        if (j == 0 || T.ch[i] == T.ch[j])
        {
            i++;
            j++;
            //若pi=pj,则next[j+1]=next[j]+1
            next[i] = j;
        }
        else
            j = next[j];
    }
}

时间复杂度O(m) (m为模式串的长度)

KMP算法优化

优化为nextval数组
从j = 2开始依次判断Pnext是否等于Pnext[j] 是的话将next [j]修正为next [next [j]]直至者不相等为止

//优化的nextval数组
void  get_nextval(SString T,int nextval[])
{
    int i = 1,j = 0;
    nextval[1] = 0;
    while (i < T.len)
    {
        if (j == 0 || T.ch[i] == T.ch[j])
        {
            i++;
            j++;
            if (T.ch[i] != T.ch[j])
                nextval[i] = j;
            else j = nextval[j];
        }
    }
}

你可能感兴趣的:(笔记,学习,数据结构,字符串)