文章目录
一、串
1、定义
零个
或多个
字符组成的有限序列;- 空串:零个字符的串;
- 空格串:
只
包含空格;- 字串:
任意
个数的连续
字符组成的子序列;
2、串的比较
通过ASCII编码来比较
3、朴素的模式匹配算法
模式匹配:字串的定位操作;
时间复杂度:O(n+m)
。
4、KMP的模式匹配算法
大大
避免重复
遍历的情况。
5、串的相关代码说明
5.1 初始化堆字符串
/*@ 初始化堆字符串 */
void Init_HeapString(HString *str)
{
str->ch = NULL;
str->length = 0;
}
将字符串指针赋值为
NULL
以及长度清零
。
5.2 字符串赋值
/*@ 字符串赋值 */
Status Assignstr_Headpstring(HString *str, char * newStr)
{
int i;
int len = GetLength_Heap(newStr); // 获取新字符串的长度
if (!len){
return ERROR;
}
Init_HeapString(str); // 初始化
str->ch = (char *)malloc(sizeof(char)* len);
if (!str->ch){
return ERROR;
}
for (i = 0; i < len; ++i)
{
str->ch[i] = newStr[i];
}
str->length = len;
return OK;
}
赋值前需要先将该str
初始化
,通过GetLength_Heap
函数或者字符串的长度,相应长度的堆空间申请
。在进行赋值。
5.3 获取字符串的长度
/*@ 获取字符串的长度 */
int GetLength_Heap(char *Str)
{
int len = 0;
while (Str[len] != '\0')// 字符串结束为\0
{
len++;
}
return len;
}
将变量循环加一,直至字符等于
\0
结束。
5.4 复制字符串
/*@ 复制字符串 */
Status CopyStr_Heap(HString *destStr, HString *srcStr){
Init_HeapString(destStr); // 初始化字符
if (isEmpty(srcStr)){ // 若源字符串为空,则不能复制
printf("该源字符串为空,不能进行复制...");
return ERROR;
}
destStr->ch = (char*)malloc(sizeof(srcStr) * srcStr->length);// 申请空间
if (!destStr->ch){
return ERROR; // 是否申请成功
}
int i = 0;
for (i; i < srcStr->length; ++i){
destStr->ch[i] = srcStr->ch[i]; // 赋值给新的字符串
}
destStr->length = srcStr->length; // 将长度赋值给新的字符串
return OK;
}
初始化
destStr
,申请空间,字符串赋值。
5.5 字符串拼接
/*@ 字符串拼接 将destStr的字符串拼接到srcStr上 */
Status ConcatStr_Heap(HString *destStr, HString *Str1, HString *Str2){
Init_HeapString(destStr); // 初始化
destStr->length = Str1->length + Str2->length;
destStr->ch = (char *)malloc(sizeof(char)* destStr->length);
if (!destStr->ch){
exit(OVERFLOW);
}
int i;
for (i = 0; i < Str1->length; ++i){
destStr->ch[i] = Str1->ch[i];
}
for (i = 0; i < Str2->length; ++i){
destStr->ch[Str1->length+i] = Str2->ch[i];
}
return OK;
}
初始化
destStr
,先将Str1
赋值到destStr
,在将Str2
赋值到destStr
上。
5.6 比较俩个字符串
/*@ 比较俩个字符串 相等-0;大于正数;小于负数*/
Status StrCompare_Heap(HString *str1, HString *str2){
int i = 0;
for (i; i < str1->length && str2->length; ++i){
if (str1->ch[i] != str2->ch[i]){ // 当俩个字符不相等时,即判断ASCII的大小
return str1->ch[i] - str2->ch[i];
}
}
return str1->length - str2->length; // 若字符相等,则判断长度
}
通过循环判断字符串的
ASCII的大小
,若都相等则在判断长度
。
5.7 截取字符串
/*@ 截取字符串 */
Status SubString_Heap(HString *destStr, HString *srcStr, int pos, int len){
if (srcStr->length == 0 || len == 0 || len + pos - 1 > srcStr->length || pos < 1
|| pos > srcStr->length || len < 0){
return ERROR;
}
Init_HeapString(destStr);
destStr->ch = (char *)malloc(sizeof(char)* len);
if (!destStr->ch) exit(OVERFLOW);
int i;
for (i = 0; i < len; ++i){
destStr->ch[i] = srcStr->ch[pos + i -1];
}
destStr->length = len;
return OK;
}
初始化
destStr
,通过循环将pos
位置后len
长度的字符串截取到destStr
,注意长度等前提条件。
5.8 索引子串位置
/*@ 返回从pos位置开始的子串在父串中的位置 */
int Indexchild_Heap(HString *srcStr, HString *child, int pos){
if (pos < 0) return ERROR;
HString *subStr = (HString *)malloc(sizeof(HString));
Init_HeapString(subStr);
int i = pos;
while (i + child->length - 1 <= srcStr->length){ // 循环判断长度是否大于主串
SubString_Heap(subStr, srcStr, i, child->length); // 截取字符串
if (StrCompare_Heap(subStr, child) == EQ){ // 判断字串和截取的字符串是否相等
return i;
}else{
i++;
}
}
free(subStr);
return 0;
}
循环从srcStr
截取child长度的字符串
与child字符串比较
若相等则返回该索引。
5.9 字符串插入
/*@ 字符串插入 */
Status InsertStr_Heap(HString *srcStr, HString *insertSrc, int pos){
if (isEmpty(srcStr) || isEmpty(insertSrc)) return ERROR;
if (pos < 1 || pos > srcStr->length + 1) return ERROR;
srcStr->length += insertSrc->length;
srcStr->ch = (char *)realloc(srcStr->ch, (srcStr->length)*sizeof(char));
int i;
// 腾出空间
for (i = srcStr->length -1; i > pos - 1; --i){
srcStr->ch[i] = srcStr->ch[i-insertSrc->length];
}
for (i = 0; i < insertSrc->length; ++i){
srcStr->ch[i+ pos - 1] = insertSrc->ch[i];
}
return OK;
}
获取
插入字符串的长度
,对srcStr进行空间重新申请
。将srcStr中pos到末尾的字符串向后移动
,在将insertSrc字符串插入
。
5.10 删除字符串
/*@ 从pos开始删除len长度的字符 */
Status DeleteStr_Heap(HString *srcStr, int pos, int len){
if (isEmpty(srcStr)) return ERROR;
if (len<0 || len + pos - 1> srcStr->length || pos < 1){
return ERROR;
}
int i;
for (i = pos - 1; i < srcStr->length - len; ++i){
srcStr->ch[i] = srcStr->ch[len + i];
}
srcStr->length -= len;
srcStr->ch = (char *)realloc(srcStr->ch, srcStr->length * sizeof(char));// 重新分配空间
return OK;
}
将pos位置开始len长度后的字符串
往pos的位置赋值
。在重新分配空间
。
5.11 替换字符
/*@ 替换字符 */
Status ReplaceStr_Heap(HString *str, HString oldStr, HString newStr){
if (isEmpty(str) || isEmpty(str)) return ERROR;
int pos = Indexchild_Heap(str, &oldStr, 1);
while (pos != 0)
{
pos = Indexchild_Heap(str, &oldStr, 1);
DeleteStr_Heap(str, pos, oldStr.length);
InsertStr_Heap(str, &newStr, pos);
}
return OK;
}
获取oldStr在str中的位置,使用
DeleteStr_Heap
将他删除,在使用InsertStr_Heap
对它进行插入。
5.12 暴风算法返回子串在主串中的位置
/*@ 使用暴风算法返回子串在主串中的位置 */
int BFIndex_Heap(HString *destStr, HString *child, int pos){
int i = pos, j = 1;
while (i <= destStr->length - 1 && j <= child->length){
if (destStr->ch[i - 1] == child->ch[j - 1]){
j++;
i++;
}
else{
i = i - j + 2;
j = 1;
}
}
if (j>child->length){
return i - child->length;
}
return 0;
}
循环判断destStr与child是否相等,若不相等则
i不回溯
,直接接着下一个字符开始。
5.13 KMP算法
/*@ 获取next数组保存子串的前缀与后缀的最长匹配【部分匹配表】 */
Status GetNext_Heap(HString *srcStr, int *next){
int j = -1, i = 0;
next[0] = j;
while (i < srcStr->length){
if (j == -1 || srcStr->ch[i] == srcStr->ch[j]){
++i;
++j;
next[i] = j;
}else{
j = next[j];
}
}
return OK;
}
/*@ KMP算法 */
int KMPIndex_Heap(HString *destStr, HString *child, int pos){
int next[255];
GetNext_Heap(destStr, next);
int i = pos - 1;
int j = 0;
while (i < destStr->length - 1 && j < child->length){
if (j == -1 || destStr->ch[i] == child->ch[j]){
++j;
++i;
}else{
j = next[j];
}
}
if (j == child->length){
return i + 1 - child->length;
}
return 0;
}
先获取前缀与后缀的最长匹配,通过
next来获取
子串的下一个索引位置
。
5.14 打印字符串
/*@ 打印字符串 */
void PPrint_Heap(HString *str){
if (!str->ch || str->length == 0){
printf("堆中字符串为空!\n");
return;
}
int i = 0;
printf("字符串为:");
for (i; i < str->length; ++i){
printf("%c", str->ch[i]);
}
printf("\n");
}
5.15 判断是否为空
/*@ 判断是否为空 */
Status isEmpty(HString *str)
{
if (str->length == 0 || !str->ch){
return TRUE;
}
return FALSE;
}
5.16 释放空间
/*@ 释放空间 */
void Destroy_HeapString(HString *str){
if (str->ch != NULL){
free(str->ch);
str->ch = NULL;
str->length = 0;
printf("字符串已销毁...\n");
}
}
6、完整代码
main
#include<stdio.h>
#include<stdlib.h>
#include "SeqString.h"
#include "MyStatusLib.h"
void test(){
HString Str;
Assignstr_Headpstring(&Str, "ABCDE"); // 字符串赋值
int len = GetLength_Heap("ABCDE");
printf("获取字符串长度:%d\n", len);
HString copyStr;
CopyStr_Heap(©Str, &Str);
printf("复制后的");
PPrint_Heap(©Str); // 打印字符串
HString conCatStr;
ConcatStr_Heap(&conCatStr, ©Str, &Str);
printf("拼接后的");
PPrint_Heap(&conCatStr); // 打印字符串
int status = StrCompare_Heap(&conCatStr, ©Str);
printf("比较结果为:");
if (status > 0){
printf("大于\n");
}
else if (status < 0){
printf("小于\n");
}
else{
printf("等于\n");
}
HString subStr;
SubString_Heap(&subStr, &Str, 2, 2);
printf("截取的");
PPrint_Heap(&subStr);
int pos = Indexchild_Heap(&conCatStr, &Str, 3);
printf("子串在父串的位置:%d\n", pos);
InsertStr_Heap(&Str, &subStr, 2);
printf("插入后的");
PPrint_Heap(&Str);
DeleteStr_Heap(&Str, 2, 2);
printf("删除后");
PPrint_Heap(&Str);
HString oldStr, newStr;
Assignstr_Headpstring(&oldStr, "D");
Assignstr_Headpstring(&newStr, "S");
ReplaceStr_Heap(&Str, oldStr, newStr);
printf("替换后");
PPrint_Heap(&Str);
HString BStr, FStr;
Assignstr_Headpstring(&BStr, "ASSSBD");
Assignstr_Headpstring(&FStr, "SB");
int x = BFIndex_Heap(&BStr, &FStr, 2);
int y = KMPIndex_Heap(&BStr, &FStr, 2);
printf("BF 算法:%d\nKMP算法:%d\n", x, y);
Destroy_HeapString(&Str); // 销毁字符串
}
int main(){
test();
system("pause");
return OK;
}
SeqString.cpp
#include "SeqString.h"
/*@ 初始化堆字符串 */
void Init_HeapString(HString *str)
{
str->ch = NULL;
str->length = 0;
}
/*@ 字符串赋值 */
Status Assignstr_Headpstring(HString *str, char * newStr)
{
int i;
int len = GetLength_Heap(newStr); // 获取新字符串的长度
if (!len){
return ERROR;
}
Init_HeapString(str); // 初始化
str->ch = (char *)malloc(sizeof(char)* len);
if (!str->ch){
return ERROR;
}
for (i = 0; i < len; ++i)
{
str->ch[i] = newStr[i];
}
str->length = len;
return OK;
}
/*@ 获取字符串的长度 */
int GetLength_Heap(char *Str)
{
int len = 0;
while (Str[len] != '\0')// 字符串结束为\0
{
len++;
}
return len;
}
/*@ 复制字符串 */
Status CopyStr_Heap(HString *destStr, HString *srcStr){
Init_HeapString(destStr); // 初始化字符
if (isEmpty(srcStr)){ // 若源字符串为空,则不能复制
printf("该源字符串为空,不能进行复制...");
return ERROR;
}
destStr->ch = (char*)malloc(sizeof(srcStr) * srcStr->length);// 申请空间
if (!destStr->ch){
return ERROR; // 是否申请成功
}
int i = 0;
for (i; i < srcStr->length; ++i){
destStr->ch[i] = srcStr->ch[i]; // 赋值给新的字符串
}
destStr->length = srcStr->length; // 将长度赋值给新的字符串
return OK;
}
/*@ 字符串拼接 将destStr的字符串拼接到srcStr上 */
Status ConcatStr_Heap(HString *destStr, HString *Str1, HString *Str2){
Init_HeapString(destStr); // 初始化
destStr->length = Str1->length + Str2->length;
destStr->ch = (char *)malloc(sizeof(char)* destStr->length);
if (!destStr->ch){
exit(OVERFLOW);
}
int i;
for (i = 0; i < Str1->length; ++i){
destStr->ch[i] = Str1->ch[i];
}
for (i = 0; i < Str2->length; ++i){
destStr->ch[Str1->length+i] = Str2->ch[i];
}
return OK;
}
/*@ 比较俩个字符串 相等-0;大于正数;小于负数*/
Status StrCompare_Heap(HString *str1, HString *str2){
int i = 0;
for (i; i < str1->length && str2->length; ++i){
if (str1->ch[i] != str2->ch[i]){ // 当俩个字符不相等时,即判断ASCII的大小
return str1->ch[i] - str2->ch[i];
}
}
return str1->length - str2->length; // 若字符相等,则判断长度
}
/*@ 截取字符串 */
Status SubString_Heap(HString *destStr, HString *srcStr, int pos, int len){
if (srcStr->length == 0 || len == 0 || len + pos - 1 > srcStr->length || pos < 1
|| pos > srcStr->length || len < 0){
return ERROR;
}
Init_HeapString(destStr);
destStr->ch = (char *)malloc(sizeof(char)* len);
if (!destStr->ch) exit(OVERFLOW);
int i;
for (i = 0; i < len; ++i){
destStr->ch[i] = srcStr->ch[pos + i -1];
}
destStr->length = len;
return OK;
}
/*@ 返回从pos位置开始的子串在父串中的位置 */
int Indexchild_Heap(HString *srcStr, HString *child, int pos){
if (pos < 0) return ERROR;
HString *subStr = (HString *)malloc(sizeof(HString));
Init_HeapString(subStr);
int i = pos;
while (i + child->length - 1 <= srcStr->length){ // 循环判断长度是否大于主串
SubString_Heap(subStr, srcStr, i, child->length); // 截取字符串
if (StrCompare_Heap(subStr, child) == EQ){ // 判断字串和截取的字符串是否相等
return i;
}else{
i++;
}
}
free(subStr);
return 0;
}
/*@ 字符串插入 */
Status InsertStr_Heap(HString *srcStr, HString *insertSrc, int pos){
if (isEmpty(srcStr) || isEmpty(insertSrc)) return ERROR;
if (pos < 1 || pos > srcStr->length + 1) return ERROR;
srcStr->length += insertSrc->length;
srcStr->ch = (char *)realloc(srcStr->ch, (srcStr->length)*sizeof(char));
int i;
// 腾出空间
for (i = srcStr->length -1; i > pos - 1; --i){
srcStr->ch[i] = srcStr->ch[i-insertSrc->length];
}
for (i = 0; i < insertSrc->length; ++i){
srcStr->ch[i+ pos - 1] = insertSrc->ch[i];
}
return OK;
}
/*@ 从pos开始删除len长度的字符 */
Status DeleteStr_Heap(HString *srcStr, int pos, int len){
if (isEmpty(srcStr)) return ERROR;
if (len<0 || len + pos - 1> srcStr->length || pos < 1){
return ERROR;
}
int i;
for (i = pos - 1; i < srcStr->length - len; ++i){
srcStr->ch[i] = srcStr->ch[len + i];
}
srcStr->length -= len;
srcStr->ch = (char *)realloc(srcStr->ch, srcStr->length * sizeof(char));// 重新分配空间
return OK;
}
/*@ 替换字符 */
Status ReplaceStr_Heap(HString *str, HString oldStr, HString newStr){
if (isEmpty(str) || isEmpty(str)) return ERROR;
int pos = Indexchild_Heap(str, &oldStr, 1);
while (pos != 0)
{
pos = Indexchild_Heap(str, &oldStr, 1);
DeleteStr_Heap(str, pos, oldStr.length);
InsertStr_Heap(str, &newStr, pos);
}
return OK;
}
/*@ 使用暴风算法返回子串在主串中的位置 */
int BFIndex_Heap(HString *destStr, HString *child, int pos){
int i = pos, j = 0;
while (i <= destStr->length - 1 && j <= child->length){
if (destStr->ch[i - 1] == child->ch[j - 1]){
j++;
i++;
}
else{
i = i - j + 2;
j = 1;
}
}
if (j>child->length){
return i - child->length;
}
return 0;
}
/*@ 获取next数组保存子串的前缀与后缀的最长匹配【部分匹配表】 */
Status GetNext_Heap(HString *srcStr, int *next){
int j = -1, i = 0;
next[0] = j;
while (i < srcStr->length){
if (j == -1 || srcStr->ch[i] == srcStr->ch[j]){
++i;
++j;
next[i] = j;
}else{
j = next[j];
}
}
return OK;
}
/*@ KMP算法 */
int KMPIndex_Heap(HString *destStr, HString *child, int pos){
int next[255];
GetNext_Heap(destStr, next);
int i = pos - 1;
int j = 0;
while (i < destStr->length - 1 && j < child->length){
if (j == -1 || destStr->ch[i] == child->ch[j]){
++j;
++i;
}else{
j = next[j];
}
}
if (j == child->length){
return i + 1 - child->length;
}
return 0;
}
/*@ 打印字符串 */
void PPrint_Heap(HString *str){
if (!str->ch || str->length == 0){
printf("堆中字符串为空!\n");
return;
}
int i = 0;
printf("字符串为:");
for (i; i < str->length; ++i){
printf("%c", str->ch[i]);
}
printf("\n");
}
/*@ 判断是否为空 */
Status isEmpty(HString *str)
{
if (str->length == 0 || !str->ch){
return TRUE;
}
return FALSE;
}
/*@ 释放空间 */
void Destroy_HeapString(HString *str){
if (str->ch != NULL){
free(str->ch);
str->ch = NULL;
str->length = 0;
printf("字符串已销毁...\n");
}
}
MyStatusLib.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#ifdef __cplusplus
extern"C"{
#endif
#define ERROR 0
#define OK 1
#define TRUE 1
#define FALSE 0
#define EQ 0
#define GT 1
#define LT -1
/*@ 堆栈溢出*/
#ifndef _STATUS_H_ // 若系统中有定义以下状态码,就不用定义
#define OVERFLOW -2
#define UNDERFLOW -3
#endif
typedef int Status; // 自定义状态码
#ifdef __cplusplus
}
#endif
SeqString.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include "MyStatusLib.h"
#define MAX_SIZE 1024
#ifdef __cplusplus
extern "C"{
#endif
/*@ 串的堆式顺序存储结构(Heap) */
typedef struct{
char *ch;
int length;
}HString;
/*@ 初始化堆字符串 */
void Init_HeapString(HString *str);
/*@ 字符串赋值 */
Status Assignstr_Headpstring(HString *str, char * newStr);
/*@ 获取字符串的长度 */
int GetLength_Heap(char *Str);
/*@ 复制字符串 */
Status CopyStr_Heap(HString *destStr, HString *srcStr);
/*@ 字符串拼接 */
Status ConcatStr_Heap(HString *destStr, HString *Str1, HString *Str2);
/*@ 比较俩个字符串 相等-0;大于正数;小于负数*/
Status StrCompare_Heap(HString *str1, HString *str2);
/*@ 截取字符串 */
Status SubString_Heap(HString *destStr, HString *srcStr, int pos, int len);
/*@ 返回从pos位置开始的子串在父串中的位置 */
int Indexchild_Heap(HString *dest, HString *child, int pos);
/*@ 从pos开始删除len长度的字符 */
Status DeleteStr_Heap(HString *srcStr, int pos, int len);
/*@ 字符串插入 */
Status InsertStr_Heap(HString *srcStr, HString *insertSrc, int pos);
/*@ 替换字符 */
Status ReplaceStr_Heap(HString *str, HString oldStr, HString newStr);
/*@ 使用暴风算法返回子串在主串中的位置 */
int BFIndex_Heap(HString *destStr, HString *child, int pos);
/*@ 获取next数组 */
Status GetNext_Heap(HString *srcStr, int *next);
/*@ KMP算法 */
Status KMPIndex_Heap(HString *srcStr, HString *child, int pos);
/*@ 判断是否为空 */
Status isEmpty(HString *str);
/*@ 打印字符串 */
void PPrint_Heap(HString *str);
/*@ 释放空间 */
void Destroy_HeapString(HString *str);
#ifdef __cplusplus
}
#endif
end😁