数据结构 | 第五章 串

一、串

1、定义
  • 零个多个字符组成的有限序列;
  • 空串:零个字符的串;
  • 空格串包含空格;
  • 字串任意个数的连续字符组成的子序列;
2、串的比较

通过ASCII编码来比较

3、朴素的模式匹配算法

模式匹配:字串的定位操作;
时间复杂度:O(n+m)

4、KMP的模式匹配算法

大大避免重复遍历的情况。

5、串的相关代码说明
5.1 初始化堆字符串
/*@ 初始化堆字符串 */
void Init_HeapString(HString *str)
{
	str->ch = NULL;
	str->length = 0;
}

将字符串指针赋值为NULL以及长度清零

5.2 字符串赋值
/*@ 字符串赋值 */
Status Assignstr_Headpstring(HString *str, char * newStr)
{
	int i;
	int len = GetLength_Heap(newStr);	// 获取新字符串的长度
	if (!len){
		return ERROR;
	}

	Init_HeapString(str);	// 初始化
	str->ch = (char *)malloc(sizeof(char)* len);
	if (!str->ch){
		return ERROR;
	}

	for (i = 0; i < len; ++i)
	{
		str->ch[i] = newStr[i];
	}
	str->length = len;

	return OK;
}

赋值前需要先将该str初始化,通过GetLength_Heap函数或者字符串的长度,相应长度的堆空间申请。在进行赋值。

5.3 获取字符串的长度
/*@ 获取字符串的长度 */
int GetLength_Heap(char *Str)
{
	int len = 0; 
	while (Str[len] != '\0')// 字符串结束为\0
	{
		len++;
	}
	return len;
}

将变量循环加一,直至字符等于\0结束。

5.4 复制字符串
/*@ 复制字符串 */
Status CopyStr_Heap(HString *destStr, HString *srcStr){
	Init_HeapString(destStr);	// 初始化字符
	if (isEmpty(srcStr)){	// 若源字符串为空,则不能复制
		printf("该源字符串为空,不能进行复制...");
		return ERROR;
	}
	destStr->ch = (char*)malloc(sizeof(srcStr) * srcStr->length);// 申请空间
	if (!destStr->ch){
		return ERROR;	// 是否申请成功
	}
	int i = 0;
	for (i; i < srcStr->length; ++i){
		destStr->ch[i] = srcStr->ch[i];	// 赋值给新的字符串
	}
	destStr->length = srcStr->length;	// 将长度赋值给新的字符串

	return OK;
}

初始化destStr,申请空间,字符串赋值。

5.5 字符串拼接
/*@ 字符串拼接 将destStr的字符串拼接到srcStr上 */
Status ConcatStr_Heap(HString *destStr, HString *Str1, HString *Str2){
	Init_HeapString(destStr);	// 初始化
	destStr->length = Str1->length + Str2->length;
	destStr->ch = (char *)malloc(sizeof(char)* destStr->length);
	if (!destStr->ch){
		exit(OVERFLOW);
	}
	int i;
	for (i = 0; i < Str1->length; ++i){
		destStr->ch[i] = Str1->ch[i];
	}
	for (i = 0; i < Str2->length; ++i){
		destStr->ch[Str1->length+i] = Str2->ch[i];
	}
	return OK;
}

初始化destStr,先将Str1赋值到destStr,在将Str2赋值到destStr上。

5.6 比较俩个字符串
/*@ 比较俩个字符串 相等-0;大于正数;小于负数*/
Status StrCompare_Heap(HString *str1, HString *str2){
	int i = 0; 
	for (i; i < str1->length && str2->length; ++i){
		if (str1->ch[i] != str2->ch[i]){	// 当俩个字符不相等时,即判断ASCII的大小
			return str1->ch[i] - str2->ch[i];
		}
	}
	return str1->length - str2->length;	// 若字符相等,则判断长度
}

通过循环判断字符串的ASCII的大小,若都相等则在判断长度

