数据结构 Chap 4/ 串

一、定义及基本操作

1.定义

        由零个或多个字符组成的有限序列,记为S=‘a1a2a3...an'(n>=0)

n为串的长度,n=0时称为空串,用Phi表示;

最后不含\n,这和代码里的字符串不同喔;

子串:串中任意个连续的字符组成的子序列;

主串:包含子串的串;

字符在主串的位置:即序号,从1开始数

子串在主串的位置:即第一个字符的序号,从1开始数

空串是什么也没有 ; 而空格串是指串里全是空格字符,每个空格字符占1B空间。

 ps:串是特殊的线性表,限定了串中的存储对象,而不是外部结构(如顺序表、链表、队列等)

2.串的基本操作

        (1)与顺序表不同,串的基本操作通常以子串为操作对象,而非某一个字符;

 

 

 Unicode相当于对ASCII进行拓展,把除了英文和标点符号外的其他文字进行了收集和编码。

(2)串的顺序存储实现【包括静态数组和动态数组】

/*1.静态数组实现*/
#define MaxLen 255
typedef struct {
	char ch[MaxLen];
}SString;//static string
/*2.动态数组(堆分配存储)实现*/
typedef struct {
	char* ch;
	int length;
}HString;//heap string
int main() {
	HString S;//declaration,用完需要释放free
	S.ch = new char[MaxLen];
	S.length = 0;//Initialization
}

静态数组采用方案四,既可以保证序号与数组下标一样,还可以在O(1)时间内找到元素个数 

 (3)串的链式存储

 注:char在任何计算机都只占1个字节,但是int、float等按照32、64计算机,分别占4、8个字节。所以需要提高存储密度,每个结点存储的数据不要单单存一个字符,而是一个4B的字符串

 (3)串的基本操作

#include <iostream>
using namespace std;
#define MaxLen 255
typedef struct {
	char ch[MaxLen];
	int length;
}SString;//static string
int StrLen(SString S)
{
	return sizeof(S.ch) / sizeof(S.ch[1]);
}//Find the number of element,may "false"
/*1.复制字符串*/
void StrCopy(SString &s1, SString s2)
{
	for(int i=1;i<=s2.length;i++)//从1开始是因为下标为0的空间不存东西
		s1.ch[i] = s2.ch[i];
	s1.length = s2.length;
}
/*2.取出主串中某个位序后的子串*/
bool SubString(SString& Sub, SString S, int pos, int len)//pos即是序号也是数组下标
{
	//子串范围越界;
	if (pos- 1 + len  > S.length)//这里减一,画图理解一下
		return false;
	for (int i = pos; i < pos + len; i++)
		Sub.ch[i - pos + 1] = S.ch[i];//一开始i=pos,Sub从1开始放
	Sub.length = len;
	return true;
}
/*3. 比较字符串大小*/
int StrCompare(SString S, SString T)
{
	for (int i = 1; i <= S.length && i <= T.length; i++)
	{
		if (S.ch[i] != T.ch[i])
			return S.ch[i] - T.ch[i];
	}//compare one by one;
	return S.length - T.length;//one string used up
}
/*4.判断s中是否有和t相等的子串,有则返回位序,无则返回0*/
int index(SString S,SString T)
{
	int i = 1, n = StrLen(S), m = StrLen(T);
	SString Sub;//for storing the substring
	while (i <= n - m + 1)
	{
		SubString(Sub, S, i, m);//get m elements from the i.th of S to Sub
			if (StrCompare(Sub, T) != 0)
				i++;
			return i;
	}
	return 0;
}
int main()
{
	SString s1, s2;
	s1.length = 0;
	s2.length = 0;
	cout << "Please  input a string for s1 to store:\n";
	cin >> s1.ch;
	s1.length = sizeof(s1);
	cout << "the length of s1 is "<<StrLen(s1);
	cout << "s1 is " << s1.ch << endl;
	cout << "Please  input a string for s1 to refresh:\n";
	cin >> s2.ch;
	s2.length = sizeof(s2);
	StrCopy(s1, s2);
	cout << "s1 is " << s1.ch<<endl;
	cout << "the length of s1 is " << s1.length;
	return 0;
}

 SubString:取出子串为什么会越界

 也可以理解为pos-1,这样会指向目标结点前面,再加上len,这样len刚好表示需要的个数

(4)不用基本操作的算法:

朴素模式匹配算法(暴力求解):当前串不行,让主串挪一个位置重新匹配,i=i-j+1

int Index(SString S, SString T)
{
	int i=1, j=1;
	while (i <= S.length && j <= T.length)
	{
		if (S.ch[i] == T.ch[j])
			i++, j++;
		else
		{
			i = i-j + 2;
//i-j表示主串指针回到S的当前子串前一个位置,+1为当前子串的第一个位置
//+2表示当前子串的第二个位置,实现主串回溯
			j = 1;
		}
	}
	if (j > T.length)
		return i - T.length;
	else return 0;
}

匹配模式的朴素算法最坏时间复杂度:O((n-m+1)m)=O(nm-m^2+m)=O(nm)

 KMP算法(主串指针不回溯,先摸清模式串特点来简化算法)

以 abaabc为例:

next[ x ] 表示第 x 位对不上时,主串位序 i 不变,但是模式串的 j 变换到第几位

对比失败的步骤:第 x 位失败,证明该子串的前 x-1 已知且和模式串相同。写出子串的前x-1位再去掉第一位,和模式串依次比较看看 j 能到第几位。

next[1]无脑写0 ;next[2]无脑写1;

 KMP优化算法:【相同则更新,不同则保留】

再次利用模式串特点,在已知next数组基础上,将next数组优化。

虽然你模式串回到从前,但是你没曾想,如果你回到的同样的字母,还是会匹配失败!

所以在这里可以从x=2开始,看看回到序号的字母和自己是否相同。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值