网站首页 > 技术教程 正文
4.1 串
4.1.1 定义
串(string):由零个或任意字符组成的有限数列
子串:串中任意连续字符组成的子序列(含空串)称为该串的子串
真子串:不包含自身的所有子串
主串:包含子串的串相应地称为主串
字符位置:字符在序列中的序号为该字符在串中的位置
子串位置:子串第一个字符在主串中的位置
空格串:由一个或多个空格组成的串,与空串不同
串相等:当且仅当两个串的长度相等并且各个对应位置上的字符都相同,这两个串才是相等的
如:“abcd”≠ “abc”
所有空串是相等的
4.1.2 案例引入
串的引用非常广泛,计算机上的非数值处理的对象大部分是字符串数据,例如:文字编辑、符号处理、各种信息处理系统等等
病毒感染检测
- 研究者将人的DNA和病毒的DNA均表示成一些字母组成的字符串序列
- 然后检测某种病毒DNA序列是否在患者的DNA序列中出现过,如果出现过,则此人感染了该病毒,否则没有感染
- 例如:假设病毒的DNA序列为baa,患者1的DNA序列为aaabbba,则感染;患者2的DNA序列为babbaa,则未感染
(注意,人的DNA序列是线性的,而病毒的DNA序列是环状的)
4.1.3 类型定义、存储结构及其运算
顺序存储
#define MAXSTRINGSIZE 255
typedef struct {
char ch[MAXSTRINGSIZE + 1]; // 存储串的一维数组
int length; // 串的当前长度
}mystring;
链式存储
链式存储结构和链表一样
下面这种结构称为:块链结构
#define MAXBLOCKLINKSTRINGSIZE 80
typedef struct BlockLinkString {
char ch[MAXBLOCKLINKSTRINGSIZE]; // 存储串的一维数组
struct BlockLinkString* next; // 指向下一个块的指针
}Block;
typedef struct {
Block* head; // 指向串的头块
Block* tail; // 指向串的尾块
int length; // 串的当前长度
}blockLinkString;
模式匹配算法
算法目的:确定主串中所含子串(模式串)第一次出现的位置(定位)
算法应用:搜索引擎、拼写检查、语言翻译、数据压缩
算法种类:
- BF(Brute-Force),又称古典的、经典的、朴素的、穷举的
- KMP算法(特点:速度快)
BF算法
算法思路:
- 将主串的第pos个字符和模式串的第一个字符比较
- 若相等,继续逐个比较后续字符
- 若不等,从主串的下一个字符起,重新与模式串的第一个字符比较
- 直到主串的一个连续子串字符序列与模式串相等。返回值与S中T匹配的子序列第一个字符的序号,即匹配成功。
- 否则,匹配失败,返回值 0
/*******************************************************************************************************************************
* @description:BF算法
* @param:S 主串
* @param:T 子串
* @param:pos 开始位置
* @return: 匹配成功返回1;否则返回0
*/
int index_BF(mystring S, mystring 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;
}
else{
i = i - j + 2; // 回溯
j = 1;
}
}
if (j > T.length) // 匹配成功
return i - T.length;
else
return 0;
}
时间复杂度:O(n*m)
KMP算法
利用已经部分匹配的结果而加快模式串的滑动速度,且主串S的指针I不必回溯,可提速到O(n+m)
因此需要一个next[j]数组,表明当模式中第j个字符与主串中相应字符“失败”时,在模式中需要重新和主串中该字符进行比较的字符的位置
例如:
next函数的改进
if(pattern[j] == pattern[i]){
next[i] = j+1;
i++;
j++;
}
else{
next[i] = j-1;
j++;
i++;
}
/*******************************************************************************************************************************
* @description:构造next数组
* @param:T 模式串
* @param:next
*/
static void get_next(mystring T, int next[])
{
int i = 1;
int j = 0;
next[1] = 0;
while (i < T.length)
{
if (j == 0 || T.ch[i] == T.ch[j])
{
++i;
++j;
if (T.ch[i] != T.ch[j])
next[i] = j;
else
next[i] = next[j];
}
else
j = next[j];
}
}
/*******************************************************************************************************************************
* @description:KMP算法
* @param:S 主串
* @param:T 模式串
* @param:pos 开始位置
* @return:
*/
int index_KMP(mystring S, mystring T, int pos)
{
int i = pos;
int j = 1;
int next[255];
get_next(T, next);
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 StringMain()
{
mystring S = { ' ', 'a','a','a','b','a','a','a','a','b' }; // 主串,第一个位置不用
S.length = 9;
mystring T = { ' ','a','a','a','a' }; // 模式串,第一个位置不用
T.length = 4;
printf("主串:");
printString(S);
printf("\n模式串:");
printString(T);
// 测试BF算法
int pos = index_BF(S, T, 1);
if (pos)
printf("\nBF算法:匹配成功,位置为:%d\n\n", pos);
else
printf("\nBF算法:匹配失败\n\n");
// 测试KMP算法
pos = index_KMP(S, T, 1);
if (pos)
printf("\nKMP算法:匹配成功,位置为:%d\n", pos);
else
printf("\nKMP算法:匹配失败\n");
}
4.2 数组
数组:按一定格式排列起来的具有相同类型的数据元素的集合
一维数组:若线性表中的数据元素为非结构的简单元素,则称为一维数组
一维数组的逻辑结构:线性结构。定长的线性表
声明格式:数据类型 变量名称[长度];
二维数组:若一维数组中的数据元素又是一维数组结构,则称为二维数组。
二维数组的逻辑结构:
- 非线性结构:每一个数据元素即在一个行表中,又在一个列表中
- 线性结构:该线性表的每个数据元素也是一个定长的线性表
数组特点:结构固定-定义后,维数和维界不再改变
数组基本操作:除了结构的初始化和销毁之外,只有取元素和修改元素值的操作
4.2.1 抽象数据类型定义
二维数组存储方式:
- 以行序为主序:C、PASCAL、JAVA、Basic
- 以列序为主序:FORTRAN
4.2.2 特殊矩阵的压缩存储
什么时压缩存储?
为多个相同的非零元素只分配一个存储空间;对零元素不分配空间
什么样的矩阵能够压缩?
一些特殊矩阵:对称矩阵,对角矩阵,三角矩阵,稀疏矩阵等
什么叫稀疏矩阵?
矩阵中非零元素的个数较少(一般小于5%)
对称矩阵
三角矩阵
对角矩阵
稀疏矩阵
三元组
十字链表
例如:
4.3 广义表
4.3.1 定义
广义表(又称列表Lists)是n≥0个元素 a0,a1,... ,a(n-1)的有限序列,其中每一个ai或者是原子,或者是一个广义表
例如:
广义表的性质:
- 广义表中的数据元素有相对次序;一个直接前驱和一个直接后继
- 广义表的长度定义为最外层所包含元素的个数;如:C = (a,(b, c))是长度为2的广义表
- 广义表的深度定义为该广义表展开后所含括号的重数;A = (b, c)的深度为1,B = (A, b)的深度为2,C = (f, B, h)的深度为3 注意:“原子”的深度为 0;“空表”的深度为 1
- 广义表可以为其它广义表共享;如:广义表B就共享表A。在B中不必列出A的值,而是通过名称来引用,B = (A)
- 广义表可以是一个递归的表,如 F = (a, F=(a, (a, (a, ...)))) 注意:递归表的深度是无穷值,长度是有限值
- 广义表是多层次结构,广义表的元素可以是单元素,也可以是子表,而子表的元素还可以是子表
4.3.2 基本运算
- 求表头GetHead(L):非空广义表的第一个元素,可以是一个原子也可以是一个子表
- 求表尾GetTail(L):非空广义表除去表头元素以外其它元素所构成的表。表尾一定是一个表
猜你喜欢
- 2024-11-13 软件开发究竟难在哪?(软件开发越来越难做)
- 2024-11-13 PHP是否越来越不受欢迎?(php没人用了)
- 2024-11-13 如何快速申请软件著作权(申请软件著作权需要什么资料)
- 2024-11-13 这个开源项目用了7年,整理了全网经典的编程书籍
- 2024-11-13 变量初始化你真的懂吗(变量初始化你真的懂吗什么意思)
- 2024-11-13 ubuntu 20.04安装gfortran gcc(ubuntu安装gcc5.4)
- 2024-11-13 5年程序员总结—这几个C语言问题超纲了,小白勿进
- 2024-11-13 字符和字符串你不知道的东西(字符与字符串的区别)
- 2024-11-13 Python术语对照表(上)(python 术语)
- 2024-11-13 蝌学荐书|菲尔兹奖得主陶哲轩15岁时写的数学思维入门书,凭什么能畅销5万册?
你 发表评论:
欢迎- 最近发表
-
- linux日志文件的管理、备份及日志服务器的搭建
- Linux下挂载windows的共享目录操作方法
- Linux系统中的备份文件命令(linux系统中的备份文件命令有哪些)
- 麒麟KYLINOS|通过不同方法设置用户访问文件及目录权限
- 「Linux笔记」系统目录结构(linux目录的结构及含义)
- linux中修改归属权chown命令和chgrp命令
- 工作日报 2021.10.27 Android-SEAndroid权限问题指南
- Windows和Linux环境下,修改Ollama的模型默认保存路径
- 如何强制用户在 Linux 上下次登录时更改密码?
- 如何删除Linux文件夹中除某些扩展名之外的所有文件?
- 标签列表
-
- 下划线是什么 (87)
- 精美网站 (58)
- qq登录界面 (90)
- nginx 命令 (82)
- nginx .http (73)
- nginx lua (70)
- nginx 重定向 (68)
- Nginx超时 (65)
- nginx 监控 (57)
- odbc (59)
- rar密码破解工具 (62)
- annotation (71)
- 红黑树 (57)
- 智力题 (62)
- php空间申请 (61)
- 按键精灵 注册码 (69)
- 软件测试报告 (59)
- ntcreatefile (64)
- 闪动文字 (56)
- guid (66)
- abap (63)
- mpeg 2 (65)
- column (63)
- dreamweaver教程 (57)
- excel行列转换 (56)
本文暂时没有评论,来添加一个吧(●'◡'●)