第4章 串、数组和广义表 丽水学院工学院.

Slides:



Advertisements
Similar presentations
阻塞操作. 在 linux 里,一个等待队列由一个 wait_queue_head_t 类型的结构来描述 等待队列的初始化: static wait_queue_head_t testqueue; init_waitqueue_head(&testqueue);
Advertisements

数据结构 2014年3月.
§1 二阶与三阶行列式 ★二元线性方程组与二阶行列式 ★三阶行列式
一、二阶行列式的引入 用消元法解二元线性方程组. 一、二阶行列式的引入 用消元法解二元线性方程组.
第五章 数组和广义表.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
第九章 字符串.
第四章 串 2018/11/13.
第4章 串 串的基本概念和C语言的串函数 串的存储结构 动态数组实现的顺序串 串的模式匹配算法——BF算法 主要知识点.
数据结构 Data Structure 主讲人:王国军,郑瑾 中南大学 中南大学信息院计科系
Zn 模式匹配与KMP算法 Zn
第二章 矩阵(matrix) 第8次课.
C语言高级编程(第四部分) 字符串 北京大学 信息科学技术学院.
数据结构 第4章 串.
第 4章 串和数组(二) 本讲主要内容: 数组的定义及其顺序表示和实现。 矩阵的压缩存储。 广义表的定义。
数据结构——串 1/15.
第四章 串和数组(一) 1/.
走进编程 程序的顺序结构(二).
串和数组.
第2讲 绪论(二).
第4章 串 4.1 串的基本概念及其抽象数据 4.2 串的存储结构 4.3 串类 4.4 串的模式匹配算法.
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
数 据 结 构 Ch.4 串 计 算 机 学 院 肖明军
第4章 串、数组和广义表 4.1 串 4.2 数组 4.3 广义表.
4.1 串的抽象数据类型的定义 4.2 串的表示和实现 4.3 串的模式匹配算法.
第4章 串 4.1 串的基本概念 4.2 串的存储结构 4.3 串的模式匹配.
陈海明 副教授 信息学院 计算机系 电子信息类非计算机专业选修课 程序设计实践 陈海明 副教授 信息学院 计算机系
模式匹配算法的原理及应用.
动态规划(Dynamic Programming)
第四章串 4.1 串类型定义 4.2 串的表示和实现 4.3 串的模式匹配算法 4.4 串操作应用举例.
第四章 串.
第五章 习题课 电子信息与计算机科学系 曾庆尚.
第4章 串和数组 本章主要介绍下列内容: 串的定义、存储结构和基本运算 数组的定义、基本运算和存储结构 特殊矩阵的压缩存储.
第五章 数组 5.1 数组的定义 5.2 数组的表示和实现* 5.3 数组的压缩.
从zval看PHP变量
第五章 串和数组 5.1 串的定义和操作 5.2 串的表示和实现 5.3 字符串应用 5.4 字符串匹配算法 5.5 数组
第四章 串.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
顺序表的删除.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
线性代数 第二章 矩阵 §1 矩阵的定义 定义:m×n个数排成的数表 3) 零矩阵: 4) n阶方阵:An=[aij]n×n
线 性 代 数 厦门大学线性代数教学组 2019年4月24日6时8分 / 45.
第五章 串和数组 5.1 串的定义和操作 5.2 串的表示和实现 5.3 字符串应用 5.4 字符串匹配算法 5.5 数组
第5章 数组和广义表 本章主题:多维数组、特殊矩阵和广义表 教学目的:掌握数组和广义表的定义、运算及存储结构 教学难点:矩阵的压缩存储
VB与Access数据库的连接.
5.1 串的基本概念 5.2 串的存储结构 5.3 串的基本运算 5.4 模式匹配 5.5 串在文本编辑中的应用
数 据 结 构 刘家芬 Sept 2012.
第四章 串和数组 4.1 串的定义* 4.2 串的表示和实现* 4.3 数组 4.4 数组的压缩.
单链表的基本概念.
顺序查找.
第 四 讲 线性表(二).
§8.3 不变因子 一、行列式因子 二、不变因子.
§6.7 子空间的直和 一、直和的定义 二、直和的判定 三、多个子空间的直和.
3.16 枚举算法及其程序实现 ——数组的作用.
第四章 串 £4.1 串的定义 £4.2 串的顺序存储结构 £4.3 串的链式存储结构 £4.4 串的应用—文本编辑
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
第15讲 特征值与特征向量的性质 主要内容:特征值与特征向量的性质.
线 性 代 数 厦门大学线性代数教学组 2019年5月12日4时19分 / 45.
第五章 串和数组 5.1 串的定义和操作 5.2 串的表示和实现 5.3 正文匹配模式 5.4 正文编辑 5.5 数组 5.6 数组的压缩.
§2 方阵的特征值与特征向量.
实验目的:掌握数据的顺序存储结构及它们在计算机中的操作。 实验内容:
第四章 串 String
基于列存储的RDF数据管理 朱敏
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
数据结构概论 第5章 数组和广义表 董黎刚 浙江工商大学信电学院.
插入排序的正确性证明 以及各种改进方法.
§4.5 最大公因式的矩阵求法( Ⅱ ).
第5章 其他线性数据结构.
Presentation transcript:

