八、串,数组和广义表

1、串

KaTeX parse error: Undefined control sequence: \qquadd at position 1: \̲q̲q̲u̲a̲d̲d̲串(string)是零个或者多个任意字符组成的有限序列。
在这里插入图片描述
\qquad 子串:一个串中任意个连续字符组成的子序列(含空串)称为该串的子串。
\qquad 真子串:指不包含自身的所有子串。
\qquad 主串:包含子串的串相应地称为主串。
\qquad 字符位置:字符在序列中的序号为该字符在串中的位置。
\qquad 子串位置:子串第一个字符在主串中的位置。
\qquad 空格串:有一个或者多个空格组成的串,与空串不同。
\qquad 串相等:当且仅当两个串的长度相等,并且各个对应位置上的字符都相同时,这两个串才是相等的。所有的空串都是相等的。
\qquad 串的应用非常广泛,计算机上的非数值处理的对象大部分是字符串数据,例如:文字编辑,符号处理,各种信息处理系统等。字符串匹配等。

1.1 串的类型定义,存储结构及运算

\qquad 串的抽象数据类型定义如下所示:
在这里插入图片描述
\qquad 串中元素逻辑关系与线性表的相同,串可以采用与线性表相同的存储结构。串可以使用顺序存储结构或者链式存储结构来实现。

1.1.1 串的顺序存储结构

\qquad 串的顺序存储结构

#define MAXLEN 255
class SString
{
	char ch[MAXLEN+1];	//存储串的一维数组
	int length;			//串的当前长度
};

\qquad 串的链式存储结构
\qquad 在进行串的链式存储时,可以多个字符放在一个结点中,克服链式存储存储密度低的缺点。在这里插入图片描述

#define CHUNKSIZE 80
class Chunk
{//块链中的块定义
	char ch[CHUNKSIZE];
	Chunk *next;
};
class LString
{
	Chunk *head, *tail;	//串的头指针和尾指针
	int curLen;			//串的当前长度	
};

1.1.2 串的模式匹配算法

\qquad 算法目的: 确定主串中所含的子串(模式串)第一次出现的位置(定位)。
\qquad 算法应用: 搜索引擎,拼写检查,语言翻译,数据压缩等
\qquad 算法种类:
\qquad BF算法(Brute-Force),又称古典的,经典的,朴素的,穷举的,即暴力破解法 \qquad KMP算法,算法速度快,但是逻辑较复杂

1.1.2.1 BF算法

\qquad BF算法的思路为穷举思路,算法从主串的每一个字符开始依次与子串的字符进行匹配,直到匹配到子串或者主串结束为止。

int Index_BF(SString S, SString T, int pos = 1)
{
	int i = pos,  j = 1;	//假设字符串第一个字符不放置元素
	while(i < S.length && j < T.length)
	{
		if(S.ch[i] == T.ch[j]){++i;++j}
		else
		{//主串回溯到下一个为止,子串置为初始位置
			i = i - j + 2;
			j = 1;
		}
		if(j >= T.length) return i - T.length;
		else return 0;
	}
}

\qquad BF算法的时间复杂度:
\qquad 假设主串长度为n,子串长度为m,则最好情况下需要比较m次,即主串第一个子串即为目标子串 O ( m ) O(m) O(m);最坏情况下,主串最后一个子串才为目标子串,则前面n-m各个主串元素均需要比较m次,则 O ( m ∗ ( n − m ) + m ) O(m*(n-m)+m) O(m(nm)+m),若m<<n,则算法的时间复杂度为: O ( n ∗ m ) O(n*m) O(nm)

1.1.2.2 KMP算法

