线性表 —— 串、数组和广义表

串、数组和广义表

栈、队列:操作受限的线性表
串:内容受限的线性表
广义表:线性结构的推广

案例引入

串的应用非常广泛,计算机上的非数值处理的对象大部分是字符串数据,例如:文字编辑、符号处理、各种信息处理系统等等
一、病毒感染检测

定义:零个或多个任意字符组成的有限序列
在这里插入图片描述

  1. 字串:串中任意个连续字符组成的子序列(含空串)称为该串的子串
    例如:”abcde“的字串有"" “a” “ab” “bc” “abcd” “cde” 等
  2. 真子串是指不包含自身的所有子串
  3. 主串:包含子串的串相应的称为主串
  4. 字符位置:字符在序列中的序号为该字符在串中的位置
  5. 子串位置:子串第一个字符在主串中的位置
  6. 空格串:由一个或多个空格组成的串,与空串不同
  7. 串相等:当且仅当两个串的长度相等并且各个对应位置上的字符都相同时,这两个串才是相等的
  8. 所有的空串都是相等的
串的类型定义

操作:

  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. StrInsert(&S, pos, T) //子串插入
  12. StrDelete(&S, pos, len) //子串删除
  13. DestroyString(&S) //串销毁
存储结构

顺序存储结构:顺序串
链式存储结构:链串
优点:操作方便 缺点:存储密度较低
方法:可将多个字符存放在一个结点中,以克服其缺点

  1. 顺序串定义:
    typedef struct {
    char ch[MAXLEN+1]; //其中存储一般从下表为1的开始
    int length;
    }SString;
  2. 块串定义
    typedef struct Chunk {
    char ch[CHUNKSIZE];
    struct Chunk* next;
    }Chunk;

typedef struct {
Chunk *head, *tail; //串的头指针和尾指针
int curlen; //串当前的长度
}LString; //字符串的块链结构

串的模式匹配模式

确定主串中所含子串(模式串)第一次出现的位置(定位)
应用:搜索引擎、拼写检查、语言翻译、数据压缩
种类:BF算法(Brute-Froce,又称古典的、经典的、朴素的、穷举的)
KMP算法(特点:速度快)

BF算法

Brute-Froce简称BF算法,亦称简单匹配算法、。采用穷举法的思路:从S的每一个字符开始依次与T的字符进行匹配
Index(S,T,pos)
将主串中第pos个字符和模式串(子串)的第一个字符比较
①若相等,继续逐个比较后续字符 ②若不等,从主串的下一个字符起,重新与模式串的第一个字符比较
直到主串的一个连续子串字符序列与模式串相等,返回值为S中与T匹配的子序列第一个字符的序号,即匹配成功
否则,匹配失败,返回值0

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; //模式匹配成功

时间复杂度:
总次数为(n-m)*m+m = (n-m+1)m
若m<<n,算法复杂度为O(n
m)

KMP算法

利用已经部分匹配的结果而加快模式串的滑动速度,且主串S的指针i不必回溯,可提速到O(n+m)
定义next[j]函数,表示当模式中第j个字符与主串中的相应字符“失配”时,在模式中需要重新和主串中该字符进行比较的字符的位置
在这里插入图片描述

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不变,j后退
}
if (j > T.length) return i-T.length; /*匹配成功*/
else return 0; /*返回不匹配标志*/

next[j]的求法

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

参考详解

KMP的改进

在这里插入图片描述

void get_nextval(SString T, int &nextval[]) {
	i = 1; 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];
	}
}
数组

按照一定格式排列起来的,具有相同类型的数据元素的集合