5.7 截取字符串
/*@ 截取字符串 */
Status SubString_Heap(HString *destStr, HString *srcStr, int pos, int len){
	if (srcStr->length == 0 || len == 0 || len + pos - 1 > srcStr->length || pos < 1
		|| pos > srcStr->length || len < 0){
		return ERROR;
	}
	Init_HeapString(destStr);	
	destStr->ch = (char *)malloc(sizeof(char)* len);
	if (!destStr->ch) 	exit(OVERFLOW);
	int i;
	for (i = 0; i < len; ++i){
		destStr->ch[i] = srcStr->ch[pos + i -1];
	}
	destStr->length = len;

	return OK;
}

初始化destStr,通过循环将pos位置后len长度的字符串截取到destStr,注意长度等前提条件。

5.8 索引子串位置
/*@ 返回从pos位置开始的子串在父串中的位置 */
int Indexchild_Heap(HString *srcStr, HString *child, int pos){
	if (pos < 0) return ERROR;	
	HString *subStr = (HString *)malloc(sizeof(HString));
	Init_HeapString(subStr);
	int i = pos;
	while (i + child->length - 1 <= srcStr->length){	// 循环判断长度是否大于主串
		SubString_Heap(subStr, srcStr, i, child->length);	// 截取字符串
		if (StrCompare_Heap(subStr, child) == EQ){	// 判断字串和截取的字符串是否相等

			return i;
		}else{
			i++;
		}
	}
	free(subStr);
	return 0;
}

循环从srcStr截取child长度的字符串child字符串比较若相等则返回该索引。

5.9 字符串插入
/*@ 字符串插入 */
Status InsertStr_Heap(HString *srcStr, HString *insertSrc, int pos){
	if (isEmpty(srcStr) || isEmpty(insertSrc)) return ERROR;
	if (pos < 1 || pos > srcStr->length + 1) return ERROR;
	srcStr->length += insertSrc->length;
	srcStr->ch = (char *)realloc(srcStr->ch, (srcStr->length)*sizeof(char));
	int i;
	// 腾出空间
	for (i = srcStr->length -1; i > pos - 1; --i){
		srcStr->ch[i] = srcStr->ch[i-insertSrc->length];
	}

	for (i = 0; i < insertSrc->length; ++i){
		srcStr->ch[i+ pos - 1] = insertSrc->ch[i];
	}

	return OK;
}

获取插入字符串的长度,对srcStr进行空间重新申请。将srcStr中pos到末尾的字符串向后移动,在将insertSrc字符串插入

5.10 删除字符串
/*@ 从pos开始删除len长度的字符 */
Status DeleteStr_Heap(HString *srcStr, int pos, int len){
	if (isEmpty(srcStr)) return ERROR;
	if (len<0 || len + pos - 1> srcStr->length || pos < 1){
		return ERROR;
	}
	int i;
	for (i = pos - 1; i < srcStr->length - len; ++i){
		srcStr->ch[i] = srcStr->ch[len + i];
	}
	srcStr->length -= len;
	srcStr->ch = (char *)realloc(srcStr->ch, srcStr->length * sizeof(char));// 重新分配空间
	return OK;
}

将pos位置开始len长度后的字符串往pos的位置赋值。在重新分配空间

5.11 替换字符
/*@ 替换字符 */
Status ReplaceStr_Heap(HString *str, HString oldStr, HString newStr){
	if (isEmpty(str) || isEmpty(str)) return ERROR;
	int pos = Indexchild_Heap(str, &oldStr, 1);
	while (pos != 0)
	{
		pos = Indexchild_Heap(str, &oldStr, 1);
		DeleteStr_Heap(str, pos, oldStr.length);
		InsertStr_Heap(str, &newStr, pos);
	}


	return OK;
}

获取oldStr在str中的位置,使用DeleteStr_Heap将他删除,在使用InsertStr_Heap对它进行插入。

