(顺序存储)串的基本操作(包含BP,KMP)

#define _CRT_SEURE_NO_WARNINGS
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100
using namespace std;

typedef struct st
{
	char* ch;
	int length;
	int strSize;
}String;

String creatNullString()
{
	String str;
	str.length = 0;
	str.strSize = MAXSIZE;
	str.ch = (char*)malloc(MAXSIZE*sizeof(char));
	return str;
}


bool isEmpty(String str)
{
	if (str.length == 0)
	{
		return true;
	}
	else
	{
		return false;
	}
}

void strAssign(String* str,const char str2[])//串赋值
{
	int i = 0;
	while (str2[i] != '\0')//str2长度
	{
		i++;
	}
	if (str->length < i)
	{
		char* temp = str->ch;
		str->ch = (char*)realloc(str->ch,i * sizeof(char));
		str->strSize = i;
		free(temp);
	}
	str->length = i;
	for (i = 0; i < str->length; i++)
	{
		str->ch[i] = str2[i];
	}
}

void strCopy(String* str1, String str2)
{
	if (str1->strSize < str2.strSize)
	{
		char*temp = str1->ch;
		str1->ch = (char*)realloc(str1->ch, str2.strSize);
		str1->strSize = str2.strSize;
		free(temp);
	}
	str1->length = str2.length;
	for (int i = 0; i < str1->length; i++)
	{
		str1->ch[i] = str2.ch[i];
	}
}

void strConcat(String* str, String str1, String str2)
{
	int i;
	if (str->strSize < str1.length + str2.length)
	{
		char* temp = str->ch;
		str->ch = (char*)realloc(str->ch,(str1.length + str2.length) * sizeof(char));
		str->strSize = str1.length + str2.length;
		free(temp);
	}
	str->length = str1.length + str2.length;
	for (i = 0; i < str1.length; i++)
	{
		str->ch[i] = str1.ch[i];
	}
	for (i = str1.length; i < str->length; i++)
	{
		str->ch[i] = str2.ch[i];
	}
}

int subString(String s, int begin, int len, String* t)//取子串
{
	if (begin <= 0 || len<0 || len>s.length || len > s.length - begin)
	{
		printf("参数有误!");
		return 0;
	}
	t->length = len;
	for (int i = 0; i < t->length; i++)
	{
		t->ch[i] = s.ch[begin - 1 + i];
	}
	return 1;
}


int insertString(String* str, int begin, String str1)//把str1插到str第begin个之后
{
	int i;
	if (begin <= 0 || begin > str->length)
	{
		printf("参数有误!");
		return 0;
	}
	if (str->strSize < str->length + str1.length)
	{
		char* temp= str->ch;
		str->ch = (char*)realloc(str->ch, (str->length + str1.length) * sizeof(char));
		str->strSize = str->length + str1.length;
		free(temp);
	}
	for (i = str->length - 1; i >= begin; i--)
	{
		str->ch[i + str1.length] = str->ch[i];
	}
	str->length = str->length + str1.length;
	for (i = 0; i <= str1.length; i++)
	{
		str->ch[begin + i] = str1.ch[i];
	}
}


int indexOf(String s, String t, int index)//从下标为index开始找
{
	if (isEmpty(t) || t.length > s.length || index <= 0 || index > s.length)
	{
		printf("参数有误");
		return -1;
	}
	int i = index;
	int j = 1;
	while (i<=s.length && j<=t.length)
	{
		if (s.ch[i-1] == t.ch[j-1])
		{
			i++;
			j++;
		}
		else
		{
			i = i - j + 2;
			j = 1;
		}
		if (j == t.length+1)
		{
			return i - j + 1;
		}
	}
	return -1;
}