\qquad KMP算法时由D.E.Knuth,J.H.Morris和V.R.Pratt共同提出的,简称KMP算法。该算法较BF算法有较大的改进,从而使算法效率有较大提高。
KMP算法的设计思想: 利用已经部分匹配的结果来加快模式串的滑动速度,并且主串S的指针i不需要回溯,子串T中的指针j可以不回到初始位置,可以提速到 O ( m + n ) O(m+n) O(m+n)
\qquad 为了衡量子串T中的指针j回到的位置,定义一个next[j]函数,表名当模式中的第j个字符与珠串中相应字符“失配”时,在模式中需要重新确定和主串中该字符进行比较的字符的位置。
n e x t [ j ] = { m a x { k   ∣   1 < k < j ,   且 " p 1 . . . p k − 1 = " p j − k + 1 . . . p j − 1 " } / / 从 头 开 始 的 k − 1 个 元 素 和 j 前 面 的 k − 1 个 元 素 0 , 当 j = 1 时 1 , 其 他 情 况 next[j]=\begin{cases} max \{ k\ |\ 1<k<j, \ 且"p_1...p_{k-1}="p_{j-k+1}...p_{j-1}"\}//从头开始的k-1个元素和j前面的k-1个元素\\ 0, 当j=1时\\ 1, 其他情况 \end{cases} next[j]=max{k  1<k<j, "p1...pk1="pjk+1...pj1"}//k1jk10,j=11,

\qquad next的例子如下图所示:
在这里插入图片描述
\qquad 使用next[j]表的KMP算法如下所示:

int Index_KMP(SString S, SString T, int pos = 1)
{
	i = pos, j = 1;
	while(i < S.length && j < T.length)
	{
		if(j==0 || S.ch[i] == T.ch[j]){++i;++j}
		else
			j = next[j];		//i的位置不变
	}
	if(j >= T.length) return i - T.lenght;	//匹配成功
	else return 0;							//匹配失败
}

//获取next[j]
void Get_next(SString T, int &next[])
{
	int i = 1, j = 0;
	next[1]=0;
	while(i < T.length)
	{
		if(j == 0 || T.ch[i]==T.ch[j])
		{
			++i; ++j;
			next[i]=j;	
		}
		else
			j = next[j];
	}
}

\qquad next的值还可以进行一定的修正,修正方法如下所示:
在这里插入图片描述
\qquad 修正版求next值的代码如下所示:

void Get_next(SString T, int &nextVal[])
{
	int i = 1, j = 0;
	nextVal[1]=0;
	while(i < T.length)
	{
		if(j == 0 || T.ch[i]==T.ch[j])
		{
			++i; ++j;
			if(T.ch[i]!=T.ch[j])nextVal[i]=j;
			else nextVal[i]=nextVal[j];
			nextVal[i]=j;	
		}
		else
			j = nextVal[j];
	}
}

2、数组

\qquad 按照一定格式排列起来的,具有相同类型的数据元素的集合。
\qquad 一维数组:若线性表中的数据元素为非结构的简单元素,则称为一维数组;一维数组的逻辑结构为线性结构,是一个定长的线性表。
\qquad 声明格式: 数据类型,变量名称[长度]

int num[5] = {0,1,2,3,4};

\qquad 二维数组: 若一维数组中的数据元素又是一维数据结构,则称为二维数组。
在这里插入图片描述
在这里插入图片描述
\qquad 声明格式: 数据类型 变量名称[行数][列数]

int num[5][8];

\qquad 三维数组: 若二维数组中的元素又是一个一维数组,则称作三维数组;
\qquad n维数组: 若n-1维数组中的元素又是一个一维数组结构,则称为n为数组。
\qquad 线性表结构是数组结构的一个特例,而数组结构又是线性表结构的拓展。 数组特点 是结构固定,定义后,维数和维界不再改变。
\qquad 数组的基本操作:除了结构的初始化和销毁外,只有取元素和修改元素值的操作。

2.1 数组的抽象数据类型定义

\qquad 以二维数组为例,定义数组的抽象数据类型:
在这里插入图片描述
在这里插入图片描述

2.2 数组的顺序存储结构

\qquad 由于数组的结构固定,维数和维界不变,所以数组一般都是采用顺序存储结构的。数组可以是多维的,但存储数据元素的内存单元地址是一维的,因此,在存储数组结构之前,需要解决将多维关系映射到一维关系的问题。

2.2.1 二维数组

\qquad 二维数组可以有两种顺序存储方式,一种是以行序为主体,低下标优先进行存储(C和Java中使用这种存储方式);另外一种是以列序为主体,高下标优先进行存储。
\qquad 以行序为主序,设数组开始存储的位置为 L O C ( 0 , 0 ) LOC(0,0) LOC(0,0),数组每行有n个元素,存储每个元素需要 L L L个存储单元,数组元素 a [ i ] [ j ] a[i][j] a[i][j]的存储为止为: L o c ( i , j ) = L o c ( 0 , 0 ) + ( i ∗ n + j ) ∗ L Loc(i,j)=Loc(0,0)+(i*n+j)*L Loc(i,j)=Loc(0,0)+(in+j)L

2.2.2 三维数组

\qquad 三维数组可以按页/行/列进行存放,页优先的顺序存储,每一页在按照行优先的顺序进行存储。如三维数组 a [ m 1 ] [ m 2 ] [ m 3 ] a[m_1][m_2][m_3] a[m1][m2][m3]各维的元素个数为: m 1 , m 2 , m 3 m_1,m_2,m_3 m1,m2,m3,则 a [ i 1 ] [ i 2 ] [ i 3 ] a[i_1][i_2][i_3] a[i1][i2][i3]元素的存储位置为: L o c ( i 1 , i 2 , i 3 ) = a + i 1 ∗ m 2 ∗ m 3 + i 2 ∗ m 3 + i 3 Loc(i_1,i_2,i_3)=a+i_1*m_2*m_3+i_2*m_3+i_3 Loc(i1,i2,i3)=a+i1m2m3+i2m3+i3

2.2.3 n维数组

在这里插入图片描述

2.3 特殊矩阵的压缩存储

\qquad 矩阵: 表示一个由 m × n m×n m×n个元素排成m行n列的表;矩阵的常规存储:将矩阵描述为一个二维数组,矩阵常规存储可以对其元素进行随机存取,矩阵运算非常简单,存储的密度为1。不适宜常规存储的矩阵:值相同的元素很多且呈现某种规律分布;零元素特别多。矩阵的压缩存储:为多个相同的非零元素只分配一个存储空间;对零元素不分配空间。
\qquad 特殊矩阵的例子:如对称矩阵,对角矩阵,三角矩阵,稀疏矩阵等。稀疏矩阵指:矩阵中非零元素的个数较少,一般小于5%。

2.3.1 对称矩阵

\qquad 特点:在n×n的矩阵a中,满足如下性质: a i j = a j i ( 1 ≤ i , j ≤ n ) a_{ij}=a_{ji}(1 \leq i,j \leq n) aij=aji(1i,jn)。对称矩阵的存储方法为:只存储下三角(包括主对角线)的数据元素。共占用 n ( n + 1 ) / 2 n(n+1)/2 n(n+1)/2个元素空间。
\qquad 对称矩阵中某个元素 a i , j a_{i,j} ai,j的存储位置为: L o c ( 0 , 0 ) + ( i ( i − 1 ) 2 + j ) ∗ L Loc(0,0)+(\frac{i(i-1)}{2}+j)*L Loc(0,0)+(2i(i1)+j)L,其中 L L L表示每一个元素所占用的内存空间。

2.3.2 三角矩阵

\qquad 特点:对角线以下(或者以上)的数据元素(不包括对角线)全部为常数c。
在这里插入图片描述
\qquad 存储方法:重复元素c共享一个元素存储单元,共占用 n ( n + 1 ) / 2 + 1 n(n+1)/2+1 n(n+1)/2+1个元素空间。
在这里插入图片描述

2.3.3 对角矩阵

\qquad 特点:在n×n的方阵中,所有非零元素都集中在以主对角线为中心的带状区域中,区域外的值全为0,则称为对角矩阵。常见的有三对角矩阵,五对角矩阵和七对角矩阵。
在这里插入图片描述
\qquad 存储方法为:以对角线的顺序进行存储,如下所示:
在这里插入图片描述

2.3.4 稀疏矩阵的存储

\qquad 设在m×n的矩阵中有t个非零元素,令 δ = t / ( m ∗ n ) \delta=t/(m*n) δ=t/(mn),当 t ≤ 0.05 t \leq 0.05 t0.05时,称为稀疏矩阵。

2.3.4.1 三元组法

\qquad 可以使用三元组法来存储稀疏矩阵,三元组 < i , j , a i , j > <i,j,a_{i,j}> <i,j,ai,j>来表示元素所在的行索引,列索引和元素值,之后还需要记录矩阵的总共和行数和列数和矩阵中总共元素的个数。三元组的不同表示方法可以决定稀疏矩阵不同的压缩存储方法。
在这里插入图片描述
\qquad 三元组法又称为有序的双下标法,其优点是:非零元素在表中按行序有序存储,因此便于进行依行顺序处理的矩阵运算;其缺点是:不能随机存取。若按照行号存取某一行中的非零元,则需从头开始进行查找。

2.3.4.2 十字链表法

\qquad 十字链表法的优点是:他能够灵活地插入因为运算而产生的新的非零元素,删除因运算而产生的新的零元素,实现矩阵的各种运算。
\qquad 在十字链表中,矩阵的每一个非零元素用一个结点表示,该节点的成员包括:行索引,列索引,元素值,链接同一行中下一个非零元素的指针,链接同一列中下一个非零元素的指针,十字链表的结点结构示意图如下所示:
在这里插入图片描述
\qquad 十字链表法的实现还需要一个行的头指针,指向每一行中第一个非零元素;一个列的头指针,指向每一列中第一个非零元素。
在这里插入图片描述

3、 广义表

\qquad 广义表是 n ≥ 0 n \geq0 n0个元素 a 0 , a 1 , . . . , a n − 1 a_0,a_1,...,a_{n-1} a0,a1,...,an1的有限序列,其中每一个 a i a_i ai或者是原子,或者是一个广义表。
\qquad 广义表的表头是广义表中的第一个元素;广义表的表尾不是广义表的最后一个元素,而是广义表除表头之外的其余元素组成的子表。

3.1 广义表的性质

\qquad 广义表中数据元素有相对次序,一个直接前驱和一个直接后继;
\qquad 广义表的长度定义为最外层所包含的元素的个数,如 C = ( a , ( b , c ) ) C=(a,(b,c)) C=(a,(b,c))是长度为2的广义表;
\qquad 广义表的深度定义为,该广义表展开之后所包含的括号的重数,原子的深度为0,空表的深度为1;
在这里插入图片描述
\qquad 广义表可以为其他广义表所共享;如上述广义表B就共享广义表A。
\qquad 广义表可以是一个递归的表,如 F = ( a , F ) F=(a,F) F=(a,F),递归表的长度为2,深度为无穷。
\qquad 广义表是多层次结构,广义表的元素可以是单元素,也可以是子表,可以用树型结构来形象地进行表示。
在这里插入图片描述

3.2 广义表和线性表的区别

\qquad 广义表可以看成线性表的推广,线性表是广义表的特例。
\qquad 当二维数组的每行或者每列作为子表处理时,二维数组即为一个广义表;
\qquad 树和图也可以用广义表来表示;
\qquad 广义表的结构相当灵活,在某种前提下,特可以兼容线性表,数组,树和有向图等各种常用的数据结构。

3.3 广义表的基本运算

\qquad 求表头,即非空广义表的第一个元素,可以是一个原子,也可以是一个子表;
\qquad 求表尾,非空广义表出去表头元素以外其他元素构成的表,表尾一定是一个表。

THE END

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Dragon Fly

多谢老板赏钱[抱拳抱拳抱拳]

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

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

打赏作者

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

抵扣说明:

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

余额充值