数据结构6-串

本文介绍了字符串的基础概念,如空格串、子串、主串等,以及串的基本操作,如赋值、比较、连接、子串获取等。重点讨论了串的顺序存储结构,包括静态数组和动态内存分配,并提及了链式存储结构。此外,文章详细讲解了暴力匹配(BF算法)和KMP算法,解释了KMP算法通过避免不必要的回溯提高匹配效率的原理,并提供了C语言实现KMP算法的代码示例。
摘要由CSDN通过智能技术生成

串(String)是由零个或多个任意字符组成的有限序列,又名字符串。
是一种特殊的内容受限的线性表
在这里插入图片描述
相关术语:

  • 空格串:由一个或多个空格组成的串,与空串不同,空格串有内容有长度且只由空格组成
  • 子串:串中任意个连续的字符组成的子序列(含空串)称为该串的子串
  • 主串:包含子串的串就相应的称为主串
  • 字符位置:字符在序列中的序号为该字符在串中的位置
  • 子串位置:子串第一个字符在主串中的位置
  • 串相等:当且仅当两个串长度相等,并且各个对应位置上的字符都相同时,这两个串才是相等的
    所有的空串都相等
  • 串的应用非常广泛,计算机的大多数非数值处理的对象大多数是字符串数据,例如:文字编辑、符号处理,各种信息系统等等
  • 串中元素逻辑关系与线性表的相同,串可以采用与线性表相同的存储结构。
    - 包括链式存储和顺序存储

串基本操作

  1. StrAssign(&T,chars)//串赋值
  2. StrCompare(S,T)//串比较
  3. StrLength(S)//求串长
  4. Concat(&T,S1,S2)//串连结
  5. SubString(&Sub,S,pos,len)//求子串
  6. StrCopy(&T,S)//串拷贝
  7. StrEmpty(S)//串判空
  8. ClearString (&S)//清空串
  9. Index(S,T,pos)//子串的位置
  10. Replace(&S,T,V)//串替换
  11. Strlnsert(&S,pos,T)//子串插入
  12. StrDelete(&S,pos,len)//子串删除
  13. DestroyString(&S)//串销毁

串的存储方式

串的顺序存储

在这里插入图片描述

1)静态数组,字符串有最大长度限制。

#define MAXSIZE 100//字符串的最大长度
typedef struct
{
	char data[MAXSIZE];//用数组存储字符串中的元素
	unsigned int length;//字符串中元素的个数
)String;

2)动态分配内存,字符串的长度可以自动护展。

typedef struct
{
	char*data;
	//存储字符串中元素的首地址。
	unsigned int maxsize;//字符串的最大长度。
	unsigned int length;//字符串的实际长度。
}String;

串的链式存储

在这里插入图片描述
在这里插入图片描述

typedef struct LNode
{
	char data;//每个结点一个字符。
	struct Lnode *next;
}LNode,*String;
//块串:实际不常用
#define NLENGTH 10
//每个结点的字符数。
typedef struct LNode{
	char data[NLENGTH];//每个结点NLENGTH个字符。
	struct Lnode*next;
}LNode,*String;

串的匹配算法

算法目的:确定主串中所含子串(模式串)第一次出现的位置(定位)
主串:
(模式串)子串:

BF算法

BF算法,即暴力(Brute Force)算法,是普通的模式匹配算法,BF算法的思想就是将主串SS的第一
个字符与模式串TT的第一个字符进行匹配,若相等,则继续比较SS的第二个字符和TT的第二个字
符;若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果。
BF算法是一种蛮力算法。

KMP算法

KMP是BF优化,KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与目标串的匹配次数以达到快速匹配
目的。KMP算法的时间复杂度O(m+n),BF算法是O(mn)。

前缀:
后缀:
公共前后缀:

KMP算法的原理:

  1. 在匹配的过程中,目标串的指针不需要不回溯,只回溯模式串的指针;
  2. 如果模式串和目标串前n个字符匹配成功,遇到匹配失败的字符时,模式串的指针回溯的位置由模式串的内容决定(回溯到匹配失败位置前的模式串内容的最长公共前后缀的长度+1),然后继续比较。

KMP算法的核心是求next数组。

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <cstring>

//函数结果状态代码 
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define MAXSIZE 255
//Status 是函数的类型,其值是函数结果状态代码
typedef int Status;


typedef struct String {
	char* data;
	int len;
} String;

Status StrAssign(String *S, char *data);

void printString(String* s);

void forceMatch(String* master, String* sub);

int* getNext(String* s);

void kmpMatch(String* master, String* sub, int* next);
#include "SeqString.h"



String* initString()
{
	String* s = (String*)malloc(sizeof(String));
	s->data = NULL;
	s->len = 0;
	return s;
}


Status StrAssign(String *S, char *data)
{
	if (&S == NULL || data == NULL)
	{
		delete data;
		return ERROR;
	}
	int len = 0;
	char * temp = data;
	while (*temp)
	{
		len++;
		temp++;
	}
	if (len == 0)
	{
		S->data = NULL;
		S->len = 0;
	}
	else
	{
		temp = data;
		S->len = len;
		S->data = (char *)malloc(sizeof(char) * (len + 1));
		for (int i = 0; i < len; i++, temp++)
		{
			S->data[i] = *temp;
		}
	}
}


void printString(String* s) 
{
	for (int i = 0; i < s->len; i++) {
		printf(i == 0 ? "%c " : "-> %c ", s->data[i]);
	}
	printf("\n");
}


void forceMatch(String* master, String* sub)
{
	int i = 0;
	int j = 0;
	while (i < master->len && j < sub->len)
	{
		if (master->data[i] == sub->data[j])
		{
			i++;
			j++;
		}
		else
		{
			i = i - j + 1;
			j = 0;
		}
	}
	if (j == sub->len)
	{
		printf("force match success.\n");
		printf("子串在主串中的位置为%d\n", i - sub->len);
	}
	else
	{
		printf("force match fail.\n");
	}
}


int* getNext(String* s)
{
	int* next = (int*)malloc(sizeof(int) * s->len);
	int i = 0;
	int j = -1;
	next[i] = j;
	while (i < s->len - 1) {
		if (j == -1 || s->data[i] == s->data[j]) {
			i++;
			j++;
			next[i] = j;
		}
		else {
			j = next[j];
		}
	}
	return next;
}


void printNext(int* next, int len) 
{
	for (int i = 0; i < len; i++) {
		printf(i == 0 ? "%d " : "-> %d ", next[i] + 1);
	}
	printf("\n");
}


void kmpMatch(String* master, String* sub, int* next) 
{
	int i = 0;
	int j = 0;
	while (i < master->len && j < sub->len) {
		if (j == -1 || master->data[i] == sub->data[j]) {
			i++;
			j++;
		}
		else {
			j = next[j];
		}
	}
	if (j == sub->len) {
		printf("kmp match success.\n");
		printf("子串在主串中的位置为%d\n", i - sub->len);
	}
	else {
		printf("kmp match fail.\n");
	}
}


void test01()
{
	String* s = initString();
	String* s1 = initString();
	StrAssign(s, "abaabbabc");
	StrAssign(s1, "abc");
	printString(s);
	printString(s1);
	forceMatch(s, s1);
}
void test02()
{
	String* s = initString();
	String* s1 = initString();
	StrAssign(s, "abaabbabc");
	StrAssign(s1, "abc");
	printString(s);
	printString(s1);
	int* next = getNext(s1);
	printNext(next, s1->len);
	kmpMatch(s, s1, next);

}
int main() {

	test02();

	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值