int indexOf1(String s, String t, int index)//从下标为index开始找
{
	if (isEmpty(t) || t.length > s.length || index <= 0 || index > s.length)
	{
		printf("参数有误");
		return -1;
	}
	int i = index;
	int j = 1;
	while (i <= s.length && j <= t.length)
	{
		if (s.ch[i-1] == t.ch[j-1])
		{
			i++;
			j++;
		}
		else
		{
			i = i - j + 2;
			j = 1;
		}
	}
	//printf("%d", i);
	//printf("%d", j);
	if (j == t.length+1)
	{
		return i - j + 1;
	}
	else
	{
		return -1;
	}
}



void print(const String str)
{
	for (int i = 0; i < str.length; i++)
	{
		cout << str.ch[i];
	}
}


void getNext(const String str,int next[])
{
	int i = 1;//长
	int j = 0;//模式串
	next[1] = 0;
	while (i < str.length)//next[1...str.length]  当i==str.length-1时进循环,i++后i==str.length,正好操作next[str.length].
	{
		if (j == 0 || str.ch[i-1] == str.ch[j-1])
		{										 //给next[i+1]赋值的时候,串的第i个元素也一定在比较的if条件里(给next[6]赋值时,比较的条件一定有a[4]),a[4]是第五个元素,进if后先加1变6,然后执行next[6]=j(正好是第六个元素的next值)
												 //给第i个元素赋next值得时候,它的前一个元素一定在比较的条件里			
			next[i + 1] = j + 1;				 //如果一样,就进if,给next[i]赋值
			i++;							     //如果不一样且j!=0,那么i不动,j回撤。对于j:
			j++;							     //1.最坏j退到0,然后进if,执行j++变1,然后给next[i],这说明:在第i个字符之前的字符没有任何重叠部分(abcda)a的next值(next[5]==1)
											     //2.j不一定退到0,他可以退到next[j],next[j]表示:子串的第j个元素和主串某个字符在比较的时候,如果不匹配,可以从子串的第next[j]个元素开始继续和主串的该字符进行匹配
											     //主串的失配字符往前,和子串的第next[j]个字符前(一直到开头)的串是一样的(就不用再比了)
											     //而j!=0且ch[i-1]!=ch[j-1],说明主串第i个字符和子串第j个字符失配了,这时i不动,ch[i-1]为第i个字符继续待比较;j=next[j](从第next[j]个位置开始比较)
												 //所以ch[j-1]正好是第j(next[j])个字符								
		}
		else
		{
			j = next[j];//j除了一开始,再想要变0,只能进这个else
		}
	}
	for (i = 1; i <= 20; i++)
		printf("%d", next[i]);
}
//整个循环过程:next[1]==0 (j==next[1])
//第一次while结束后:next[2]==1,i==2,j==1(j==next[2]);(第一次while是固定的,得到的结果对于任何串都一样)
//第二次while开始:i==2,j==1 进if里比较(ch[1]==ch[0])也就是第一个字符和第二个字符比较
//1.相等:执行next[i+1]=j+1;也就是next[3]==2(给第三个元素赋next值时,比的是前两个元素,相等意味着这个串为aaxxx或者bbxxx)这个时候j==next[3]
//2.不等:(j==1不为0)进else把j变成0(j==next[1]),第三次while时一定进if,让next[3]==1

void getNext1(const String str, int next[])
{
	int i = 1;
	int j = 0;
	next[1] = 0;
	while (i < str.length)
	{
		if(j == 0 || str.ch[j - 1] == str.ch[i - 1])
		{
			j = j + 1;
			i = i + 1;
			if (str.ch[j - 1] != str.ch[i - 1])
			{
				next[i] = j;
			}
			else
			{
				next[i] = next[j];
			}
		}
		else
		{
			j = next[j];
		}
	}
	for (i = 1; i <= 20; i++)
		printf("%d", next[i]);
}


int KMP(String str1, String str2)
{
	int i = 1;
	int j = 1;
	int next[30];
	getNext1(str2, next);
	while (i <= str1.length && j<= str2.length)
	{
		if (j == 0||str2.ch[j - 1] == str1.ch[i - 1])
		{
			i++;
			j++;
		}
		else
		{
			j = next[j];
		}
	}
	if (j == str2.length + 1)
	{
		return i - str2.length;
	}
	else
	{
		return -1;
	}
}

	


