数据结构Part3 串

分节目录

数据结构(完结)
数据结构Part1 绪论与线性表
数据结构Part2 栈和队列
数据结构Part3 串
数据结构Part4 树与二叉树
数据结构Part5 图
数据结构Part6 查找
数据结构Part7 排序

第四章 串

1. 串的定义和基本操作

1.1 概念

串:即字符串(String),是由零个或多个字符组成的有限序列、一般记为S = “a1a2a3······an”,n>=0。是一种特殊的线性表(串的数据类型只能属于字符集),数据元素之间呈现线性关系。

注意:字符串用双引号括起来:java,c,c++,python;字符串用单引号括起来:python。

空串:串长度为零的串叫做空串

子串:串中任意个连续的字符组成的子序列,空串是任意串的子串。

1.2 基本操作

串的基本操作是对”字串“为对象进行操作的。

假设有串T="",S=" iPhone 11 Pro Max?",W="Pro"
StrAssign(&T,chars)			//赋值操作。把串T赋值为chars;
StrCopy(&T,S)				//复制操作。由串S复制得到串T;
StrEmpty(S)					//判空操作。若s为空串,则返回TRUE,否则返回FALSE;
StrLength(S)				//求串长。返回串s的元素个数;
ClearString(&S)				//清空操作。将s清为空串,不释放空间;
DestroyString(&S)			//销毁串。将串s销毁(回收存储空间);
Concat(&T,S1,S2)			//串联接。用T返回由S1和S2联接而成的新串
SubString(&Sub,S,pos,len)	//求子串。用sub返回串s的第pos个字符起长度为len的子串。
Index(S,T)					//定位操作。若主串S中存在与串T值相同的子串,则返回它在主串S中第一次出现位置;否则函数值为0。
StrCompare(S,T)				//比较操作。若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0。自行定义大小规则,从第一个字符开始一次比较 。
//注意:存储空间扩展
//执行基本操作Concat(&T, S,W)后,T="iPhone 11 Pro Max?Pro"
//执行基本操作SubString(&T ,S,4,6)后,T="one 11"
//执行基本操作Index(s, W)后,返回值为11

不同编码规则下每个字符所占的空间不同,考试默认为1B。

附录:ASCII码表:

decocthexchdecocthexchdecocthexchdecocthexch
0000NULL (空)324020(空格)6410040@9614060` (锐音符)
1101SOH (标题开始)334121!6510141A9714161a
2202STX (正文开始)344222"6610242B9814262b
3303ETX (正文结束)354323#6710343C9914363c
4404EOT (传送结束)364424$6810444D10014464d
5505ENQ (询问)374525%6910545E10114565e
6606ACK (确认)384626&7010646F10214666f
7707BEL (响铃)394727'7110747G10314767g
81008BS (退格)405028(7211048H10415068h
91109HT (横向制表)415129)7311149I10515169i
10120aLF (换行)42522a*741124aJ1061526aj
11130bVT (纵向制表)43532b+751134bK1071536bk
12140cFF (换页)44542c,761144cL1081546cl
13150dCR (回车)45552d-771154dM1091556dm
14160eSO (移出)46562e.781164eN1101566en
15170fSI (移入)47572f/791174fO1111576fo
162010DLE (退出数据链)48603008012050P11216070p
172111DC1 (设备控制1)49613118112151Q11316171q
182212DC2 (设备控制2)50623228212252R11416272r
192313DC3 (设备控制3)51633338312353S11516373s
202414DC4 (设备控制4)52643448412454T11616474t
212515NAK (反确认)53653558512555U11716575u
222616SYN (同步空闲)54663668612656V11816676v
232717ETB (传输块结束)55673778712757W11916777w
243018CAN (取消)56703888813058X12017078x
253119EM (媒介结束)57713998913159Y12117179y
26321aSUB (替换)58723a:901325aZ1221727az
27331bESC (退出)59733b;911335b[1231737b{
28341cFS (文件分隔符)60743c<921345c\1241747c|
29351dGS (组分隔符)61753d=931355d]1251757d}
30361eRS (记录分隔符)62763e>941365e^1261767e~
31371fUS (单元分隔符)63773f?951375f_1271777fDEL (删除)

2. 串的存储结构

2.1 顺序存储

定长字符串:定义一个静态数组来存储定长的串,与线性表相同,只不过数据类型为字符类型(char)。

可变长字符串:定义一个基地址指针,使用动态数组的方式实现(堆分配存储)。

插入和删除不方便,字符串末尾有一个’\0’(对应的ASCII码为0),没有length变量,所占空间为字符串长度加一。

define MAXLEN 255
typedef struct{
	char ch[MAXLEN];		//创建一个定长的字符串数组
	int length;				//串的长度
}SString;
typedef struct{
	char *ch;				//按串长分配存储区,ch指向串的基地址
	int length;				//串的长度
}HString;

//使用完毕后需要手动free
HString S;
S.ch = (char *) malloc(MAXLEN * sizeof(char));		
S.length = 0;

2.2 链式存储

不具备随机存储的特性。

typedef struct StringNode{
	char ch[4];		//每个节点一般存多个字符,提高存储密度,结尾可以特殊字符填充,如'\0'。
	struct StringNode *next;	
}StringNode, *String;

所以说为什么想不开要用链表存字符串呢,搞不懂哦。

2.3 基于顺序存储实现基本操作(模式匹配)

define MAXLEN 255
typedef struct{
	char ch[MAXLEN];		//创建一个定长的字符串数组
	int length;				//串的长度
}SString;
SubString(&Sub,S,pos,len)	//求子串。用sub返回串s的第pos个字符起长度为len的子串。
bool SubString(SString &sub, SString S, int pos, int len){
	//子串范围越界
	if (pos+len-1 > S.length)
		return false;
	for (int i=pos; i<pos+len; i++)
		sub.ch[i-pos+1] = S.ch[i];
    sub.length = len;
	return true;
}
StrCompare(S,T)				//比较操作。若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0。自行定义大小规则,从第一个字符开始一次比较 。
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];
    }
	//扫描过的所有字符都相同,则长度长的串更大
	return S.length-T.length;
}
Index(S,T)					//定位操作。若主串S中存在与串T值相同的子串,则返回它在主串S中第一次出现位置;否则函数值为0。
int Index(SString S, SString T){
    int i = 1, n = StrLength(S), m = StrLength(T);
    SString sub;
    while(i <= n - m +1){
        SubString(sub, S, i, m);
        if(StrCompare(sub, T)!=0) ++i;
        else return i;
    }
    return 0;
}

串的模式匹配算法:在主串中找到与模式串相同的子串,并返回其所在位置(Index(S, T))。

朴素模式匹配:依次检查子串,时间复杂度为O(nm)。

int Index(SString s, sstring T){
	int k = 0;
	int i=k, j=0;
	while(i < s.length && j < T.length){
		if(S.ch[i]==T.ch[j]){
			++i;
			++j;		//继续比较后继字符
		} eise {
			k++;		//检查下一个子串
			i=k;
            j=1;
		}
	}
	if(j>T.length)	return k;
    else			return 0;
}

模式串长度为m,主串长度为n,(n>>m)

时间复杂度匹配成功匹配失败
最好O(m)O(n-m+1)=O(n-m)≈O(n)
最坏O((n-m+1)*m)≈O(nm)O((n-m+1)*m)≈O(nm)
*KMP算法(重点)

主串指针不回溯,只有字串指针回溯,不用一位一位得比较,而是记下回退几个能对上,关键在于求字串数组回溯得个数next[i];

在这里插入图片描述

int IndexKMP(SString S, SString T, int next[]){
	int i = 0,j = 0;
	while( i < s.length && j < T.length){
		if(j==-1 || s.ch[i]==T.ch[j] ){
			++i;
            ++j; 		//继续比较后继字符
        } else j=next[j]; 	//模式串向右移动
	}
    if(j > T.length)
        return i-T.length;	//匹配成功
    else return -1;
}

求模式串的next数组

void Getnext(int next[],String t)
{
   int j=0,k=-1;
   next[0]=-1;
   while(j < t.length-1)
   {
      if(k == -1 || t[j] == t[k])
      {
         j++;k++;
         next[j] = k;
      }
      else k = next[k];		//核心代码
   }
}

重点来看看 k = next[k] 这句,首先要明确得是,k表示的是一个用来生成next数组得游标,是可以向左移动来取数的,而j才是用来标记next数组最新下标的,是只能向右移动的,其次是next数组的值的含义,next[i]表示当模式串扫描到第i个位置与主串不同时,模式串游标移动到的位置。因此这句话相当于是创建了一个新串ss来做模式串,之前的模式串做主串。这里的ss是在动态变动的,而这句话表示得是表示的是字符串t0到k-1子串(构建的新字串ss)与j-k到j-1子串(长度均为k)是相同的。

在这里插入图片描述

改进的kmp算法,改进点依然在next数组上。按照原方案,当主串i位置与模式串j位置不同时,应该进行移动,使得主串的i位置与模式串的**next[j]**位置对应,然而若这两个位置无法对应,那么这次移动就是无意义的,因此需要在构建next数组时添加一个判断。

在这里插入图片描述

void Getnext(int next[],String t)
{
   int j=0,k=-1;
   next[0]=-1;
   while(j < t.length-1)
   {
      if(k == -1 || t[j] == t[k])
      {
         j++;k++;
         if(t[j]==t[k])				//当两个字符相同时,就跳过
            next[j] = next[k];
         else
            next[j] = k;
      }
      else k = next[k];
   }
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值