5.12 暴风算法返回子串在主串中的位置
/*@ 使用暴风算法返回子串在主串中的位置 */
int BFIndex_Heap(HString *destStr, HString *child, int pos){
	int i = pos, j = 1;
	
	while (i <= destStr->length - 1 && j <= child->length){
		if (destStr->ch[i - 1] == child->ch[j - 1]){
			j++;
			i++;
		}
		else{
			i = i - j + 2;
			j = 1;
		}
	}
	if (j>child->length){
		return i - child->length;
	}
	return 0;
}

循环判断destStr与child是否相等,若不相等则i不回溯,直接接着下一个字符开始。

5.13 KMP算法

/*@ 获取next数组保存子串的前缀与后缀的最长匹配【部分匹配表】 */
Status GetNext_Heap(HString *srcStr, int *next){
	int j = -1, i = 0;
	next[0] = j;
	while (i < srcStr->length){
		if (j == -1 || srcStr->ch[i] == srcStr->ch[j]){
			++i;
			++j;
			next[i] = j;
		}else{
			j = next[j];
		}
	}

	return OK;
}

/*@ KMP算法 */
int KMPIndex_Heap(HString *destStr, HString *child, int pos){
	int next[255];
	GetNext_Heap(destStr, next);
	int i = pos - 1;
	int j = 0;
	while (i < destStr->length - 1 && j < child->length){
		if (j == -1 || destStr->ch[i] == child->ch[j]){
			++j;
			++i;
		}else{
			j = next[j];
		}
	}
	if (j == child->length){
		return i + 1 - child->length;
	}
	return 0;
}

先获取前缀与后缀的最长匹配,通过next来获取子串的下一个索引位置

5.14 打印字符串
/*@ 打印字符串 */
void PPrint_Heap(HString *str){
	if (!str->ch || str->length == 0){
		printf("堆中字符串为空!\n");
		return;
	}
	int i = 0;
	printf("字符串为:");
	for (i; i < str->length; ++i){
		printf("%c", str->ch[i]);
	}
	printf("\n");
}
5.15 判断是否为空
/*@ 判断是否为空 */
Status isEmpty(HString *str)
{
	if (str->length == 0 || !str->ch){
		return TRUE;
	}

	return FALSE;
}
5.16 释放空间
/*@ 释放空间 */
void Destroy_HeapString(HString *str){
	if (str->ch != NULL){
		free(str->ch);
		str->ch = NULL;
		str->length = 0;
		printf("字符串已销毁...\n");
	}
}

6、完整代码

main

#include<stdio.h>
#include<stdlib.h>
#include "SeqString.h"
#include "MyStatusLib.h"


void test(){
	HString Str;
	Assignstr_Headpstring(&Str, "ABCDE");	// 字符串赋值

	int len = GetLength_Heap("ABCDE");
	printf("获取字符串长度:%d\n", len);

	HString copyStr;
	CopyStr_Heap(&copyStr, &Str);
	printf("复制后的");
	PPrint_Heap(&copyStr);	// 打印字符串

	HString conCatStr;
	ConcatStr_Heap(&conCatStr, &copyStr, &Str);
	printf("拼接后的");
	PPrint_Heap(&conCatStr);	// 打印字符串

	int status = StrCompare_Heap(&conCatStr, &copyStr);
	printf("比较结果为:");
	if (status > 0){
		printf("大于\n");
	}
	else if (status < 0){
		printf("小于\n");
	}
	else{
		printf("等于\n");
	}

	HString subStr;
	SubString_Heap(&subStr, &Str, 2, 2);
	printf("截取的");
	PPrint_Heap(&subStr);

	int pos = Indexchild_Heap(&conCatStr, &Str, 3);
	printf("子串在父串的位置:%d\n", pos);

	InsertStr_Heap(&Str, &subStr, 2);
	printf("插入后的");
	PPrint_Heap(&Str);

	DeleteStr_Heap(&Str, 2, 2);
	printf("删除后");
	PPrint_Heap(&Str);

	HString oldStr, newStr;
	Assignstr_Headpstring(&oldStr, "D");
	Assignstr_Headpstring(&newStr, "S");

	ReplaceStr_Heap(&Str, oldStr, newStr);
	printf("替换后");
	PPrint_Heap(&Str);

	HString BStr, FStr;
	Assignstr_Headpstring(&BStr, "ASSSBD");
	Assignstr_Headpstring(&FStr, "SB");

	int x = BFIndex_Heap(&BStr, &FStr, 2);
	int y = KMPIndex_Heap(&BStr, &FStr, 2);
	printf("BF 算法:%d\nKMP算法:%d\n", x, y);

	Destroy_HeapString(&Str);	// 销毁字符串
}