第4章 串、数组和广义表 丽水学院工学院

第2章 线性表 第3章 栈和队列 第4章 串、数组和广义表 线性结构 可表示为:(a1 , a2 , ……, an) 2018年11月15日

调用标准库函数 #include<string.h> 串比较,strcmp(char s1,char s2) 串复制,strcpy(char to,char from) 串连接,strcat(char to,char from) 求串长,strlen(char s) …… 2018年11月15日

第4章 串、数组和广义表 教学内容 4.1 串 4.2 数组 4.3 广义表 2018年11月15日

教学目标 1. 了解串的存储方法,理解串的两种模式匹配算法,重点掌握BF算法。 2. 明确数组和广义表这两种数据结构的特点,掌握数组地址计算方法,了解几种特殊矩阵的压缩存储方法。 3.掌握广义表的定义、性质及其GetHead和GetTail的操作。 1. 掌握串的存储方法,理解串的两种模式匹配算法; 2. 明确数组和广义表这两种数据结构的特点,掌握数组存储时地址计算方法,了解几种特殊矩阵的压缩存储方法。 2018年11月15日

4.1 串的定义 串(String)----零个或多个字符组成的有限序列 串名 串值 n n=0 串长 空串 2018年11月15日

a=‘BEI’, b=‘JING’ c=‘BEIJING’ d=‘BEI JING’ 子串 主串 字符位置 子串位置 串相等 空格串 2018年11月15日

4.2 案例引入 案例4.1 :病毒感染检测 研究者将人的DNA和病毒DNA均表示成由一些字母组成的字符串序列。 例如,假设病毒的DNA序列为baa,患者1的DNA序列为aaabbba,则感染,患者2的DNA序列为babbba,则未感染。 (注意,人的DNA序列是线性的,而病毒的DNA序列是环状的)

