数据结构与算法—复习:顺序表字符串的KMP算法实现
首先感叹一下KMP算法中求解next数组的算法之精妙:
int* findNext(PSeqString s){
int* next = (int*)malloc(sizeof(s->n)); //分配适合大小的next数组空间
int i = 0 , k = -1; //初始化开始的值
next[0] = -1; //next[0] 一定是 -1 有些地方写的是 0
while(i < s->n - 1){ //求解第i+1个下标的next数组值
while(k >= 0 && s->c[i] != s->c[k])
k = next[k];
i++;k++;
next[i] = k;
}
return next;
}
下面给出全套代码:
/**
* 程序说明:顺序表实现字符串
* 1.创建一个空的字符串
* 1.3. 判断字符串是否为空
* 2.创建一个
* 3.删除指定下标的字符
* 4.在指定下标插入字符
* 5.NULL
* 6.返回指定下标的字符
* 7.拼接字符串
* 8.返回某字符串在主字符串中第一次出现的位置
*/
#include <stdio.h>
#include <malloc.h>
/**
* 字符串类型的定义,与顺序表一致,替换了其中DataType
*/
struct SeqString{
int MAXNUM; //字符串最大长度
int n; //当前字符串长度
char* c; //字符串内容数组
};
typedef struct SeqString* PSeqString;
/**
* 1.创建一个空的字符串
* @param m
* @return
*/
PSeqString createNullStr_seq(int m){
PSeqString pstr = (PSeqString)malloc(sizeof(struct SeqString));
if(pstr != NULL){
pstr->c = (char*)malloc(sizeof(char)*m);
if(pstr->c){
pstr->MAXNUM = m;
pstr->n = 0;
return pstr;
}else{
free(pstr);
}
}
printf("字符串头指针分配空间出错\n");
return NULL;
}
/**
* 1.2 初始化字符串数据
* @param pstr
* @param data
*/
void initString(PSeqString pstr,char data[],int size){
if(pstr == NULL){
printf("字符串为空,无法初始化\n");
return;
}
for(int i = 0; i < size ;i++){
pstr->c[i] = data[i];
pstr->n++;
}
printf("初始化完成\n");
}
/**
* 1.3 打印字符串
* @param pstr
*/
void printString(PSeqString pstr){
if(pstr == NULL){
printf("字符串为空,无法打印\n");
return;
}
for(int i=0;i<pstr->n;i++)
{
printf("%c",pstr->c[i]);
}
printf("\n");
}
/**
* 1.3.判断字符串是否为空
* @param pstr
* @return
*/
int isNullString_seq(PSeqString pstr){
if(pstr->n == 0)
return 1;
else
return 0;
}
/**
* 2.求子串 从第i个字符开始的后续j个
* abcdef 中 a就是第一个(不按照下标考虑,按照考虑)
* @param pstr
* @param i
* @param j
* @return
*/
PSeqString subStr_seq(PSeqString pstr,int i,int j){
if(pstr == NULL || isNullString_seq(pstr)){
printf("字符串不存在或为空,无法执行求子串操作\n");
return NULL;
}
/*求从s所指的顺序串第i个字符开始连续的j个字符所构成的子串*/
PSeqString pstr_son;
int k;
pstr_son = createNullStr_seq(j);
if(pstr_son == NULL) return NULL;
if(i>0 && i<=pstr->n && j>0){
if(pstr->n < i+j-1)
j = pstr->n -i + 1;
for(k=0;k<j;k++){
pstr_son->c[k] = pstr->c[i+k-1];
}
pstr_son->n = j;
}
return pstr_son;
}
/**
* 3.删除指定下标的字符
* @param pstr
* @param p
* @return
*/
int deleteP_SeqString(PSeqString pstr,int p){
if(pstr == NULL || isNullString_seq(pstr)){
printf("字符串不存在或为空,无法执行删除操作\n");
return -1;
}
if(p<0 || p>pstr->n){
printf("所给下标超出字符串范围\n");
return -1;
}
for(int i=p;i<pstr->n;i++){
if(i+1 != pstr->n)
pstr->c[i] = pstr->c[i+1];
}
pstr->n--;
}
/**
* 4.在指定的下标插入字符
* @param pstr
* @param p
* @param c
* @return
*/
int insertChar(PSeqString pstr,int p,char c){
if(pstr == NULL || isNullString_seq(pstr)){
printf("字符串不存在或为空,无法执行插入操作\n");
return -1;
}
if(p<0 || p>pstr->n){
printf("所给下标超出字符串范围\n");
return -1;
}
pstr->n++;
for(int i = pstr->n - 1;i > p; i--){
pstr->c[i] = pstr->c[i-1];
}
pstr->c[p] = c;
return 1;
}
/**
* 6.返回指定下标的字符
* @param pstr
* @param postion
* @return
*/
char charAt(PSeqString pstr,int postion){
if(pstr == NULL || isNullString_seq(pstr)){
printf("字符串不存在或字符串长度为空\n");
return '!';
}
return pstr->c[postion - 1];
}
/**
* 7.拼接两个字符串
* @param s1
* @param s2
* @return
*/
PSeqString concat(PSeqString s1,PSeqString s2){
int len = s1->n+s2->n;
int flag = 0;
PSeqString s = createNullStr_seq(len);
for(int i=0;i<len;i++)
{
if(i>=s1->n){
s->c[i] = s2->c[flag];
s->n++;
flag++;
}else{
s->c[i] = s1->c[i];
s->n++;
}
}
return s;
}
/**
* 8.找出子串第一次出现在主串的位置
* @param s1
* @param s2
* @return
*/
int Index(PSeqString s1,PSeqString s2){
if(s1 == NULL || isNullString_seq(s1)){
printf("主串不存在或为空,无法执行操作\n");
return -1;
}
if(s2 == NULL || isNullString_seq(s2))
return -1;
int p = 0;
int mark = 1;
for(int i=0;i<=s1->n;i++){
if(p == s2->n){
return (i - p);
}
if(s1->c[i] != s2->c[p]){
//如果不匹配,指针回溯
i = mark - 1;
mark++;
p = 0;
}else{
p++;
}
}
return -1;
}
int* findNext(PSeqString s){
int* next = (int*)malloc(sizeof(int) * s->n);
next[0] = -1;
int i = 0, k = -1;
while(i < s->n-1) //k = 2 , i = 4 , next[3] = 1;
{
while(k >= 0 && s->c[i] != s->c[k])
k = next[k];
i++;
k++;
next[i] = k;
}
return next;
}
int KMP(PSeqString s1,PSeqString s2,int* next){
if(s1 == NULL || isNullString_seq(s1)){
printf("主串不存在或为空,无法执行操作\n");
return -1;
}
if(s2 == NULL || isNullString_seq(s2)){
return -1;
}
int i = 0 , j = 0;
while(i < s1->n && j < s2->n)
{
if(j == -1 || s1->c[i] == s2->c[j]){
i++;j++;
}else{
j = next[j];
}
}
if(j >= s2->n)
return i - (s2->n);
else
return -1;
}
int main(){
//测试KMP算法:
printf("测试KMP算法:\n");
char t2[] = {'A','B','A','B','A','A','A','C','A','B','A','A'};
char t3[] = {'A','C','A'};
int size3 = (sizeof(t2) / sizeof(char));
int size4 = (sizeof(t3) / sizeof(char));
printf("%d\n",size3);
printf("%d\n",size4);
PSeqString test2 = createNullStr_seq(100);
PSeqString test3 = createNullStr_seq(100);
initString(test2,t2,size3);
initString(test3,t3,size4);
printString(test2);
printString(test3);
int* next = findNext(test3);
for(int i=0;i<size4;i++)
{
printf("%d ",next[i]);
}
printf("\n");
printf("KMP是否找到:%d\n",KMP(test2,test3,next));
}