int main(){

	test();

	system("pause");
	return OK;
}

SeqString.cpp

#include "SeqString.h"


/*@ 初始化堆字符串 */
void Init_HeapString(HString *str)
{
	str->ch = NULL;
	str->length = 0;
}

/*@ 字符串赋值 */
Status Assignstr_Headpstring(HString *str, char * newStr)
{
	int i;
	int len = GetLength_Heap(newStr);	// 获取新字符串的长度
	if (!len){
		return ERROR;
	}

	Init_HeapString(str);	// 初始化
	str->ch = (char *)malloc(sizeof(char)* len);
	if (!str->ch){
		return ERROR;
	}

	for (i = 0; i < len; ++i)
	{
		str->ch[i] = newStr[i];
	}
	str->length = len;

	return OK;
}


/*@ 获取字符串的长度 */
int GetLength_Heap(char *Str)
{
	int len = 0; 
	while (Str[len] != '\0')// 字符串结束为\0
	{
		len++;
	}

	return len;
}

/*@ 复制字符串 */
Status CopyStr_Heap(HString *destStr, HString *srcStr){
	Init_HeapString(destStr);	// 初始化字符
	if (isEmpty(srcStr)){	// 若源字符串为空,则不能复制
		printf("该源字符串为空,不能进行复制...");
		return ERROR;
	}
	destStr->ch = (char*)malloc(sizeof(srcStr) * srcStr->length);// 申请空间
	if (!destStr->ch){
		return ERROR;	// 是否申请成功
	}
	int i = 0;
	for (i; i < srcStr->length; ++i){
		destStr->ch[i] = srcStr->ch[i];	// 赋值给新的字符串
	}
	destStr->length = srcStr->length;	// 将长度赋值给新的字符串

	return OK;
}

/*@ 字符串拼接 将destStr的字符串拼接到srcStr上 */
Status ConcatStr_Heap(HString *destStr, HString *Str1, HString *Str2){
	Init_HeapString(destStr);	// 初始化
	destStr->length = Str1->length + Str2->length;
	destStr->ch = (char *)malloc(sizeof(char)* destStr->length);
	if (!destStr->ch){
		exit(OVERFLOW);
	}
	int i;
	for (i = 0; i < Str1->length; ++i){
		destStr->ch[i] = Str1->ch[i];
	}
	for (i = 0; i < Str2->length; ++i){
		destStr->ch[Str1->length+i] = Str2->ch[i];
	}
	return OK;
}

/*@ 比较俩个字符串 相等-0;大于正数;小于负数*/
Status StrCompare_Heap(HString *str1, HString *str2){
	int i = 0; 
	for (i; i < str1->length && str2->length; ++i){
		if (str1->ch[i] != str2->ch[i]){	// 当俩个字符不相等时,即判断ASCII的大小
			return str1->ch[i] - str2->ch[i];
		}
	}
	return str1->length - str2->length;	// 若字符相等,则判断长度
}

