数据结构 —— 串

串、串长、空串、空格串、子串、主串、字符在主串中的位置、子串在主串中的位置

一、串的基本操作

存储结构为:定长顺序存储

1.1 赋值操作

StrAssign(&T, chars) : 串T赋值为chars

SString StrAssign(SString &T, char *chars){ 
	int i = 0;
	while(chars[i] != '\0'){
		T.ch[i] = chars[i];
		i++;
	}
	T.length = i;
	return T;
} 

1.2 复制操作

StrCopy(&T, S) : 串S复制得到串T

SString StrCopy(SString &T, SString S){
	for(int i=0; i<S.length; i++)
		T.ch[i] = S.ch[i];
		
	T.length = S.length;
	return T; 
} 

1.3 判空操作

StrEmpty(S) : 串S为空,返回TRUE,否则返回FALSE

bool StrEmpty(SString S){
	if(S.length == 0)
		return true;
	else
		return false;
}

1.4 求串长

StrLength(S) : 返回串S的元素个数

int StrLength(SString S){
	return S.length;
} 

1.5 清空操作

ClearString(&S) : 串S清为空串

bool ClearString(SString &S){
	S.length = 0;
	return true;
} 

1.6 销毁串

DestroyString(&S) : 销毁串S,即回收存储空间

1.7 串连接

Concat(&S, T) : S返回由串S和串T连接成的新串

bool Concat(SString &S, SString T){
	// 插入后总串长 <= MAXLEN
    if(S.length + T.length <= MAXLEN){	
    	for(int i=S.length; i<S.length+T.length; i++)
    		S.ch[i] = T.ch[i-S.length]; 
				
		S.length = S.length + T.length;
		return true;
	}else{
		return false;
	}
} 

1.8 求子串 ⭐

SubString(&Sub, S, pos, len) : Sub返回串S的第pos个字符起长度为len的子串

// 使用定长顺序存储
bool SubString(SString &Sub, SString S, int pos, int len){
    // 子串越界
    if(pos<0 || pos+len-1 > S.length)
        return false;
    
    for(int i=pos; i<pos+len; i++)
        Sub.ch[i-pos+1] = S.ch[i];
    
    Sub.length = len;
    return true;
}

1.9 串比较操作 ⭐

StrCompare(S, T) : 若S>T,则返回值 > 0;若S=T,则返回值 = 0;若S<T,则返回值 < 0

int StrCompare(SString S, SString T){
    for(int i=0; i<=S.length && i<=T.length; i++){
        if(S.ch[i] != T.ch[i])
            return S.ch[i] - T.ch[i];
    }
    // 扫描过所有字符都相同,则字符串长度大的更大
    return S.length - T.length;
}

1.10 定位操作 ⭐

Index(S, T) : 若主串S中存在与串T值相同的子串,则返回它在主串S中第一次出现的位置;否则函数值为0

int Index(SString S, SString T){
    int i=0, n=StrLength(S), m=StrLength(T);
    SString sub;
    while(i <= n-m){
        SubString(sub,S,i,m);		// 获取S中的长度为m的子串
        if(StrCompare(sub,T) != 0)	// 比较子串与串T
            i++;
        else
            return i;				// 找到则返回子串在主串S中的位置
    }
    return -1;		// 主串S中不存在与串T相等的子串
}

1.11 串插入操作

StrInsert(S, pos, T) : 在串S中第pos位前插入串T

int StrInsert(SString S, int pos, SString T){
    if(pos<0 || pos > S.length)		// 插入位置不合法
        return 0;
    if(S.length + T,length <= MAXLEN)
}

1.12 串删除操作

StrDelete(&S, pos, len) : 删除串S中自pos位起的len个字符

bool StrDelete(SString &S, int pos, int len){
	if(pos<0 || pos>S.length-len)		// 删除位置不合法
        return false;
        
    for(int i=pos+len; i<S.length; i++)
    	S.ch[i-len] = S.ch[i];
    
	S.length -= len;
    return true;
} 

1.13 输出串

void PrintString(SString S){
	for(int i=0; i<S.length; i++){
		cout<<S.ch[i]; 
	}
    printf("\n");
}

二、串的存储结构

2.1 定长顺序存储(静态数组)

#define MAXLEN 255		// 预定义最大串长为255
typedef struct{
    char ch[MAXLEN];	// 每个分量存储一个字符
    int length;			// 串的实际长度
}SString;

📌 tips:

王道书中采用 静态数组存储结构

ch[0] 废弃不用,ch[1] 开始,最后变量length存储长度

2.2 堆分配存储(动态数组)

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

HString S;
S.ch = (char *) malloc(MAXLEN * sizeof(char));	// 用完需手动free
S.length = 0;

2.3 链式存储

typedef struct StringNode{
    char ch[4];		// 每个结点可存多个字符
    struct StringNode *next;
}StringNode, *String;

三、字符串的模式匹配

3.1 朴素模式匹配算法

主串长度为n,模式串长度为m
朴素模式匹配算法:将主串中 所有长度为m的子串 依次与模式串对比,直到找到一个完全匹配的子串,或所有子串都不匹配为止。(最多有 n-m+1 个子串) —> 即 Index(S, T) 定位操作

// 另一方法:直接利用下标
int Index(SString S, SString T){
    int i=1, j=1;
    while(i<=S.length && j<=T.length){
        if(S.ch[i] == T.ch[j]){	// 继续比较下一个字符
            ++i;
            ++j;
        }else{
            i = i-j+2;
            j = 1;		// 重新开始匹配
        }
    }
    
    if(j>T.length)
        return i-T.length;	// 匹配成功,返回子串位置
    else
        return 0;		// 没找到
}

最坏时间复杂度 = O((n-m+1)m) = O(nm) (一般n>>m)

3.2 KMP算法

KMP算法:先预处理:根据模式串T,求出next数组;—> 利用next数组进行匹配(主串指针不回溯)
​ next数组只和短短的模式串有关,和长长的主串无关(掌握手算即可)

next数组作用:当模式串的第j个字符失配时,从模式串的第 next[j] 的继续往后匹配;
对任何模式串,其**next[1] = 0; next[2] = 1;** 例:模式串 google ,其next数组如下:

next数组next[0]next[1]next[2]next[3]next[4]next[5]next[6]
j011121
int Index_KMP(SString S, SString T, int next[]){
    int i=1, j=1;
    while(i<=S.length && j<=T.length){
        if(j==0 || S.ch[i] == T.ch[j]){	// 继续比较下一个字符
            ++i;
            ++j;
        }else{
            j = next[j];		// 重新开始匹配
        }
    }
    
    if(j>T.length)
        return i-T.length;	// 匹配成功,返回子串位置
    else
        return 0;		// 没找到
}

最坏时间复杂度 = O(m + n);

求next数组时间复杂度O(m); 模式匹配过程最坏时间复杂度O(n)

3.2.1 next数组的优化

序号j123456
模式串ababaa
next[j]011234
nextval[j]010104
// 先求next数组,再由next数组求nextval数组
nextval[1] = 0;
for(int j=2; j<=T.length; j++){
    // 模式串中第j个  <--对应-->  next[j]所指模式串中字符
    if(T.ch[j] == T.ch[next[j]])	// 如j=4,b <--> next[4]=2,j=2,b 字符相等
        nextval[j] = nextval[next[j]];
    else
        nextval[j] = next[j];
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值