第4章 串、数组、广义表
1、串(String)——零个或多个任意字符组成的 有限序列
2、子串:串中任意个连续字符组成的子序列(含空串)称为该串的子串
3、真子串是指不包含自身的所有子串
4、字符位置:字符在序列中的序号为该字符在串中的位置
5、子串位置:子串第一个字符在空串中的位置
6、空格串:由一个或多个空格组成的串
7、串相等:当且仅当两个串的长度相等并且各个对应位置上的字符都相同时,这两个串才是相等的
串的顺序存储结构
#define MAXSIZE 255
typedef struct{
char ch[MAXSIZE+1];//存储串的一维数组
int length;//串的当前长度
}SString;
串的链式存储结构
//串的链式存储结构—块链结构
#define CHUNKSIZE 80//块的大小可由用户定义
typedef struct Chunk{
char ch[CHUNKSIZE];
struct Chunk *next;
}Chunk;
typedef stuct{
Chunk *head, *tail;//串的头指针,尾指针
int curlen;//串的当前长度
}LString;//字符串的 块链结构
Brute-Force简称为BF算法,亦称简单匹配算法。采用穷举法的思路
算法的思路:是从S的每一个字符开始一次与T的字符进匹配
第一次:
S: a a a a b c d
T: a b c
第二次
S: a a a a b c d
T: a b c
第三次
S: a a a a b c d
T: a b c
第四次:匹配成功
S: a a a a b c d
T: a b c
int Index_BF(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;
j = 1;
}
}
if(j>=T.length) return i-T.length;//返回匹配的第一个字符的下标
else return 0;//模式匹配不成功
}
int Index_BF(SString S, SString T, int pos){
int i = pos;
int j =1;
while(i <= S.length && j <= T.length){
if(S.ch[i] == t.ch[j]){
++i;
++j;
}
}
if(j >=T.length) return i-T.length;//返回匹配的第一个字符的下标
else return 0;//模式匹配不成功
}
KMP算法
int Index_KMP(SString S, SString T, int pos){
int i = pos;
int j = 1;
while(i< S.length && j < T.length){
if(j==0||S.ch[i] == T.ch[j]){
i++;
j++;
}else{
j = next[j];
}
}
if(j > T.length) return i - T.length;
else return 0;
}
void get_next(SString T, int &next[]){
int i = 1;
int next[1] = 0;
int j = 0;
while(i<T.length){
if(j==0||T.ch[i] == T.ch[j]){
++i;
++j;
next[i] = j;
}
else
{
j = next[j];
}
}
}
void get_nextval(SString T, int &nextval[]){
int i = 1;
int nextval[1] = 0;
j = 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]
}
else
{
j = nextval[j];
}
}
}
数组
按一定格式排列起来的,具有相同类型的数据元素的集合
一维数组:
若线性表的数据元素为非结构的简单元素,则称为一维数组
一维数组的逻辑结构:
线性结构。定长的线性表
声明格式:
数据类型 变量名称[长度]
二维数组
若一维数组中断数据元素又是一维数组结构,则称为二维数组
声明格式:
数据类型 变量名称[行数] [列数]
数组的顺序存储
数组的特点:结构固定——维数和维界不变
特殊矩阵的压缩存储
1、什么是压缩存储
若多个数据元素的值都相同,则只分配一个元素值的存储空间,且零元素不占存储空间。
2、什么样的矩阵能够压缩
一些特殊矩阵,如:对称矩阵,对角矩阵,三角矩阵,稀疏矩阵等
3、什么叫稀疏矩阵
矩阵中非零元素的个数较少(一般小于5%)
对称矩阵
存储方法:只存储下(或者上)三角(包括主对角线的)数据元素。共占用n(n+1)/2
三角矩阵
特点:对角线以下(或者以上)的数据元素(不包括对角线)包括常数c
存储方法:重复元素c共享一个元素存储空间,共占用n(n+1)/2 + 1个元素
对角矩阵(带状矩阵)
特点:在n*n的方阵中,所有非零元素都集中在以主对角线为中心的带状区域中,区域外的值全为0,则称为对角矩阵。
稀疏矩阵
稀疏矩阵:设在m×n的矩阵中有t个非零元素,令t/(m*n) <= 0.05时称为稀疏矩阵
三元组顺序表又称为有序的双下标法
三元组顺序表的优点:非零元在表中按行序有序存储,因此便于进行依行顺序处理的矩阵运算
三元组顺序表的缺点:不能随机存取。若按行号存取某一行中的非零元,则需从头开始进行查找
稀疏矩阵的链式存储结构:十字链表
优点:它能够灵活地插入因运算而产生新的非零元素,删除因运算而产生的新的零元素,实现矩阵的各种运算。
在十字链表中,矩阵的每一个非零元素用一个结点表示,该结点除了(row, col, value)以外,还有两个域:
right:用于链表同一行中的下一个非零元素
down:用以链接同一行中的下一个非零元素。
广义表
广义表(又称列表Lists)是n >=0个元素。其中每个ai或者是原子,或者是一个广义表。
习惯上,一般用大写字母表示广义表,小写字母表示原子
表头:若LS非空(n>=1),则其中第一个元素a1就是表头。记作head(LS) = a1.注意:表头可以是原子,也可以是子表
表尾:除表头之外的其他元素组成的表
记作tail(LS) = (a2,a3……,an);
注意:表尾不是最后一个元素,而是一个子表
例如:
A = () 空表,长度为0
B =(())长度为1,表头表尾均为()
C=(a,(b,c))长度为2,由原子a和子表(b,c)构成。表头为a,表尾为((b,c))
D=(x,y,z) 长度为3,每一项都是原子,表头是x,表尾是(y,z)
广义表的性质
- 广义表中的数据元素有相对次序;一个直接前驱和一个直接后继
- 广义表的长度定义为最外层所包含元素的个数
- 广义表的深度定义为该广义表展开后所含括号的重数
- 广义表可以为其他广义表共享
- 广义表可以是一个递归的表
- 广义表是多层次结构,广义表的元素可以是单元素,也可以是子表,而子表的元素还可以是子表
广义表与线性表的区别
广义表可以看成是线性表的推广,线性表是广义表的特例
广义表的结构相当灵活,在某种前提下,它可以兼容线性表、数组、树和有向图等各种常用的数据结构
当二维数组的每行(或每列作为子表处理时),二维数组即为一个广义表
另外,树和有向图也可以用广义表来表示
广义表的基本运算
(1)求表头GetHead(L):非空广义表的第一个元素,可以是一个元素,也可以是一个子表
(2)求表尾GetTail(L):非空广义表出去表头元素意外其他元素所构成的表。表尾一定是一个表