目录
一、串的基本操作
1 . 静态数组实现(定长顺序存储)
#include <iostream>
#include <string.h>
using namespace std;
#define MAXLEN 255//预定义最大串长 255
typedef struct {
//静态数组实现(定长顺序存储)
char ch[MAXLEN];//每个分量存储一个字符
int length;//串的实际长度
} SString;
//初始化
bool InitString(SString &S) {
S.length = 0;
return true;
}
//赋值操作 把串T赋值为 chars
bool StrAssign(SString &T, const char *chars) {
if(strlen(chars) > MAXLEN) {
return false;
}
for (int i = 1; i <= strlen(chars); i++) {
T.ch[i] = chars[i - 1];
T.length++;
}
return true;
}
//复制操作 由串S复制得到T
bool StrCopy(SString &T, SString S) {
for(int i = 1; i <= S.length; i++) {
T.ch[i] = S.ch[i];
T.length++;
}
return true;
}
//判空操作 空返回true 非空则false
bool StrEmpty(SString S) {
if(S.length == 0) {
return true;
}
return false;
}
//若s>t 返回>0 s==t 返回=0 s<t 返回<0
int StrCompare(SString S, SString T) {
for (int i = 1; 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;
}
//返回串长
int StrLength(SString S) {
return S.length;
}
//求子串 用sub返回串s的第pos个位置开始的长度为len的串
bool SubString(SString &Sub, SString S, int pos, int len) {
if(pos + len - 1 > S.length || pos < 1 || pos > 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;
}
//字符串拼接 用T返回由S1和S2连接的新串
bool Concat(SString &T, SString S1, SString S2) {
if(S1.length + S2.length > MAXLEN) { //字符串拼接会被截断
for (int i = 1; i <= S1.length ; i++) {
T.ch[i] = S1.ch[i];
}
for (int i = 1; i <= MAXLEN - S1.length ; i++) {
T.ch[S1.length + i] = S2.ch[i];
}
T.length = MAXLEN;
return false;
} else { //字符串拼接不会被截断
for (int i = 1; i <= S1.length ; i++) {
T.ch[i] = S1.ch[i];
}
for (int i = 1; i <= S2.length ; i++) {
T.ch[S1.length + i] = S2.ch[i];
}
T.length = S1.length + S2.length ;
return true;
}
}
//返回串T在S中第一次出现的位置 不存在返回0
int Index(SString S, SString T) {
int i = 1, n = StrLength(S), m = StrLength(T);
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相等的字串
}
//清空操作
bool ClearString(SString &S) {
S.length = 0;
return true;
}
//打印串
bool showString(SString S) {
if(StrEmpty(S)) {
return false;
}
for (int i = 1; i <= S.length; i++) {
cout << S.ch[i];
}
cout << endl;
return true;
}
void test() {
SString S1;
InitString(S1);
if(StrEmpty(S1)) {
cout << "S1 Is Empty!" << endl;
} else {
cout << "S1 Isn't Empty!" << endl;
}
StrAssign(S1, "SString");
showString(S1);
SString S2;
InitString(S2);
StrCopy(S2, S1);
showString(S2);
cout << "StrCompare(S1, S2): " << StrCompare(S1, S2) << endl; // =0
cout << "StrLength(S1): " << StrLength(S1) << endl;
cout << "StrLength(S2): " << StrLength(S2) << endl;
//求字串,用 Sub返回 串S 的第 pos 个位置开始的长度为 len 的串
SString Sub;
InitString(Sub);
SubString(Sub, S1, 2, 4);
showString(Sub);
SString T;
InitString(T);
Concat(T, S1, S2);
showString(T);
// //返回 串Sub 在 S1 中第一次出现的位置,不存在返回0
cout << "Index(S1, Sub):" << Index(S1, Sub) << endl;
ClearString(S1);
cout << "StrLength(S1):" << StrLength(S1) << endl;
}
int main() {
test();
return 0;
}
1-1 代码运行结果![](https://img-blog.csdnimg.cn/20210902170426929.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5oiR6L-Z5LmI5aW955yL,size_20,color_FFFFFF,t_70,g_se,x_16)
2 . 动态数组实现(堆分配存储)
#include <iostream>
#include <string.h>
using namespace std;
#define MAXLEN 10//预定义最大串长 10
typedef struct {
//动态数组实现(堆分配存储)
char *ch;//按串长分配存储区 ch指向串的基地址
int length;//串的长度
int maxSize;
} HString;
typedef struct StringNode { //存储密度低 每个字符 1B 每个指针 4B(以32位系统为例)
//串的链式存储
char ch;//每个结点存 1 个字符
struct StringNode *next;
} StringNode, *String;
//typedef struct StringNode { //存储密度提高
// //串的链式存储(推荐)
// //如果结点存不满 可以用特殊字符(如 '\0')填充
// char ch[4];//每个结点存 多 个字符
// struct StringNode *next;
//} StringNode, *String;
//初始化
bool InitString(HString &S) {
S.ch = (char *)malloc(MAXLEN * sizeof(char));
S.length = 0;
S.maxSize = MAXLEN;
}
//增加串 长度
bool increaseStringSize(HString &S, int len) {
char *p = S.ch;
S.ch = (char *)malloc((S.maxSize + len) * sizeof(char));
if(!S.ch) { //申请空间失败
return false;
}
for (int i = 1; i <= S.length; i++) {
S.ch[i] = p[i];
}
S.maxSize += len;
free(p);
}
//赋值操作 把串T赋值为 chars
bool StrAssign(HString &T, const char *chars) {
if(strlen(chars) > T.maxSize) {
increaseStringSize(T, strlen(chars) - T.maxSize);
}
for (int i = 1; i <= strlen(chars); i++) {
T.ch[i] = chars[i - 1];
T.length++;
}
return true;
}
//复制操作 由串S复制得到T
bool StrCopy(HString &T, HString S) {
if(T.length < S.length) {
increaseStringSize(T, S.length - T.length);
}
for(int i = 1; i <= S.length; i++) {
T.ch[i] = S.ch[i];
T.length++;
}
return true;
}
//判空操作 空返回true 非空则false
bool StrEmpty(HString S) {
if(S.length == 0) {
return true;
}
return false;
}
//若s>t 返回>0 s==t 返回=0 s<t 返回<0
int StrCompare(HString S, HString T) {
for (int i = 1; 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;
}
//返回串长
int StrLength(HString S) {
return S.length;
}
//求子串 用sub返回串s的第pos个位置开始的长度为len的串
bool SubString(HString &Sub, HString S, int pos, int len) {
if(pos + len - 1 > S.length || pos < 1 || pos > 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;
}
//字符串拼接 用T返回由S1和S2连接的新串
bool Concat(HString &T, HString S1, HString S2) {
if(S1.length + S2.length > T.maxSize) { //字符串拼接会被截断 需要拓展容量
increaseStringSize(T, S1.length + S2.length - T.maxSize);
}
for (int i = 1; i <= S1.length ; i++) {
T.ch[i] = S1.ch[i];
}
for (int i = 1; i <= S2.length ; i++) {
T.ch[S1.length + i] = S2.ch[i];
}
T.length = S1.length + S2.length ;
return true;
}
//返回串T在S中第一次出现的位置 不存在返回0
int Index(HString S, HString T) {
int i = 1, n = StrLength(S), m = StrLength(T);
HString sub;
while(i <= n - m + 1) {
SubString(sub, S, i, m);
if(StrCompare(sub, T) != 0) {
++i;
} else {
return i;//返回字串在主串中的位置
}
}
return 0;//S 中不存在与 T相等的字串
}
//清空操作
bool ClearString(HString &S) {
S.length = 0;
return true;
}
//销毁串
bool DestoryString(HString &S) {
S.length = 0;
if(!S.ch) {
free(S.ch);
}
return true;
}
//打印串
bool showString(HString S) {
if(StrEmpty(S)) {
return false;
}
for (int i = 1; i <= S.length; i++) {
cout << S.ch[i];
}
cout << endl;
return true;
}
void test() {
HString S1;
InitString(S1);
if(StrEmpty(S1)) {
cout << "S1 Is Empty!" << endl;
} else {
cout << "S1 Isn't Empty!" << endl;
}
StrAssign(S1, "googooglegoogoogle");
showString(S1);
HString S2;
InitString(S2);
StrCopy(S2, S1);
showString(S2);
cout << "StrCompare(S1, S2): " << StrCompare(S1, S2) << endl; // =0
cout << "StrLength(S1): " << StrLength(S1) << endl;
cout << "StrLength(S2): " << StrLength(S2) << endl;
//求字串,用 Sub返回 串S 的第 pos 个位置开始的长度为 len 的串
HString Sub;
InitString(Sub);
SubString(Sub, S1, 13, 6);
showString(Sub);
HString T;
InitString(T);
Concat(T, S1, S2);
showString(T);
cout << "StrLength(T):" << StrLength(T) << endl;
// //返回 串Sub 在 S1 中第一次出现的位置,不存在返回0
cout << "Index(S1, Sub):" << Index(S1, Sub) << endl;
ClearString(S1);
cout << "StrLength(S1):" << StrLength(S1) << endl;
DestoryString(T);
}
int main() {
test();
return 0;
}
2-1 代码运行结果![](https://img-blog.csdnimg.cn/20210902171022337.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5oiR6L-Z5LmI5aW955yL,size_20,color_FFFFFF,t_70,g_se,x_16)
二、串的匹配模式
1 . 简单的匹配算法
//简单的模式匹配算法
int Index_01(HString S, HString T) {
//分别用计数指针 i j 指示主串 S 和模式串 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;
}
}
void test02() {
HString S;
InitString(S);
StrAssign(S, "sdbdnhfvfnjgoogooglegoogoogle");
showString(S);
HString T;
InitString(T);
StrAssign(T, "google");
showString(T);
cout << Index_01(S, T) << endl;
}
1-1 代码运行结果![](https://img-blog.csdnimg.cn/20210902171519163.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5oiR6L-Z5LmI5aW955yL,size_20,color_FFFFFF,t_70,g_se,x_16)
2 . 改进的模式匹配算法——KMP算法
//改进的的模式匹配算法--(KMP算法)
//获得next值
void getNext(HString T, int next[]) {
int i = 1, j = 0;
next[1] = 0;
while (i < T.length) {
if(j == 0 || T.ch[i] == T.ch[j]) {
++i;
++j;
next[i] = j; //若pi=pj 则next[j+1]=next[j]+1;
} else {
j = next[j];//否则令j=next[j] 循环继续
}
}
}
//KMP算法
int Index_KMP(HString S, HString T, int next[]) {
//分别用计数指针 i j 指示主串 S 和模式串 T当前正待比较字符的位置
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;
}
}
void test03() {
HString S;
InitString(S);
StrAssign(S, "sdbdnhfvfnjgoogooglegoogoogle");
showString(S);
HString T;
InitString(T);
StrAssign(T, "google");
showString(T);
int next[10];
getNext(T, next);
cout << Index_KMP(S, T, next) << endl;
}
2-1 代码运行结果![](https://img-blog.csdnimg.cn/2021090217152194.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5oiR6L-Z5LmI5aW955yL,size_20,color_FFFFFF,t_70,g_se,x_16)
3 . KMP算法的进一步优化
//KMP算法的进一步优化
void getNextVal(HString T, int nextval[]) {
int i = 1, j = 0;
nextval[1] = 0;
while (i < T.length) {
if(j == 0 || T.ch[i] == T.ch[j]) {
++i;
++j;
if(T.ch[i] != T.ch[j]) {
nextval[i] = j;
} else {
nextval[i] = nextval[j];
}
} else {
j = nextval[j];
}
}
}
//KMP算法
int Index_KMP(HString S, HString T, int next[]) {
//分别用计数指针 i j 指示主串 S 和模式串 T当前正待比较字符的位置
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;
}
}
void test04() {
HString S;
InitString(S);
StrAssign(S, "sdbdnhfvfnjgoogooglegoogoogle");
showString(S);
HString T;
InitString(T);
StrAssign(T, "google");
showString(T);
int nextval[10];
getNextVal(T, nextval);
cout << Index_KMP(S, T, nextval) << endl;
}