/*@ 截取字符串 */
Status SubString_Heap(HString *destStr, HString *srcStr, int pos, int len){
	if (srcStr->length == 0 || len == 0 || len + pos - 1 > srcStr->length || pos < 1
		|| pos > srcStr->length || len < 0){
		return ERROR;
	}
	Init_HeapString(destStr);	
	destStr->ch = (char *)malloc(sizeof(char)* len);
	if (!destStr->ch) 	exit(OVERFLOW);
	int i;
	for (i = 0; i < len; ++i){
		destStr->ch[i] = srcStr->ch[pos + i -1];
	}
	destStr->length = len;

	return OK;
}

/*@ 返回从pos位置开始的子串在父串中的位置 */
int Indexchild_Heap(HString *srcStr, HString *child, int pos){
	if (pos < 0) return ERROR;	
	HString *subStr = (HString *)malloc(sizeof(HString));
	Init_HeapString(subStr);
	int i = pos;
	while (i + child->length - 1 <= srcStr->length){	// 循环判断长度是否大于主串
		SubString_Heap(subStr, srcStr, i, child->length);	// 截取字符串
		if (StrCompare_Heap(subStr, child) == EQ){	// 判断字串和截取的字符串是否相等

			return i;
		}else{
			i++;
		}
	}
	free(subStr);
	return 0;
}

/*@ 字符串插入 */
Status InsertStr_Heap(HString *srcStr, HString *insertSrc, int pos){
	if (isEmpty(srcStr) || isEmpty(insertSrc)) return ERROR;
	if (pos < 1 || pos > srcStr->length + 1) return ERROR;
	srcStr->length += insertSrc->length;
	srcStr->ch = (char *)realloc(srcStr->ch, (srcStr->length)*sizeof(char));
	int i;
	// 腾出空间
	for (i = srcStr->length -1; i > pos - 1; --i){
		srcStr->ch[i] = srcStr->ch[i-insertSrc->length];
	}

	for (i = 0; i < insertSrc->length; ++i){
		srcStr->ch[i+ pos - 1] = insertSrc->ch[i];
	}

	return OK;
}

/*@ 从pos开始删除len长度的字符 */
Status DeleteStr_Heap(HString *srcStr, int pos, int len){
	if (isEmpty(srcStr)) return ERROR;
	if (len<0 || len + pos - 1> srcStr->length || pos < 1){
		return ERROR;
	}
	int i;
	for (i = pos - 1; i < srcStr->length - len; ++i){
		srcStr->ch[i] = srcStr->ch[len + i];
	}
	srcStr->length -= len;
	srcStr->ch = (char *)realloc(srcStr->ch, srcStr->length * sizeof(char));// 重新分配空间
	return OK;
}

/*@ 替换字符 */
Status ReplaceStr_Heap(HString *str, HString oldStr, HString newStr){
	if (isEmpty(str) || isEmpty(str)) return ERROR;
	int pos = Indexchild_Heap(str, &oldStr, 1);
	while (pos != 0)
	{
		pos = Indexchild_Heap(str, &oldStr, 1);
		DeleteStr_Heap(str, pos, oldStr.length);
		InsertStr_Heap(str, &newStr, pos);
	}


	return OK;
}

/*@ 使用暴风算法返回子串在主串中的位置 */
int BFIndex_Heap(HString *destStr, HString *child, int pos){
	int i = pos, j = 0;
	
	while (i <= destStr->length - 1 && j <= child->length){
		if (destStr->ch[i - 1] == child->ch[j - 1]){
			j++;
			i++;
		}
		else{
			i = i - j + 2;
			j = 1;
		}
	}
	if (j>child->length){
		return i - child->length;
	}
	return 0;
}

/*@ 获取next数组保存子串的前缀与后缀的最长匹配【部分匹配表】 */
Status GetNext_Heap(HString *srcStr, int *next){
	int j = -1, i = 0;
	next[0] = j;
	while (i < srcStr->length){
		if (j == -1 || srcStr->ch[i] == srcStr->ch[j]){
			++i;
			++j;
			next[i] = j;
		}else{
			j = next[j];
		}
	}

	return OK;
}

