作者在学习数据结构时,发现鲜有完全按照 C 语言描述的算法操作,这让习惯于写 .c 而不是 .cpp 的初学者很是头疼。本文将基于 C 语言描述算法操作,如有错漏还望大佬们指正。
前言
本文将按照严惠敏所著《数据结构(C语言版)》所做的函数原型声明进行算法描述,由于C语言不支持函数参数中出现取地址符,我将函数参数更改为指针,调用函数时需要使用一级指针。基本操作调用示例将在本文后给出。
2023.4.10 08 : 20 2023.4.10\ 08:20 2023.4.10 08:20 新增了 I n d e x Index Index 的 K M P KMP KMP 算法及其调用示例
一、定长顺序串基本操作的函数声明
//生成一个其值等于 chars 的串 S
extern Status StrAssign(SString* S, char* chars);
//由串 S 复制得串 T
extern Status StrCopy(SString *T, SString S);
//若 S 为空串,则返回 TRUE,否则返回 FAUSE
extern Status StrEmpty(SString S);
//若 S > T,则返回值 > 0;若 S = T,则返回值 = 0;若 S < T,则返回值 < 0
extern int StrCompare(SString S, SString T);
//返回串 S 的元素个数,称为串的长度
extern int StrLength(SString S);
//将 S 清为空串
extern Status ClearString(SString *S);
//用 T 返回由 S1 和 S2 联接而成的新串,如果连接时未截断则返回 TRUE,否则返回 FAUSE
extern Status Concat(SString *T, SString S1, SString S2);
//用 Sub 返回串 S 的第 pos 个字符起长度为 len 的子串
extern Status SubString(SString *Sub, SString S, int pos, int len);
//如果主串 S 中存在和串 T 值相同的子串,则返回它在主串 S 中第 pos 个字符之后第一次出现的位置;否则函数值为 0
extern int Index(SString S, SString T, int pos);
//用串 V 替换主串 S 中出现的所有与串 T 相等的不重叠的子串
extern Status Replace(SString *S, SString T, SString V);
//在串 S 的第 pos 个字符前插入串 T
extern Status StrInsert(SString *S, int pos, SString T);
//从串 S 的第 pos 个字符起长度为 len 的子串
extern Status StrDelete(SString *S, int pos, int len);
//销毁串 S
extern Status DestroyStr(SString *S);
//打印串 S
extern Status PrintStr(SString S);
//模式匹配的的 KMP 算法:如果主串 S 中存在和串 T 值相同的子串,则返回它在主串 S 中第 pos 个字符之后第一次出现的位置;否则函数值为 -1
extern int Index_KMP(SString S, SString T, int pos);
//计算 KMP 算法中串 T 的 next 函数值
extern void get_nextval(SString T, int *nextval);
二、定长顺序串基本操作的完整描述
/* 定长顺序串 */
#include <stdio.h>
#include <stdlib.h>
#define MAXSTRLEN 255
#define OK 0
#define ERROR 1
#define TRUE 0
#define FAUSE 1
#define OVERFLOW -2
typedef char Elemtype;
typedef int Status;
/*--------串的定长顺序表示--------*/
typedef unsigned char SString[MAXSTRLEN + 1];
//--------定长顺序串的基本操作的函数声明--------
//生成一个其值等于 chars 的串 S
extern Status StrAssign(SString* S, char* chars);
//由串 S 复制得串 T
extern Status StrCopy(SString *T, SString S);
//若 S 为空串,则返回 TRUE,否则返回 FAUSE
extern Status StrEmpty(SString S);
//若 S > T,则返回值 > 0;若 S = T,则返回值 = 0;若 S < T,则返回值 < 0
extern int StrCompare(SString S, SString T);
//返回串 S 的元素个数,称为串的长度
extern int StrLength(SString S);
//将 S 清为空串
extern Status ClearString(SString *S);
//用 T 返回由 S1 和 S2 联接而成的新串,如果连接时未截断则返回 TRUE,否则返回 FAUSE
extern Status Concat(SString *T, SString S1, SString S2);
//用 Sub 返回串 S 的第 pos 个字符起长度为 len 的子串
extern Status SubString(SString *Sub, SString S, int pos, int len);
//如果主串 S 中存在和串 T 值相同的子串,则返回它在主串 S 中第 pos 个字符之后第一次出现的位置;否则函数值为 0
extern int Index(SString S, SString T, int pos);
//用串 V 替换主串 S 中出现的所有与串 T 相等的不重叠的子串
extern Status Replace(SString *S, SString T, SString V);
//在串 S 的第 pos 个字符前插入串 T
extern Status StrInsert(SString *S, int pos, SString T);
//从串 S 的第 pos 个字符起长度为 len 的子串
extern Status StrDelete(SString *S, int pos, int len);
//销毁串 S
extern Status DestroyStr(SString *S);
//打印串 S
extern Status PrintStr(SString S);
//模式匹配的的 KMP 算法:如果主串 S 中存在和串 T 值相同的子串,则返回它在主串 S 中第 pos 个字符之后第一次出现的位置;否则函数值为 -1
extern int Index_KMP(SString S, SString T, int pos);
//计算 KMP 算法中串 T 的 next 函数值
extern void get_nextval(SString T, int *nextval);
Status StrAssign(SString* S, char* chars) {
int len; char* c;
for (len = 0, c = chars; *c; len++, c++) {
(*S)[len + 1] = *c;
}
(*S)[0] = len;
return OK;
}// StrAssign
Status StrCopy(SString *T, SString S) {
for (int i = 1; i <= S[0]; i++) (*T)[i] = S[i];
(*T)[0] = S[0];
return OK;
}// StrCopy
Status StrEmpty(SString S) {
if (S[0]) return FAUSE;
else return TRUE;
}// StrEmpty
int StrCompare(SString S, SString T) {
if (S[0] > T[0]) return 1;
else if (S[0] < T[0]) return -1;
else {
for (int i = 1; i <= S[0]; i++) {
if (S[i] > T[i]) return 1;
else if (S[i] < T[i]) return -1;
}
return 0;
}
}// StrCompare
int StrLength(SString S) {
return S[0];
}// StrLength
Status ClearString(SString *S) {
(*S)[0] = 0;
return OK;
}// ClearString
Status Concat(SString *T, SString S1, SString S2) {
int uncut = 0;
if (S1[0] + S2[0] <= MAXSTRLEN) {
for (int i = 1; i <= S1[0]; i++) (*T)[i] = S1[i];
for (int i = S1[0] + 1; i <= S1[0] + S2[0]; i++) (*T)[i] = S2[i - S1[0]];
(*T)[0] = S1[0] + S2[0]; uncut = TRUE;
}
else if (S1[0] < MAXSTRLEN) {
for (int i = 1; i <= S1[0]; i++) (*T)[i] = S1[i];
for (int i = S1[0] + 1; i <= MAXSTRLEN; i++) (*T)[i] = S2[i - S1[0]];
(*T)[0] = MAXSTRLEN; uncut = FAUSE;
}
else {
for (int i = 0; i <= MAXSTRLEN; i++) (*T)[i] = S1[i];
uncut = FAUSE;
}
return uncut;
}// Concat
Status SubString(SString *Sub, SString S, int pos, int len) {
if (pos < 1 || pos > S[0] || len < 0 || len > S[0] - pos + 1) return ERROR;
for (int i = 1; i <= len; i++) (*Sub)[i] = S[pos + i - 1];
(*Sub)[0] = len; return OK;
}// SubString
int Index(SString S, SString T, int pos) {
if (pos > 0) {
int n = StrLength(S), m = StrLength(T), i = pos;
SString sub;
while (i <= n - m + 1) {
SubString(&sub, S, i, m);
if (StrCompare(sub, T) != 0) ++i;
else return i;
}
}
return 0;
}// Index
Status Replace(SString *S, SString T, SString V) {
int pos = Index(*S, T, 1);
if (!pos) return ERROR;
StrDelete(S, pos, T[0]);
StrInsert(S, pos, V);
return OK;
}// Replace
Status StrInsert(SString* S, int pos, SString T) {
if ((*S)[0] + T[0] > MAXSTRLEN) exit(OVERFLOW);
SString tmp;
for (int i = 1; i <= (*S)[0] - pos + 1; i++) tmp[i] = (*S)[pos + i - 1];
tmp[0] = (*S)[0] - pos + 1;
for (int i = 1; i <= T[0]; i++)
(*S)[pos + i - 1] = T[i];
for (int i = 1; i <= tmp[0]; i++) (*S)[pos + T[0] + i - 1] = tmp[i];
(*S)[0] = (*S)[0] + T[0];
return OK;
}// StrInsert
Status StrDelete(SString* S, int pos, int len) {
for (int i = 0; i <= (int)(*S)[0] - pos - len; i++)
(*S)[pos + i] = (*S)[pos + len + i];
(*S)[0] -= len;
return 0;
}// StrDelete
Status DestroyStr(SString *S) {
free(S);
return OK;
}// DestroyStr
Status PrintStr(SString S) {
for (int i = 1; i <= S[0]; i++) {
printf("%c", S[i]);
}
printf("\n");
return OK;
}// PrintList
int Index_KMP(SString S, SString T, int pos) {
int i = pos, j = 1;
int next[MAXSTRLEN + 1];
get_nextval(T, next);
while (i <= S[0] && j <= T[0]) {
if (j == 0 || S[i] == T[j]) { ++i; ++j; }
else j = next[j];
}
if ((j > T[0])) return (i - T[0]);
}// Index_KMP
void get_nextval(SString T, int *nextval) {
* nextval = (long int)malloc(MAXSTRLEN * sizeof(int));
int i = 1; nextval[1] = 0; int j = 0;
while (i < T[0]) {
if (j == 0 || T[i] == T[j]) {
++i; ++j;
if (T[i] != T[j]) nextval[i] = j;
else nextval[i] = nextval[j];
}
else j = nextval[j];
}
}// get_nextval
三、调用示例
int main() {
char chars[MAXSTRLEN + 1] = {0};
SString S, T, P;
printf("Please enter a string: ");
scanf("%s", chars);
StrAssign(&S, chars);
printf("The resulting string: ");
PrintStr(S);
StrCopy(&T, S);
printf("StrCopy(&T, S): ");
PrintStr(T);
printf("StrCompare(S, T): result = %d\n", StrCompare(S, T));
printf("StrLength(S): %d\n", StrLength(S));
Concat(&P, S, T);
printf("Concat(&P, S, T): P = ");
PrintStr(P);
char chars1[MAXSTRLEN + 1] = { 0 }, chars2[MAXSTRLEN + 1] = { 0 };
SString S, T;
printf("Index_KMP: Please enter chars1: ");
scanf("%s", chars1);
printf("Index_KMP: Please enter chars2: ");
scanf("%s", chars2);
StrAssign(&S, chars1);
StrAssign(&T, chars2);
printf("Index_KMP: result = %d\n", Index_KMP(S, T, 1));
return 0;
}
终端输出结果如下:
Please enter a string: abcde
The resulting string: abcde
StrCopy(&T, S): abcde
StrCompare(S, T): result = 0
StrLength(S): 5
Concat(&P, S, T): P = abcdeabcde
Index_KMP: Please enter chars1: samples
Index_KMP: Please enter chars2: sam
Index_KMP: result = 0
总结
以上是定长顺序串的基本操作的算法描述,更多数据结构的算法描述还在更新中,敬请关注作者专栏。