串是由0个或多个字符组成的有限序列,例如:
s="abcdef"
s是串名,双引号里面的是串值。
串的长度:双引号里面字符的个数(空格也算一个字符)
空串:字符个数为0,例如
s=""
空格串:双引号里面的字符只有空格(一个或多个),不要与空串混淆,例如
s=" "
子串:串中任意连续的字符组成的子序列称为该串的子串
主串:相对于该子串来说,包含这个子串的另一个串称为主串
有三个字符串s1、s2和s3,s2是s1的子串,s1被称为s2的主串。s3不是s1的子串
s1="qwerty"
s2="wer"
s3="qer"
串赋值,将字符数组的元素赋值给串
StrAssign(String &str, char chars[]);
串比较,str1的ascii码比str2的大就返回1,相等返回0,小于返回-1
StrCompare(String str1, String str2);
求串长
StrLength(String str);
串连结,将str1和str2连接,返回给str
Concat(String &str, String str1, String str2);
求子串,在str中截取从指定位置开始,指定长度的子串,并返回给subStr
SubString(String &subStr, String str, int startPoint, int len);
串拷贝
StrCopy(String &str1, String str2);
串判空
StrEmpty(String str);
清空串
ClearString(String &str);
获取子串的位置,使用DF算法,既暴力穷举法,是子串返回第一个字符出现的位置,找不到返回0
index_DF(String str, String T, int point);
获取子串的位置,kmp算法查找,找到返回模式串第一个字符出现在主串中的位置,找不到返回0
index_KMP(String str, String T, int point);
子串的插入,将子串subStr插入到str指定位置中
StrInsert(String &str, int insertPoint, String subStr);
子串的删除
StrDelete(String &str, int startPoint, int len);
串销毁
DestroyString(String &str);
打印串
printStr(String str);
计算出字符串的公共前缀表
prefix_table(String str, int prefix[]);
//###一些常量
//函数结果状态码
#include
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
//串的最大容量
#define MAXSIZE 100
//函数类型
typedef int Status;
typedef struct {
//存储串的最大度,第ch[0]位置不存储元素
char ch[MAXSIZE + 1];
//记录串的长度
int length;
} String;
//------------------------------------
//串赋值,将字符数组的元素赋值给串
void StrAssign(String &str, char chars[]);
//串比较,str1的ascii码比str2的大就返回1,相等返回0,小于返回-1
int StrCompare(String str1, String str2);
//求串长
int StrLength(String str);
//串连结,将str1和str2连接,返回给str
void Concat(String &str, String str1, String str2);
//求子串,在str中截取从指定位置开始,指定长度的子串,并返回给subStr
Status SubString(String &subStr, String str, int startPoint, int len);
//串拷贝
void StrCopy(String &str1, String str2);
//串判空
Status StrEmpty(String str);
//清空串
void ClearString(String &str);
//获取子串的位置,使用DF算法,既暴力穷举法,是子串返回第一个字符出现的位置,找不到返回0
int index_DF(String str, String T, int point);
//获取子串的位置,kmp算法查找,找到返回模式串第一个字符出现在主串中的位置,找不到返回0
int index_KMP(String str, String T, int point);
//子串的插入,将子串subStr插入到str指定位置中
Status StrInsert(String &str, int insertPoint, String subStr);
//子串的删除
Status StrDelete(String &str, int startPoint, int len);
//串销毁
void DestroyString(String &str);
//打印串
void printStr(String str);
//计算出模式串的公共前缀表
void prefix_table(String str, int prefix[]);
//------------TEST-------------
int main() {
// 创建一个串
String string;
// 声明一个内容为HelloWorld的字符数组
char *data = new char[10]{'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd'};
// 赋值
StrAssign(string, data);
printf("string串的长度:%d\n", StrLength(string));//9
// 判断串是否为空
printf("string串是否为空:%d\n", StrEmpty(string));//0
printf("string串:");
printStr(string);
// 创建另外一个串
String string2;
// 声明一个内容为HelloWorld的字符数组
char *data2 = new char[10]{'W', 'o', 'r', 'l', 'd'};
// 赋值
StrAssign(string2, data2);
printf("string2串:");
printStr(string2);
//比较string和string2两个串的ASCII码值大小
printf("string串和string2串的大小(1为string大,0为相等,-1为string小)"
":%d\n", StrCompare(string, string2));//1
//获取string2在string出现的位置
printf("string2在string出现的位置(1):%d\n", index_DF(string, string2, 1));//6
//子串删除
StrDelete(string, index_DF(string, string2, 1), StrLength(string2));
//获取string2在string出现的位置
printf("string2在string出现的位置(2):%d\n", index_DF(string, string2, 1));//0
//拷贝
String string3;
StrCopy(string3, string);
printf("string3的长度:%d\n", StrLength(string3));//5
printf("string3串:");
printStr(string3);
// 串连结
String string4;
Concat(string4, string3, string3);
printf("string4的长度:%d\n", StrLength(string4));//10
printf("string4串:");
printStr(string4);
//将string2插入到string4中
StrInsert(string4, 4, string2);
printf("string4串:");
printStr(string4);
//从string4中截取出子串
String string5;
SubString(string5, string4, 2, 8);
//串销毁
DestroyString(string);
printStr(string);
//
StrAssign(string, new char[12]{'C', 'A', 'B', 'A', 'A', 'B', 'A', 'B', 'A', 'C', 'A'});
String str;
StrAssign(str, new char[10]{'A', 'C', 'A'});
int point = index_KMP(string, str, 1);
printf("出现的位置:%d", point);//9
}
//-----------------------------
/**
* 打印串
* @param str
*/
void printStr(String str) {
if (StrEmpty(str)) {
printf("空串\n");
return;
}
for (int i = 1; i <= str.length; i++) {
printf("%c", str.ch[i]);
}
printf("\n");
}
/**
* 获取子串的位置,使用DF算法,既暴力穷举法,是子串返回第一个字符出现的位置,不是返回0
* @param str 主串
* @param temStr 用来对比的模板串
* @param startPoint 从主串中开始匹配的位置
* @return temStr是子串:返回temStr的第一个字符在str中出现的位置
*/
int index_DF(String str, String temStr, int startPoint) {
//开始查找位置校验
if (startPoint < 1 || startPoint > str.length) {
printf("开始查找的位置有误");
return 0;
}
for (int i = startPoint, j = 1; i <= str.length && j <= temStr.length;) {
if (str.ch[i] != temStr.ch[j]) {
//主串上的字符和模板串上的字符不相等时
//主串位置回溯
i = i - j + 2;
//子串回到第一个
j = 1;
//结束本次循环,从模板串第一个字符开始比较
continue;
}
//两个位置的字符相等,下一次对比的位置都后移
i++, j++;
//子串已经完了,且前面每一个位置都相等,返回模板串第一个字符在主串中出现的位置
if (j > temStr.length) {
return i - temStr.length;
}
}
//不是子串,返回0
return 0;
}
/**
* kmp算法查找,找到返回模式串第一个字符出现在主串中的位置,找不到返回-1
* @param str 主串
* @param temStr 模式串
* @param point 在主串中开始查找的位置
* @return
*/
int index_KMP(String str, String temStr, int point) {
//校验开始查找的位置是否正确
if (point < 1 || point > str.length) {
printf("point值的范围不正确");
return 0;
}
// printStr(temStr);
//定义出公共前缀表
int prefix[temStr.length];
//根据串求出这个串的公共前缀表
prefix_table(temStr, prefix);
//打印公共前缀表
// for(int i = 0; i
// printf("%d\t", prefix[i]);
// }
//使用kmp算法进行查找
//i指向主串,j指向模式串
int i = point, j = 1;
while (i <= str.length && j <= temStr.length) {
if (str.ch[i] == temStr.ch[j]) {
//相同的话,两个位置都后移
i++;
j++;
} else {
//两个位置出现不相等
//模式串根据公共前缀表回溯j指向的位置
if (prefix[j - 1] != -1) {
//
j = prefix[j - 1] + 1;
} else {
j = 1;
i++;
}
}
//根据j的位置进行判断是否找到
if (j > temStr.length) {
return i - temStr.length;
}
}
return 0;
}
/**
* 计算出模式串的公共前缀表
* @param str 模式串
* @param prefix 接收公共前缀表
*/
void prefix_table(String str, int prefix[]) {
//第一个字符,公共前缀为0
prefix[0] = 0;
//公共前缀的长度
int len = 0;
//从串的第二个字符开始,第一个字符公共前缀是0
int i = 2;
//计算出公共前缀表
while (i <= str.length) {
if (str.ch[i] == str.ch[prefix[i - 2] + 1]) {
prefix[i - 1] = ++len;
i++;
} else {
if (len > 0) {
if (str.ch[i] == str.ch[prefix[len - 1] + 1]) {
len = prefix[len - 1] + 1;
prefix[i - 1] = len;
i++;
} else {
len--;
}
} else {
prefix[i - 1] = 0;
i++;
}
}
}
//去掉公共前缀表的最后一个,并将剩余元素依次往后移一个位置,第一个位置的公共前缀的长度设为-1
for (int i = str.length - 1; i >= 0; i--) {
if (i == 0) {
prefix[i] = -1;
} else {
prefix[i] = prefix[i - 1];
}
}
}
/**
* 求串长
* @param str
* @return 串的长度
*/
int StrLength(String str) {
return str.length;
}
/**
* 串赋值,将字符数组的元素赋值给串
* @param str
* @param chars
*/
void StrAssign(String &str, char chars[]) {
//清空
ClearString(str);
//将字符数组的每个元素放到串的数组中
for (int i = 1; chars[i - 1] != '\0' && i < MAXSIZE; i++) {
//放入数组中
str.ch[i] = chars[i - 1];
//长度加1
str.length++;
}
}
/**
* 清空串,将串的每个元素置为空
* @param str 要清空的串
*/
void ClearString(String &str) {
// if(str.length){
// //存储串的数组的第一个元素不用来存储
// for(int i = 1; i <= str.length || str.ch[i] != '\0'; i++){
// //将每个元素都设置为空
// str.ch[i] = '\0';
// }
// //将数组的长度置为0
// str.length = 0;
// }
str.length = 0;
}
/**
* 判断串是否为空
* @param str 串
* @return
*/
Status StrEmpty(String str) {
return str.length ? FALSE : TRUE;
}
/**
* 串销毁
* @param str 串
*/
void DestroyString(String &str) {
ClearString(str);
}
/**
* 子串的插入,将子串subStr插入到str指定位置中
* @param str 被插入的串
* @param insertPoint 插入的位置
* @param subStr 要插入的子串
* @return
*/
Status StrInsert(String &str, int insertPoint, String subStr) {
//判断是否有插入的空间
if (str.length + subStr.length > MAXSIZE) {
printf("插入失败,串现有的剩余空间不足以存放子串!");
return ERROR;
}
//如果插入的位置在串的最后一个元素的后面,将插入的位置都调到串的最后一个字符之后
if (insertPoint > str.length) {
insertPoint = str.length + 1;
}
//判断插入位置是否正确
if (insertPoint < 1 || subStr.length + insertPoint > MAXSIZE) {
printf("插入的位置不正确");
return ERROR;
}
//计算出最后插入的位置
int endPoint = insertPoint + subStr.length - 1;
//将要插入位置的元素后移,到指定位置就插入
for (int i = str.length; i >= insertPoint; i--) {
str.ch[i + subStr.length] = str.ch[i];
//到插入的位置了,将元素插入
if (i == endPoint) {
str.ch[i] = subStr.ch[(endPoint--) - insertPoint + 1];
}
}
str.length += subStr.length;
return TRUE;
}
/**
* 子串的删除
* @param str 串
* @param startPoint 要开始删除的位置
* @param len 删除的长度
*/
Status StrDelete(String &str, int startPoint, int len) {
//计算出要删除子串的最后一个位置
int endPoint = startPoint + len - 1;
//判断要删除的位置是否正确
if (startPoint < 1 || endPoint > str.length) {
printf("要删除的位置有误\n");
return ERROR;
}
//
//将要删除的位置的后面的字符覆盖删除的位置的字符
for (int i = endPoint + 1; i <= str.length; i++) {
str.ch[startPoint++] = str.ch[i];
}
str.length -= len;
return OK;
}
/**
* 串比较,str1的ascii码比str2的大就返回1,相等返回0,小于返回-1
* @param str1 串
* @param str2 串
* @return
*/
int StrCompare(String str1, String str2) {
//计算出每个串的ASCII码总值
int str1Ascii = 0;
int str2Ascii = 0;
//最大循环次数,取决于最长的串
int max = str1.length > str2.length ? str1.length : str2.length;
for (int i = 1; i <= max; i++) {
//计算str1的ASCII码
if (i <= str1.length) {
str1Ascii += str1.ch[i];
} else {
//str1算完之后,要是小于str2的,直接结束循环
if (str1Ascii < str2Ascii) break;
}
//计算str2的ASCII码
if (i <= str2.length) {
str1Ascii += str2.ch[i];
} else {
//str2算完之后,要是小于str1的,直接结束循环
if (str1Ascii > str2Ascii) break;
}
}
if (str1Ascii > str2Ascii) {
return 1;
} else if (str1Ascii < str2Ascii) {
return -1;
} else {
//相等情况
return 0;
}
}
/**
* 串连结,将str1和str2连接,返回给str
* @param str 接收结果的串
* @param str1 用来拼接的串1
* @param str2 用来拼接的串2
*/
void Concat(String &str, String str1, String str2) {
//先将str串清空
ClearString(str);
//读取str1串到str
for (int i = 1; i <= str1.length; i++) {
str.ch[i] = str1.ch[i];
str.length++;
}
//读取str2串到str
for (int i = (str1.length + 1); i <= (str1.length + str2.length); i++) {
str.ch[i] = str2.ch[i - str1.length];
str.length++;
}
}
/**
* 求子串,在str中截取从指定位置开始,指定长度的子串,并返回给subStr
* @param subStr
* @param str
* @param startPoint
* @param len
*/
Status SubString(String &subStr, String str, int startPoint, int len) {
//截取位置校验
if (startPoint + len > str.length || startPoint < 1) {
printf("位置出错了");
return ERROR;
}
//将子串清空
ClearString(subStr);
//读取str指定位置的字符到subStr中
for (int i = startPoint; i <= startPoint + len; i++) {
subStr.ch[i - startPoint] = str.ch[i];
subStr.length++;
}
return OK;
}
/**
* 串拷贝,将str2拷贝到str1
* @param str1
* @param str2
*/
void StrCopy(String &str1, String str2) {
//清空str1
ClearString(str1);
//拷贝
for (int i = 1; i <= str2.length; i++) {
str1.ch[i] = str2.ch[i];
str1.length++;
}
}