预备知识
  • 一维数组的逻辑结构:线性结构,定长的线性表
  • 二维数组的逻辑结构:①非线性结构:每一个数据元素既在一个行表中,又在一个列表中 ②线性结构(定长的线性表):该线性表的每个数据元素也是一个定长的线性表
    是特殊的线性表
  • 定义:
    ①typedef elemtype array2[m][n]
    ②typedef elemtype array1[m] //类型是有n个元素的一维数组
    typedef array1 array2[n] //这个一维数组有n个元素,每个元素类型是array1类型
    同理可推n维数组
  • 数组特点:结构固定——定义后,维数和维界不再改变
  • 数组的基本操作:除了结构的初始化和销毁之外,只有取元素和修改元素值的操作
  • 基本操作:
    1)IntiArray(&A,n,bound1,…,boundn); //构造数组A
    2)DestroyArray(&A) //销毁数组A
    3)Value(A,&e,index1,…,indexn) //取数组的元素值
    4)Assin(A,&e,index1,…,indexn) //给数组元素赋值
    一般不做插入和删除运算,所以一般采用顺序存储结构来表示数组
    在这里插入图片描述
特殊矩阵的压缩存储
  • 矩阵:一个由m×n个元素排成的m行n列的表
  • 矩阵的常规存储:将矩阵描述为一个二维数组
  • 矩阵常规存储的特点:可以对其元素进行随机存取;矩阵运算非常简单;存储密度为1
  • 不适宜常规存储的矩阵:值相同的元素很多且呈某种规律分布;零元素多
  • 矩阵的压缩存储:为多个相同的非零元素只分配一个存储空间;对零元素不分配存储空间
  • 适合压缩存储的矩阵:对称矩阵、对角矩阵、三角矩阵、稀疏矩阵
  • 稀疏矩阵:矩阵中非零元素的个数较少(一般小于5%)
  • 对称矩阵的存储方法:只存储上三角或下三角(包括主对角线)的数据元素,只占用(n+1)n/2个元素空间
    可以以行序为主序将元素存放在一个一维数组s[n(n+1)/2]中
  • 三角矩阵:对角线以下或者以上的数据元素(不包括对角线)全部为常数c,包括上三角矩阵,下三角矩阵
    存储方法:重复元素c共享一个元素存储空间,共占用n(n+1)/2+1个元素
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    其中0位置存储总共6行,6列,有效元素个数是8个
  • 三元组顺序表又称有序的双下标法
  • 三元组顺序表的优点:非零元在表中按行序有序存储,因此便于进行依行顺序处理的矩阵运算
  • 缺点:不能随机存取,若按行号存取某一行中的非零元,则需从头开始查找
  • 稀疏矩阵的链式存储结构:十字链表
    在这里插入图片描述
    在这里插入图片描述
广义表

在这里插入图片描述

  • 广义表通常记作LS = (a1,a2,…,an)
    其中LS为表名,n为表的长度,每一个ai为表的元素
  • 习惯上,一般用大写字母表示广义表,小写字母表示原子
  • 表头:若LS非空(n≥1),则其第一个元素a1就是表头,记作head(LS) = a1 注:表头可以是原子,也可以是子表
  • 表尾:除表头之外的其他元素组成的表,记作tail(LS) = (a2,…,an) 注:表尾不是最后一个元素,而是一个子表
  • eg:
    ①A = ();空表,长度为0
    ②B = (()); 长度为1,表头和表尾都是()
    ③C = (a,(b,c)); 长度为2,由原子a和子表(b,c)构成,表头为a;表尾为((b,c)) ///对比④的表尾
    ④D = (x,y,z); 长度为3,每一项都是原子,表头为x,表尾为(y,z) ///对比③的表尾
    ⑤E = (C,D); 长度为2,每一项都是子表,表头为C,表尾为(D)
    ⑥F = (a,F) ; 长度为2,第一项为原子,第二项为它本身;表头为a,表尾为(F)
    F = (a,(a,(a,…)))
  • 广义表的性质:
    在这里插入图片描述
    在这里插入图片描述
  • 广义表可以看作是线性表的推广,线性表是广义表的特例
  • 基本操作:
    ①GetHead(L) :非空广义表的第一个元素,可以是一个原子,也可以是一个子表
    ②GetTail(L) :非空广义表除去表头元素以外其他元素所构成的表。表尾一定是一个表
    eg:D = (E,F) = ((a,(b,c)), F)
    GetHead(D) = E; GetTail(L) = F
    GetHead(E) = a;GetTail(L) = ((b,c))
    GetHead(((b,c))) = (b,c);GetTail(((b,c))) = ()
  • 存储结构:链式存储
案例分析与实现

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值