4.3 串的类型定义、存储结构及运算 ADT String { 数据对象: 数据关系: 基本操作: (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) //子串的位置 (11) Replace(&S,T,V) //串替换 (12) StrInsert(&S,pos,T) //子串插入 (12) StrDelete(&S,pos,len) //子串删除 (13) DestroyString(&S) //串销毁 }ADT String 2018年11月15日

串的存储结构 顺序存储 链式存储 2018年11月15日

顺序存储表示 typedef struct{ char *ch; //若串非空,则按串长分配存储区, //否则ch为NULL int length; //串长度 }HString;

链式存储表示

链式存储表示 #define CHUNKSIZE 80 //可由用户定义的块大小 typedef struct Chunk{ char ch[CHUNKSIZE]; struct Chunk *next; }Chunk; typedef struct{ Chunk *head,*tail; //串的头指针和尾指针 int curlen; //串的当前长度 }LString; 2018年11月15日

可将多个字符存放在一个结点中,以克服其缺点 链式存储表示 优点:操作方便 缺点:存储密度较低 实际分配的存储位 串值所占的存储位 存储密度 = 可将多个字符存放在一个结点中,以克服其缺点 2018年11月15日

串的模式匹配算法 算法目的: 算法种类: 确定主串中所含子串第一次出现的位置(定位) 即如何实现教材P72 Index(S,T,pos)函数 BF算法(又称古典的、经典的、朴素的、穷举的) KMP算法(特点:速度快) 算法种类: 2018年11月15日

BF算法设计思想 i S : a b a b c a b c a c b a b T : a b c j 北京林业大学信息学院

BF算法设计思想 Index(S,T,pos) 将主串的第pos个字符和模式的第一个字符比较, 若相等,继续逐个比较后续字符; 若不等,从主串的下一字符起,重新与模式的第一个字符比较。 直到主串的一个连续子串字符序列与模式相等 。返回值为S中与T匹配的子序列第一个字符的序号,即匹配成功。 否则,匹配失败,返回值 0

BF算法描述(算法4.1) int Index(Sstring S,Sstring T,int pos){ i=pos; j=1; while (i<=S[ 0 ] && j <=T[ 0 ]){ if ( S[ i ]=T[ j ]) {++i; ++j; } else{ i=i-j+2; j=1; } if ( j>T[ 0 ]) return i-T[0]; else return 0; }

总次数为:(n-m)*m+m=(n-m+1)*m 若m<<n,则算法复杂度O(n*m) BF算法时间复杂度 例: S=‘0000000001’,T=‘0001’,pos=1 若n为主串长度,m为子串长度,最坏情况是 主串前面n-m个位置都部分匹配到子串的最后一位,即这n-m位各比较了m次 最后m位也各比较了1次 总次数为:(n-m)*m+m=(n-m+1)*m 若m<<n,则算法复杂度O(n*m)

KMP(Knuth Morris Pratt)算法 《计算机程序设计艺术 第1卷 基本算法》   《计算机程序设计艺术 第2卷 半数值算法》 《计算机程序设计艺术 第3卷 排序与查找》 http://www-cs-faculty.stanford.edu/~knuth/ 2018年11月15日

KMP算法设计思想 利用已经部分匹配的结果而加快模式串的滑动速度? 且主串S的指针i不必回溯!可提速到O(n+m)! S=‘a b a b c a b c a c b a b’ a b a S=‘a b a b c a b c a c b a b’ T=‘a b c a c’ a b c T=‘a b c a c’ i i i k k S=‘a b a b c a b c a c b a b’ T=‘a b c a c’ k

因p1≠p2,s2=p2,必有s2≠p1,又因p1=p3,s3=p3,所以必有s3=p1。因此,第二次匹配可直接从i=4, j=2开始。

改进:每趟匹配过程中出现字符比较不等时,不回溯主指针i,利用已得到的“部分匹配”结果将模式向右滑动尽可能远的一段距离,继续进行比较。

s1 s2 s3…si-j+1 si-j+2…si-2 si-1 si si+1 ‖ ‖ ‖ ‖ ≠ p1 p2 … pj-2 pj-1 pj pj+1 ‖ ‖ p1 … pk-1 pk pk+1 ① “p1p2…pk-1” = “si-k+1si-k+2…si-1” ②“pj-k+1pj-k+2…pj-1” = “si-k+1si-k+2…si-1”(部分匹配) ③ “p1p2…pk-1” = “pj-k+1pj-k+2…pj-1” (真子串)

为此,定义next[j]函数,表明当模式中第j个字符与主串中相应字符“失配”时,在模式中需重新和主串中该字符进行比较的字符的位置。 max{ k|1<k<j,且“p1…pk-1”=“pj-k+1…pj-1” } 当此集合非空时 0 当j=1时 1 其他情况 next[j]=

int Index_KMP (SString S,SString T, int pos) { i= pos,j =1; while (i<S[0] && j<T[0]) { if (j==0 || S[i]==T[j]) { i++;j++; } else j=next[j]; /*i不变,j后退*/ } if (j>T[0]) return i-T[0]; /*匹配成功*/ else return 0; /*返回不匹配标志*/

如何求next函数值 1. next[1] = 0;表明主串从下一字符si+1起和模式串重新开始匹配。i = i+1; j = 1; 2. 设next[j] = k,则next[j+1] = ? ①若pk=pj,则有“p1…pk-1pk”=“pj-k+1…pj-1pj” ,如果在 j+1发生不匹配,说明next[j+1] = k+1 = next[j]+1。 ②若pk≠pj,可把求next值问题看成是一个模式匹配问 题,整个模式串既是主串,又是子串。

p1 p2…pj-k+1…pj-1 pj pj+1 next[j]=k ‖ ‖ ≠ p1 … pk-1 pk pk+1 next[k]=k’ p1…… pk’ pk’+1 next[k’]=k” p1… pk’’ pk’’+1 next[k’’’]=k’’’ 若pk’=pj,则有“p1…pk’”=“pj-k’+1…pj”, next[j+1]=k’+1=next[k]+1=next[next[j]]+1. 若pk”=pj ,则有“p1…pk””=“pj-k”+1…pj”, next[j+1]=k”+1=next[k’]+1=next[next[k]]+1. next[j+1]=1.

模式串 a b c a a b b c a b c a a b d a b j 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 模式串 a b c a a b b c a b c a a b d a b next[j] 1 1 1 2 2 3 1 1 2 3 4 5 6 7 1 2

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

KMP算法的时间复杂度 设主串s的长度为n,模式串t长度为m,在KMP算法中求next数组的时间复杂度为O(m),在后面的匹配中因主串s的下标不减即不回溯,比较次数可记为n,所以KMP算法总的时间复杂度为O(n+m)。

next[j] = k,而pj=pk,则 主串中si和pj不等时,不需再和pk进行比较,而直接和pnext[k]进行比较。 模式 a a a a b next[j] 0 1 2 3 4 nextval[j] 0 0 0 0 4 next函数的改进 i=4 a a a b a a a a b a a a a ① a a a ② a a ③ a a a a a b i = 5; j = 1 j=4 j=3 next[j] = k,而pj=pk,则 主串中si和pj不等时,不需再和pk进行比较,而直接和pnext[k]进行比较。 j=2 j=1

模式串 a b c a a b b c a b c a a b d a b j 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 模式串 a b c a a b b c a b c a a b d a b next[j] 0 1 1 1 2 2 3 1 1 2 3 4 5 6 7 1 2 nextval[j] 1 1 2 1 3 1 1 1 2 1 7 1

void get_nextval(SString T, int &nextval[]) { i= 1; nextval[1] = 0; j = 0; while( i<T[0]){ if(j==0 || T[i] == T[j]){ ++i; ++j; if(T[i] != T[j]) nextval[i] = j; else nextval[i] = nextval[j]; } else j = nextval[j]; next[i] = j;

4.4 数组 本节所讨论的数组与高级语言中的数组区别: 高级语言中的数组是顺序结构;  高级语言中的数组是顺序结构;  而本章的数组既可以是顺序的,也可以是链式结构,用户可根据需要选择。

数组的抽象数据类型 ADT Array { 数据对象: 数据关系:

基本操作: }ADT Array (1) InitArray (&A,n,bound1, boundn) //构造数组A (2) DestroyArray (&A) // 销毁数组A (3) Value(A,&e,index1,…,indexn) //取数组元素值 (4) Assign (A,&e,index1,…,indexn) //给数组元素赋值 }ADT Array 2018年11月15日

LOC(i-1)+l = a+i*l, i > 0 一维数组 a, i = 0 LOC(i) = LOC(i-1)+l = a+i*l, i > 0 0 1 2 3 4 5 6 7 8 9 a 35 27 49 18 60 54 77 83 41 02 l l l l l l l l l l a+i*l LOC(i) = LOC(i-1)+l = a+i*l

二维数组

数组的顺序存储 以行序为主序 C, PASCAL

以列序为主序 FORTRAN

a[n][m] 二维数组的行序优先表示 设数组开始存放位置 LOC( 0, 0 ) = a LOC ( j, k ) = a + j * m + k

三维数组 按页/行/列存放,页优先的顺序存储 ① ② ③

LOC ( i1, i2, i3 ) = a + i1* m2 * m3 + i2* m3 + i3 前i1页总 第i1页的 三维数组 a[m1][m2] [m3] 各维元素个数为 m1, m2, m3 下标为 i1, i2, i3的数组元素的存储位置: LOC ( i1, i2, i3 ) = a +  i1* m2 * m3 + i2* m3 + i3 前i1页总 元素个数 第i1页的 前i2行总元素个数 第 i2 行前 i3 列元素个数

n维数组 各维元素个数为 m1, m2, m3, …, mn 下标为 i1, i2, i3, …, in 的数组元素的存储位置:

n维数组

练习 设有一个二维数组A[m][n]按行优先顺序存储,假设A[0][0]存放位置在644(10),A[2][2]存放位置在676(10),每个元素占一个空间,问A[3][3](10)存放在什么位置?脚注(10)表示用10进制表示。 设数组元素A[i][j]存放在起始地址为Loc ( i, j ) 的存储单元中 ∵ Loc ( 2, 2 ) = Loc ( 0, 0 ) + 2 * n + 2 = 644 + 2 * n + 2 = 676. ∴ n = ( 676 - 2 - 644 ) / 2 = 15 ∴ Loc ( 3, 3 ) = Loc ( 0, 0 ) + 3 * 15 + 3 = 644 + 45 + 3 = 692.

练习 设有二维数组A[10,20],其每个元素占两个字节, A[0][0]存储地址为100,若按行优先顺序存储,则元素A[6,6]的存储地址为 ,按列优先顺序存储,元素A[6,6]的存储地址为 。 352 232 (6*20+6)*2+100=352 (6*10+6)*2+100=232

数组下标(i,j) 确定 存储地址 1. 对称矩阵 k= i(i-1)/2+j 当ij j(j-1)/2+i 当i<j aji 1. 对称矩阵 [特点] 在nn的矩阵a中,满足如下性质: aij=aji (1  i, j  n) [存储方法] 只存储下(或者上)三角(包括主对角线)的数据元素。共占用n(n+1)/2个元素空间。 k= i(i-1)/2+j 当ij j(j-1)/2+i 当i<j sa a11 a21 a22 a31 aij(aji) ann k 1 2 3 4 n(n+1)/2 aji aij

C C 2. 三角矩阵 k= (i-1)(2n-i+2)/2+j-i+1 ij k= i(i-1)/2+j ij 2. 三角矩阵 [特点] 对角线以下(或者以上)的数据元素(不包括对角线)全部为常数c。 [存储方法] 重复元素c共享一个元素存储空间,共占用n(n+1)/2+1个元素空间: sa[1.. n(n+1)/2+1] 上三角矩阵 下三角矩阵 k= (i-1)(2n-i+2)/2+j-i+1 ij k= i(i-1)/2+j ij n(n+1)/2+1 i>j n(n+1)/2+1 i<j C C 上三角矩阵 下三角矩阵

3. 对角矩阵(带状矩阵) [特点] 在nn的方阵中,非零元素集中在主对角线及其两侧共L(奇数)条对角线的带状区域内 — L对角矩阵。 [存储方法] 以对角线的顺序存储 8 2 3 0 0 0 4 2 0 3 0 0 5 7 7 6 8 0 0 9 6 9 1 5 0 0 6 1 4 2 0 0 0 2 8 3 1 2 3 4 5 6 -2 -1 1 2 3 3 8 5 2 0 6 1 2 8 2 7 9 4 3 4 7 6 1 8 5 9 6 2 i1=i-j j1=j |i-j|(L-1)/2 sa s[-2..2; 1..6] k 1 n*L 五对角矩阵 k=(i1+2)*n+j1=(i-j+2)*n+j |i-j|(L-1)/2

只存储带状区内的元素 除首行和末行,按每行 L个元素,共(n-2)L+(L+1)个元素。sa[1..(n-1)L+1] k=(i-1)L+1+(j-i) |i-j|(L-1)/2 8 2 3 0 0 0 4 2 0 3 0 0 5 7 7 6 8 0 0 9 6 9 1 5 0 0 6 1 4 2 0 0 0 2 8 3 sa 8 2 3 4 2 0 3 5 7 k 1 2 3 4 5 6 7 8 9 10 7 6 8 9 6 9 1 5 6 1 11 12 13 14 15 16 17 18 19 20 4 2 2 8 3 21 22 23 24 25 26

稀疏矩阵 [特点] 大多数元素为零。 [常用存储方法] 只记录每一非零元素(i,j,aij ) 节省空间,但丧失随机存取功能 顺序存储:三元组表 链式存储:十字(正交)链表 15 0 0 22 0 -15 0 11 3 0 0 0 0 0 0 -6 0 0 0 0 0 0 0 0 91 0 0 0 0 0 0 0 28 0 0 0 66

4.6 案例分析与实现 案例4.1 :病毒感染检测 【案例分析】 因为患者的DNA和病毒DNA均是由一些字母组成的字符串序列,要检测某种病毒DNA序列是否在患者的DNA序列中出现过,实际上就是字符串的模式匹配问题。 可以利用BF算法,也可以利用更高效的KMP算法。 但与一般的模式匹配问题不同的是,此案例中病毒的DNA序列是环状的。 这样需要对传统的BF算法或KMP算法进行改进。

【案例实现】 对于每一个待检测的任务,假设病毒DNA序列的长度是m,因为病毒DNA序列是环状的,为了线性取到每个可行的长度为m的模式串,可将存储病毒DNA序列的字符串长度扩大为2m,将病毒DNA序列连续存储两次。 然后循环m次,依次取得每个长度为m的环状字符串,将此字符串作为模式串,将人的DNA序列作为主串,调用BF算法进行模式匹配。 只要匹配成功,即可中止循环,表明该人感染了对应的病毒;否则,循环m次结束循环时,可通过BF算法的返回值判断该人是否感染了对应的病毒。

【算法步骤】 ① 从文件中读取待检测的任务数num。 ② 根据num个数依次检测每对病毒DNA和人的DNA是否匹配,循环num次,执行以下操作: 从文件中分别读取一对病毒DNA序列和人的DNA序列; 设置标志性变量flag,用来标识是否匹配成功,初始为0,表示未匹配; 病毒DNA序列的长度是m,将存储病毒DNA序列的字符串长度扩大为2m,将病毒DNA序列连续存储两次; 循环m次,重复执行以下操作: 依次取得每个长度为m的病毒DNA环状字符串; 将此字符串作为模式串,将人的DNA序列作为主串,调用BF算法进行模式匹配,将匹配结果返回赋值给flag; 若flag非0,表示匹配成功,中止循环,表明该人感染了对应的病毒。 退出循环时,判断flag的值,若flag非0,输出“YES”,否则,输出“NO”。

小结 1. 了解串的存储方法,理解串的两种模式匹配算法,重点掌握BF算法。 2. 明确数组和广义表这两种数据结构的特点,掌握数组地址计算方法。