串的基本操作

串的定义

串:是一种特殊的线性表,它是由字符组成的,是由零个或多个字符组成的有限序列。一般记为:

S = "a~1~a~2~a~3~……a~n~" (n≥0) 如:A= "BEIJING", B= "JING"

串相关概念

  • 空串(null string):长度为零的串,它不包含任何字符。

  • 空格串(black string):任由一个或多个空格组成的串,长度大于等于1

  • 子串(sub string):串中任意个连续字符的组成的子序列称为该串的“子串”

  • 主串(master string):包含子串的串相应的称为“主串”,因此子串是主串的一部分

  • 串长度:当前字符串的元素个数,不包含字符串结束标记\0

  • 前缀:除了最后一个字符以外,一个字符串的全部头部组合

  • 后缀:除了第一个字符以外,一个字符串的全部尾部组合

串常见操作

串的操作不局限于插入、删除元素,而是各种查找,替换的操作,串的数据对象限制为字符,并且一般以串作为整体进行操作,主要有以下操作:

  • 创建串

  • 插入子串

  • 查找子串//关键

    • BF匹配

    • KMP匹配

  • 删除串

    • 区间删除

    • 删除子串

  • 求串长度

  • 串连接

  • 串比较

  • 串拷贝

typedef struct String 
{
	char *pstr;
	size_t count;
}String;

创建字符串

String* create_string(const char* str) 
{
	String* temp = (String*)calloc(1, sizeof(String));
	assert(temp);
	temp->count = strlen(str);//设置长度
	temp->pstr = (char*)calloc(temp->count + 1, sizeof(char));//开辟空间
	strcpy_s(temp->pstr,temp->count+1, str);写入串内
	return temp;
}

打印字符串

void print_string(String* str)
{
	puts(str->pstr);
}

判断是否为空串

bool empty_string(String* str)
{
	if (str == NULL)
		return true;
	return str->count==0;
}

把字符串插到原串的pos位置

void insert_string(String* str, const char* data, int pos)
{
	assert(str);
	//1.求数据的长度
	//Iloveyou -->8
	//520   -->3
	int len = strlen(data);
	char* temp = realloc(str->pstr, str->count + len + 1);//第二个参数传入的是目标内存地址长度
	assert(temp);
	str->pstr = temp;
	//2.考虑pos有效性
	if (pos > str->count||pos<1)//如果超出原串长度新串直接加在后面
	{
#if 0
		//序号无效,直接不做出
		return;
#endif
		for (int i = 0; i < len+1; i++) 
		{
			str->pstr[str->count++] = data[i];
		}
	}
	else 
	{
		//位序到数组下标转换
		pos = pos - 1;			
		//Iloveyou -->8
		//520   -->3
		//Il520oveyou
		//先腾出位置
		for (int i = str->count; i >= pos; i--) 
		{
			str->pstr[i + len] = str->pstr[i];
		}
		//插入元素
		for (int i = 0; i < len; i++) 
		{
			str->pstr[i + pos] = data[i];
		}
		str->count += len;
	}
}

 删除部分元素

void erase_string(String* str, int start, int end)
{
	//1.区间有效性
	if (start > end || end > str->count || start <= 0) 
	{
		printf("区间无效!\n");
		return;
	}
	//2.删除元素数
	int size = end - start + 1;
	//3.数组伪删除
	for (int i = end, j = start - 1; i < str->count; i++, j++) 
	{
		str->pstr[j] = str->pstr[i];
	}
	//4.后面内存手动置为\0
	for (int i = str->count; i >= str->count - size; i--) 
	{
		str->pstr[i] = '\0';
	}
	//5.真正删除是计数的改变
	str->count -= size;
}

复制

void copy_string(String* str1, String* str2)
{
	assert(str1);
	assert(str2);
	free(str1->pstr);
	str1->count = str2->count;
	str1->pstr = (char*)calloc(str2->count + 1, sizeof(char));
	strcpy_s(str1->pstr, str1->count+1, str2->pstr);
}

串添加一个元素

void cat_string(String* str1, String* str2)
{
	assert(str1);
	assert(str2);
	char* temp = get_string(str2);
	insert_string(str1, temp, str1->count+1);
}

字符串长度比较

int compare_string(String* str1, String* str2)
{
	assert(str1);
	assert(str2);
	return strcmp(str1->pstr,str2->pstr);
}
int compare_string(String* str1, String* str2)
{
    assert(str1);
    assert(str2);
    while(*str1==*str2)
{
if(*str1=='\0')
{return 0;
}
str1++;
str2++;
}
return *str1-*str2;
    
}

释放串与将串的值读取出来、

void destory_string(String* str1)
{
	assert(str1);
	free(str1->pstr);
	free(str1);
}

char* get_string(String* str1)
{
	return str1->pstr;
}

bf算法直接查找子串位置,并进行删除(暴力的方法可能导致超时)

int bf_string(String* str1, String* str2)
{
	int index = 0;
	int i = 0;
	int j = 0;
	while (str1->pstr[i] != '\0' && str2->pstr[j] != '\0')
	{
		if (str1->pstr[i] == str2->pstr[j])
		{
			i++;
			j++;
		}
		else
		{
			index++;		//比较位置换成下一个位置
			j = 0;
			i = index;
		}
	}
	if (str2->pstr[j] == '\0')
	{
		return index;
	}
	return -1;
}

void erase_bf_string(String* str1, String* str2)
{
	int pos = bf_string(str1, str2);
	if (pos == -1) 
	{
		return;
	}
	int start = pos + 1;
	int end = str2->count+start;
	erase_string(str1, start, end);
}

KMP算法

什么是KMP算法

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。

部分匹配表

KMP算法的核心是部分匹配表(Partial Match Table)的数组"就是"前缀"和"后缀"的最长的共有元素的长度

关键:移动位数 = 已匹配的字符数 - 对应的部分匹配值

 先获取部分匹配值

void get_next_string(String* str, int next[])
{
	int len = str->count;
	int i = 0;
	int j = -1;
	next[0] = -1;
	while (i < len) 
	{
		//ABCBA 
		if (j == -1 || str->pstr[i] == str->pstr[j]) 
		{
			i++;
			j++;
			next[i] = j;   //next[0]=0  j=0 i=1
		}
		else 
		{
			j = next[j];
		}
	}
}

在进行kmp匹配删除

int kmp_string(String* str1, String* str2)
{
	int count = str2->count;
	int* next = (int*)calloc(count + 1, sizeof(int));
	assert(next);
	get_next_string(str2, next);
	int i = 0;
	int j = 0;
	while (i < str1->count && j < str2->count) 
	{
		if (j == -1 || str1->pstr[i] == str2->pstr[j]) //初始或者两字符相同
		{
			i++;
			j++;
		}
		else 
		{
			j = next[j];
		}
	}
	if (j == str2->count) 
	{
		return i - j;//返回起点
	}
	return -1;
}

也可以打断点测试 F10 F5 单步调试

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值