mirror of
https://github.com/kangjianwei/Data-Structure.git
synced 2026-02-06 00:07:05 +08:00
407 lines
8.2 KiB
C
407 lines
8.2 KiB
C
/*=============================
|
||
* 串的定长顺序存储表示(顺序串)
|
||
*
|
||
* 包含算法: 4.1、4.2、4.3、4.5
|
||
==============================*/
|
||
|
||
#include "SString.h" //**▲04 串**//
|
||
|
||
/*
|
||
* 初始化
|
||
*
|
||
* 构造一个值为chars的串T。
|
||
*
|
||
*【注】
|
||
* 该操作属于最小操作子集
|
||
*/
|
||
Status StrAssign(SString T, const char* chars) {
|
||
int i, len;
|
||
|
||
len = (int) strlen(chars);
|
||
|
||
// chars过长
|
||
if(len > MAXSTRLEN) {
|
||
return ERROR;
|
||
}
|
||
|
||
T[0] = len;
|
||
for(i = 1; i <= len; i++) {
|
||
T[i] = chars[i - 1];
|
||
}
|
||
|
||
return OK;
|
||
}
|
||
|
||
/*
|
||
* 销毁
|
||
*
|
||
* 将串S销毁。
|
||
*
|
||
*【注】
|
||
* 顺序串的结构无法销毁
|
||
*/
|
||
Status DestroyString(SString S) {
|
||
return OK;
|
||
}
|
||
|
||
/*
|
||
* 清空
|
||
*
|
||
* 将串S清空。
|
||
*/
|
||
Status ClearString(SString S) {
|
||
// 只需要将长度置为0就可以
|
||
S[0] = 0;
|
||
return OK;
|
||
}
|
||
|
||
/*
|
||
* 判空
|
||
*
|
||
* 判断串S中是否包含有效数据。
|
||
*
|
||
* 返回值:
|
||
* TRUE : 串S为空
|
||
* FALSE: 串S不为空
|
||
*/
|
||
Status StrEmpty(SString S) {
|
||
return S[0] == 0 ? TRUE : FALSE;
|
||
}
|
||
|
||
/*
|
||
* 计数
|
||
*
|
||
* 返回串S中元素的个数。
|
||
*
|
||
*【注】
|
||
* 该操作属于最小操作子集
|
||
*/
|
||
int StrLength(SString S) {
|
||
return S[0];
|
||
}
|
||
|
||
/*
|
||
* ████████ 算法4.3 ████████
|
||
*
|
||
* 求子串
|
||
*
|
||
* 用Sub返回S[pos, pos+len-1]。
|
||
* 返回值指示是否截取成功。
|
||
*
|
||
*【注】
|
||
* 该操作属于最小操作子集
|
||
*/
|
||
Status SubString(SString Sub, SString S, int pos, int len) {
|
||
int i;
|
||
|
||
if(pos < 1 || pos > S[0] || len < 0 || pos + len - 1 > S[0]) {
|
||
return ERROR;
|
||
}
|
||
|
||
// 复制元素
|
||
for(i = 1; i <= len; i++) {
|
||
Sub[i] = S[pos + i - 1];
|
||
}
|
||
|
||
// 确定新长度
|
||
Sub[0] = len;
|
||
|
||
return OK;
|
||
}
|
||
|
||
/*
|
||
* ████████ 算法4.1 ████████
|
||
*
|
||
* 查找
|
||
*
|
||
* 从pos处开始搜索模式串T在主串S中首次出现的位置,如果不存在,则返回0。
|
||
* 如果查找成功,返回匹配的位置。
|
||
*
|
||
*【注】
|
||
* 1.此实现需要依赖串的最小操作子集
|
||
* 2.该实现比较低效
|
||
*/
|
||
int Index_1(SString S, SString T, int pos) {
|
||
int i, n, m; // 记录S和T的长度
|
||
SString sub;
|
||
|
||
/*
|
||
* 失败情形提前处理
|
||
* 这里与教材写法略微不同
|
||
*/
|
||
if(pos < 1 || pos > S[0] || StrEmpty(T)) {
|
||
return 0;
|
||
}
|
||
|
||
n = StrLength(S);
|
||
m = StrLength(T);
|
||
i = pos;
|
||
|
||
// 保证长度不越界
|
||
while(i <= n - m + 1) {
|
||
// 获取S[i, i+m-1]
|
||
SubString(sub, S, i, m);
|
||
|
||
// 如果子串与模式串不匹配,则需要继续推进
|
||
if(StrCompare(sub, T) != 0) {
|
||
++i;
|
||
} else {
|
||
return i;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* ████████ 算法4.5 ████████
|
||
*
|
||
* 查找
|
||
*
|
||
* 从pos处开始搜索模式串T在主串S中首次出现的位置,如果不存在,则返回0。
|
||
* 如果查找成功,返回匹配的位置。
|
||
*
|
||
*【注】
|
||
* 1.此实现不依赖串的最小操作子集
|
||
* 2.该实现比较低效
|
||
*/
|
||
int Index_2(SString S, SString T, int pos) {
|
||
int i = pos;
|
||
int j = 1;
|
||
|
||
if(pos < 1 || pos > S[0] || StrEmpty(T)) {
|
||
return 0;
|
||
}
|
||
|
||
while(i <= S[0] && j <= T[0]) {
|
||
// 遇到相同字符,则继续比较后继字符
|
||
if(S[i] == T[j]) {
|
||
i++;
|
||
j++;
|
||
|
||
// 遇到不同的字符,则游标需要回退,重新比较
|
||
} else {
|
||
i = i - (j - 1) + 1; // j-1代表徒劳地前进了j-1个元素,在第j个元素上功亏一篑
|
||
j = 1; // 游标j回到串T的第一个位置
|
||
}
|
||
}
|
||
|
||
// 增加了一个T[0]>0的判断
|
||
if(j > T[0] && T[0] > 0) { // T不为空串
|
||
return i - T[0]; // 匹配成功
|
||
} else {
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* 插入
|
||
*
|
||
* 将串T插入到主串S的pos位置处。
|
||
*/
|
||
Status StrInsert(SString S, int pos, SString T) {
|
||
int i;
|
||
|
||
if(pos < 1 || pos > S[0] + 1 || S[0] + T[0] > MAXSTRLEN) {
|
||
return ERROR;
|
||
}
|
||
|
||
// 如果待插入的串为空,则提前返回
|
||
if(StrEmpty(T)) {
|
||
return OK;
|
||
}
|
||
|
||
// 在S中腾出位置,为插入T做准备
|
||
for(i = S[0]; i >= pos; i--) {
|
||
// 从后向前遍历,将前面的元素挪到后面
|
||
S[i + T[0]] = S[i];
|
||
}
|
||
|
||
// 将串T插入在S中腾出的位置上
|
||
for(i = pos; i <= pos + T[0] - 1; i++) {
|
||
S[i] = T[i - pos + 1];
|
||
}
|
||
|
||
// 长度增加
|
||
S[0] += T[0];
|
||
|
||
return OK;
|
||
}
|
||
|
||
/*
|
||
* 删除
|
||
*
|
||
* 删除S[pos, pos+len-1]。
|
||
*/
|
||
Status StrDelete(SString S, int pos, int len) {
|
||
int i;
|
||
|
||
if(pos < 1 || pos + len - 1 > S[0] || len < 0) {
|
||
return ERROR;
|
||
}
|
||
|
||
// 如果待删除的长度为0,则提前返回
|
||
if(len == 0) {
|
||
return OK;
|
||
}
|
||
|
||
// 把后面的元素挪到前面,覆盖掉被删除的元素
|
||
for(i = pos + len; i <= S[0]; i++) {
|
||
S[i - len] = S[i];
|
||
}
|
||
|
||
// 长度减少
|
||
S[0] -= len;
|
||
|
||
return OK;
|
||
}
|
||
|
||
/*
|
||
* 比较
|
||
*
|
||
* 比较串S和串T,返回比较结果。
|
||
*
|
||
*【注】
|
||
* 该操作属于最小操作子集
|
||
*/
|
||
int StrCompare(SString S, SString T) {
|
||
int i = 1;
|
||
|
||
while(i <= S[0] && i <= T[0]) {
|
||
// 遇到不同的字符时,比较其大小
|
||
if(S[i] != T[i]) {
|
||
return S[i] - T[i];
|
||
}
|
||
|
||
i++;
|
||
}
|
||
|
||
return S[0] - T[0];
|
||
}
|
||
|
||
/*
|
||
* 复制
|
||
*
|
||
* 将串S复制到串T。
|
||
*/
|
||
Status StrCopy(SString T, SString S) {
|
||
int i;
|
||
|
||
// 连同长度信息一起复制
|
||
for(i = 0; i <= S[0]; i++) {
|
||
T[i] = S[i];
|
||
}
|
||
|
||
return OK;
|
||
}
|
||
|
||
/*
|
||
* 替换
|
||
*
|
||
* 用V替换主串S中出现的所有与T相等的且不重叠的子串。
|
||
*
|
||
*【注】
|
||
* 1.该操作依赖最小操作子集
|
||
* 2.该实现比较低效
|
||
*/
|
||
Status Replace(SString S, SString T, SString V) {
|
||
int i;
|
||
|
||
if(StrEmpty(S) || StrEmpty(T)) {
|
||
return ERROR;
|
||
}
|
||
|
||
// 在主串S中寻找模式串T第一次出现的位置
|
||
i = Index_2(S, T, 1);
|
||
|
||
// 如果存在匹配的字符串,且可以被完全替换(替换后不溢出)
|
||
while(i != 0 && S[0] - T[0] + V[0] <= MAXSTRLEN) {
|
||
StrDelete(S, i, StrLength(T)); // 从S中删除T
|
||
StrInsert(S, i, V); // 向S中插入V
|
||
|
||
i += StrLength(V); // i切换到下一个位置
|
||
|
||
i = Index_2(S, T, i); // 查找下一个匹配的字符串
|
||
}
|
||
|
||
if(i == 0) { // S中的T已全部被替换
|
||
return OK;
|
||
} else { // S中尚有T,但是V已经插不进去了
|
||
return ERROR;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* ████████ 算法4.2 ████████
|
||
*
|
||
* 串联接
|
||
*
|
||
* 联接S1和S2,并存储到T中返回。如果联接后的长度溢出,则只保留未溢出的部分。
|
||
* 返回值表示联接后的串是否完整。
|
||
*
|
||
*【注】
|
||
* 该操作属于最小操作子集
|
||
*/
|
||
Status Concat(SString T, SString S1, SString S2) {
|
||
int i;
|
||
int uncut; // 新串是否完整
|
||
|
||
// 完全不需要裁剪
|
||
if(S1[0] + S2[0] <= MAXSTRLEN) {
|
||
// 复制S1到T中
|
||
for(i = 1; i <= S1[0]; i++) {
|
||
T[i] = S1[i];
|
||
}
|
||
|
||
// 复制S2到T中
|
||
for(i = S1[0] + 1; i <= S1[0] + S2[0]; i++) {
|
||
T[i] = S2[i - S1[0]];
|
||
}
|
||
|
||
// 设置新长度
|
||
T[0] = S1[0] + S2[0];
|
||
|
||
// 未裁剪,完整
|
||
uncut = TRUE;
|
||
|
||
// 需要裁剪S2
|
||
} else if(S1[0] <= MAXSTRLEN) {
|
||
// 复制S1到T中
|
||
for(i = 1; i <= S1[0]; i++) {
|
||
T[i] = S1[i];
|
||
}
|
||
|
||
// 将S2的一部分复制到T中
|
||
for(i = S1[0] + 1; i <= MAXSTRLEN; i++) {
|
||
T[i] = S2[i - S1[0]];
|
||
}
|
||
|
||
// 设置新长度
|
||
T[0] = MAXSTRLEN;
|
||
|
||
uncut = FALSE;
|
||
|
||
// 只需要复制S1的一部分
|
||
} else {
|
||
// 连同长度信息一起复制
|
||
for(i = 0; i <= MAXSTRLEN; i++) {
|
||
T[i] = S1[i];
|
||
}
|
||
|
||
uncut = FALSE;
|
||
}
|
||
|
||
return uncut;
|
||
}
|
||
|
||
// 输出:打印字符串
|
||
void StrPrint(SString S) {
|
||
int i;
|
||
|
||
for(i = 1; i<=S[0] ; i++) {
|
||
printf("%c", S[i]);
|
||
}
|
||
|
||
printf("\n");
|
||
}
|