/*@ KMP算法 */
int KMPIndex_Heap(HString *destStr, HString *child, int pos){
	int next[255];
	GetNext_Heap(destStr, next);
	int i = pos - 1;
	int j = 0;
	while (i < destStr->length - 1 && j < child->length){
		if (j == -1 || destStr->ch[i] == child->ch[j]){
			++j;
			++i;
		}else{
			j = next[j];
		}
	}
	if (j == child->length){
		return i + 1 - child->length;
	}
	return 0;
}

/*@ 打印字符串 */
void PPrint_Heap(HString *str){
	if (!str->ch || str->length == 0){
		printf("堆中字符串为空!\n");
		return;
	}
	int i = 0;
	printf("字符串为:");
	for (i; i < str->length; ++i){
		printf("%c", str->ch[i]);
	}
	printf("\n");
}

/*@ 判断是否为空 */
Status isEmpty(HString *str)
{
	if (str->length == 0 || !str->ch){
		return TRUE;
	}

	return FALSE;
}

/*@ 释放空间 */
void Destroy_HeapString(HString *str){
	if (str->ch != NULL){
		free(str->ch);
		str->ch = NULL;
		str->length = 0;
		printf("字符串已销毁...\n");
	}
}


MyStatusLib.h

#pragma once

#include<stdio.h>
#include<stdlib.h>


#ifdef __cplusplus
	extern"C"{
#endif

#define ERROR 0
#define OK 1
#define TRUE 1
#define FALSE 0
#define EQ 0
#define GT 1
#define LT -1

/*@ 堆栈溢出*/
#ifndef _STATUS_H_	// 若系统中有定义以下状态码,就不用定义
	#define OVERFLOW -2
	#define UNDERFLOW -3
#endif


typedef int Status; // 自定义状态码

#ifdef __cplusplus
	}
#endif

SeqString.h

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include "MyStatusLib.h"


#define MAX_SIZE 1024
#ifdef __cplusplus
extern "C"{
#endif
	/*@ 串的堆式顺序存储结构(Heap) */
	typedef struct{
		char *ch;
		int length;
	}HString;

	/*@ 初始化堆字符串 */
	void Init_HeapString(HString *str);

	/*@ 字符串赋值 */	
	Status Assignstr_Headpstring(HString *str, char * newStr);

	/*@ 获取字符串的长度 */
	int GetLength_Heap(char *Str);

	/*@ 复制字符串 */
	Status CopyStr_Heap(HString *destStr, HString *srcStr);

	/*@ 字符串拼接 */
	Status ConcatStr_Heap(HString *destStr, HString *Str1, HString *Str2);

	/*@ 比较俩个字符串 相等-0;大于正数;小于负数*/
	Status StrCompare_Heap(HString *str1, HString *str2);

	/*@ 截取字符串 */
	Status SubString_Heap(HString *destStr, HString *srcStr, int pos, int len);

	/*@ 返回从pos位置开始的子串在父串中的位置 */
	int Indexchild_Heap(HString *dest, HString *child, int pos);

	/*@ 从pos开始删除len长度的字符 */
	Status DeleteStr_Heap(HString *srcStr, int pos, int len);

	/*@ 字符串插入 */
	Status InsertStr_Heap(HString *srcStr, HString *insertSrc, int pos);

	/*@ 替换字符 */
	Status ReplaceStr_Heap(HString *str, HString oldStr, HString newStr);

	/*@ 使用暴风算法返回子串在主串中的位置 */
	int BFIndex_Heap(HString *destStr, HString *child, int pos);

	/*@ 获取next数组 */
	Status GetNext_Heap(HString *srcStr, int *next);

	/*@ KMP算法 */
	Status KMPIndex_Heap(HString *srcStr, HString *child, int pos);

	/*@ 判断是否为空 */
	Status isEmpty(HString *str);

	/*@ 打印字符串 */
	void PPrint_Heap(HString *str);

	/*@ 释放空间 */
	void Destroy_HeapString(HString *str);

#ifdef __cplusplus
}
#endif
													end😁
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jxiepc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值