int main()
{
	String s1 = creatNullString();
	String s2 = creatNullString();
	String s3 = creatNullString();
	const char* p3 = "abaaaaa";
	
	const char* p1 = "sbcd";
	const char* p2 = "efgh";
	//int next[28] = {100};
	strAssign(&s1,p1);
	strAssign(&s2,p2);
	//getNext1(s1, next);
	//int x = KMP(s1, s2);
	//printf("%d", x);
	//对于栈操作那个,是把一个pHead指针赋值给一个形参指针,形参指针只是pHead的一个副本,对形参的操作(开辟堆内存,赋值),在功能函数结束之后就被销毁了,pHead依然为空,不会改变。
	//但这个不同,这是通过指针修改s1里的内容。把s1的地址给形参指针,通过指针修改s1里堆内存的内容,s1会改变。
	strConcat(&s3, s1, s2);
	print(s3);
}
基于定长顺序存储结构实现对的赋值、比较、求子的位置、替换等操作。要求所有操作均以函数的形式实现,在主函数中调用各个函数实现整体功能。 注意:每一个字符的第一个元素存放的是该字符的长度(不包括第一个元素),除的赋值外,其他所有操作(比较、求子的位置、替换)等都不应包含该字符。 1.1.实验1:赋值函数实现: 按照系统已经定义的函数接口编写函数实体,实现:将输入数组StrInput[]的数据赋值给待赋值数组StrTobeAssigned[],其中待赋值数组StrTobeAssigned[0]存放有效数据的长度,StrTobeAssigned[1]之后存放带赋值数据。 具体要求和相关假设为: ① 函数接口定义为:int MyStrAssign(char * StrTobeAssigned, char * StrInput); ② 输入参数:待赋值字符变量StrTobeAssigned,字符的期望值StrInput; ③ 输出参数:无; ④ 处理规则及返回值:将StrTobeAssigned[1]及之后的内容赋值为StrInput的有效内容,StrTobeAssigned[0]赋值为StrInput有效字符的长度,并返回1; ⑤ 假设: a)两个字符均不为空; b)StrInput存放的是一个完成的字符(不包含长度); c)赞不考虑输入数据超过数组总长度的情况。 1.2实验2:替换函数: 按照系统已经定义的函数接口编写函数实体,实现:在主中MainStr查找是否存在某特定子SubStr1,若存在则将所有的SubStr1替换为新的指定子SubStr2,函数返回字符替换的次数。 具体要求和相关假设为: ① 函数接口定义为:int MyStrReplace(char * MainStr, char * SubStr1, char * SubStr2); ② 输入参数:主变量MainStr,子变量SubStr1,SubStr2; ③ 输出参数:无; ④ 处理规则及返回值:若主中存在子,用SubStr2替换主MainStr中出现的所有与SubStr1相同的不重叠的子,并返回字符替换的次数;否则返回0。 ⑤ 假设: a)主和两个子均不为空; b)MainStr[0]和SubStr1[0],SubStr2[0]分别存放对应字符的长度,不用替换该部分。 2.问题分析 (1)根据实验一的内容可知,我们需要通过编写函数实体的形式实现的赋值操作,主要的思路包括: (a)获得输入字符的长度len; (b)将输入字符的长度len赋值给待赋值字符的第一个元素StrTobeAssigned[0]; (c)依次将输入字符的数据赋值给待赋值字符。 (2)根据实验二的内容可知,我们需要通过编写函数实体的形式实现的替换操作,主要的思路包括: (a)遍历主MainStr,检查是否存在某特定子SubStr1; (b)如果存在则找到子在主中的位置; (c)在主中删除该子并更新主长度; (d)在主中插入该子并更新主长度; (e)过程中记录替换字符的次数,遍历结束后返回该次数(如果没有替换则为0); 如果有必要,可以使用本实验已经提供的相关函数,如:求子位置的函数MySubStrIndex(),子删除函数MyStrDelete()和子插入函数MyStrInsert()等
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值