数 据 结 构 Ch.4 串 计 算 机 学 院 肖明军 Email: xiaomj@ustc.edu.cn http://staff.ustc.edu.cn/~xiaomj.

Slides:



Advertisements
Similar presentations
王 子 坊 《洛陽伽藍記》 主講教師:張其昀.
Advertisements

幼 兒 遊 戲 訪 談 組別:第七組 班級:幼保二甲 姓名:4A0I0008劉俐音 4A0I0043吳碧娟 4A0I0059劉又甄 4A0I0060江佳霓 4A0I0061蕭靖霓 4A0I0079王毓君.
与优秀的人在一起
第八章 影响消费心理的社会因素 第一节 消费习俗的影响 第二节 流行对消费行为的影响 第三节 消费习惯与消费心理 第四节 感性消费与消费心理
电子成绩单项目实现.
102年度統一入學測驗 報名作業說明會 時 間:101年12月14日(星期五) A.M.9:00~10:20 地 點:行政七樓講堂
千里之行, 始于规范 兴隆中学 八(1)班主题班会.
姓名:劉芷瑄 班級:J201 座號:39號 ISBN:957-33-1963-2
小微企业融资担保产品介绍 再担保业务二部 贾天
情緒與壓力管理─背部舒緩 指導老師:彭易璟 第六組組員:會資三乙 499A0047 謝宛霖 會資三乙 499A0019 吳汶諭
数据结构概论 第2章 线性表 董黎刚 浙江工商大学信电学院
南投縣道路交通安全聯席會報 101年4月份會議程序
第三章 鏈結串列 Linked List.
[聚會時, 請將傳呼機和手提電話關掉, 多謝合作]
資料結構與演算法 課程教學投影片.
数据结构——树和二叉树 1/96.
TA:于波 计算机科学工程系 上海交通大学 December 5, 2009
第八章 查找.
第十章 内部排序 10.1 概述 10.2 插入排序 直接插入排序 其他插入排序 希尔排序
第二章 线性表 1 线性表的逻辑结构及其基本操作 2 线性表的顺序存储结构 3 线性表的链式存储结构 4 静态链表 5 应用实例.
[聚會時,請將傳呼機和手提電話關掉,多謝合作]
C语言基础——指针的高级应用 Week 05.
組員:蔡典龍4970E027 蕭積遠4970E026 王建智4970E050 李雅俐4970E025 賴品言4970E054
天气和气候.
[聚會時,請將傳呼機和手提電話關掉,多謝合作]
专题研讨课二: 数组在解决复杂问题中的作用
Linked List Operations
單向鏈結串列 Singly Linked Lists.
第4章 串 串的基本概念和C语言的串函数 串的存储结构 动态数组实现的顺序串 串的模式匹配算法——BF算法 主要知识点.
数据结构 Data Structure 主讲人:王国军,郑瑾 中南大学 中南大学信息院计科系
Zn 模式匹配与KMP算法 Zn
补充内容 结构体 概述 定义结构体类型和定义结构体变量 结构体变量的引用 结构体变量的初始化 指针与结构体 用typedef定义类型的别名.
数 据 结 构 Ch.6 树 计 算 机 学 院 肖明军
结构体和共用体 2 梁春燕 华电信息管理教研室.
数据结构 第4章 串.
线性表小结 元素之间的线性关系 顺序表 顺序表:元素相邻存储 单链表:后继指针链接 一维数组 给定下标随机存取
第2章 线性表 线性表抽象数据类型 顺序表 主要知识点 单链表 循环单链表 循环双向链表 静态链表 设计举例.
第5章 堆疊(Stacks) 5-1 堆疊的基礎 5-2 堆疊的表示法 5-3 堆疊的應用 - 運算式的計算與轉換
第八章 查找表 8.1静态查找表 8.2动态查找表 8.3哈希表及其查找.
第 3 讲 线性表(一).
第三章 栈和队列.
陈海明 副教授 信息学院 计算机系 电子信息类非计算机专业选修课 程序设计实践 陈海明 副教授 信息学院 计算机系
設計者:顏嘉慧老師 協同設計:黃錦照老師 實施對象:觀二乙全體同學
中央广播电视大学开放教育试点课程 数据结构 辅导教师 倪政林.
第9章 内部排序 9.1 概述 9.2 插入排序 9.3 快速排序 9.4 选择排序 9.5 归并排序 9.6 基数排序
耆康會長者中央議會 <<長者與社會參與>>計劃培訓
数据结构 第9章 查找 什么是查找?? 静态查找 动态查找 哈希表 数据结构.
6.6 Huffman树及其应用 王 玲.
西师大版 语文 一年级 上册 十个数.
第四章串 4.1 串类型定义 4.2 串的表示和实现 4.3 串的模式匹配算法 4.4 串操作应用举例.
数据结构 第八章 查找.
王玲 第 2 章 线性表 王玲 2019/2/25.
教 师:曾晓东 电 话: E_mail: 计算机软件技术基础 教 师:曾晓东 电 话: E_mail:
第五章 串和数组 5.1 串的定义和操作 5.2 串的表示和实现 5.3 字符串应用 5.4 字符串匹配算法 5.5 数组
3.1 线性表及逻辑结构 3.2 线性表的顺序存储 3.3 线性表的链式存储 3.4 链式存储结构的应用
7.1 广义表的概念 广义表是n(n≥0)个数据元素组成的序列,其中每个数据元素或是单个数据元素(简称原子),或仍然是一个广义表 。
第十章 结构体与链表 西安工程大学.
C语言复习3----指针.
第五章 串和数组 5.1 串的定义和操作 5.2 串的表示和实现 5.3 字符串应用 5.4 字符串匹配算法 5.5 数组
第1章 绪论(二) 教学目标 理解算法的特性及评价标准 掌握算法时间复杂度和空间复杂度的分析方法 1/
Ch.9 查找 §9.1 基本概念 查找和排序是两个重要的运算
本教學投影片係屬教科書著作之延伸,亦受著作權法之保護。
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
单片机原理及应用 实践部分 主讲人:刘 强 四川工商学院单片机教学团队 单片机原理及应用 实践部分 主讲人:刘 强
字符串模式匹配- KMP 主讲:朱佳 博士 华南师范大学计算机学院.
随机算法 东南大学计算机学院 方效林.
第三章 线性表 3.1 线性表的类型定义 3.2 顺序存储的线性表 3.3 链式存储的线性表 3.4 有序表 3.5 顺序表和链表的综合比较.
顺序查找与二分查找复习.
臺中市龍山國小 校園常見瓢蟲辨識   瓢蟲屬於鞘翅目瓢蟲科。目前世界上約有5000多種瓢蟲,台灣地區約有80種以上,其中能捕食有害生物的瓢蟲約七十種之多。瓢蟲因為捕食有害生物為主食,所以又稱為『活農藥』。
第六章 复合数据类型 指针的声明与使用 数组的声明与使用 指针与数组的相互引用 字符串及相关库函数 new与delete
Presentation transcript:

数 据 结 构 Ch.4 串 计 算 机 学 院 肖明军 Email: xiaomj@ustc.edu.cn http://staff.ustc.edu.cn/~xiaomj

Ch.4 串 字符串是一种特殊的线性表,它的每个结点仅有一个字符组成 早期,串只能出现在输入输出中,以直接量形式出现,不参与运算

§4.1 串定义及运算 基本概念 串:零个或多个字符组成的有限序列 记为s=“a1a2……an”(n≥0) s为串名,引号中为串值 ai:字母,数字等字符 串长度:n,n=0为空串 空白串:“ ”和“”之差别

§4.1 串定义及运算 子串:串中任意个连续字符组成的子序列称为该串的子串,包含子串的的串称为主串 特别地:空串是任意串的子串 任意串是其自身的子串 串常量:只能引用,不能改变,一般用直接量表示 有的语言允许对其命名,如C++; const char path[]=“dir/bin/appl” 串变量:可读写,一般有名字

§4.1 串定义和运算 基本运算 ①求串长 ②复制 ③拼接 ④比较 ⑤子串定位 C中<string.h> 比较 相等:长度相等,且各对应位置上字符亦 相等 大小:字典序 “axy”<“ba” “baker”>“Baker”

§4.1 串定义及运算 子串定位 子串在主串中首次出现时,该子串首字符对应主串中的位置序号 A=“This is a string” B=“is” 序号为3 3 6 其它复杂操作:均可用基本操作构成 C中有丰富的函数

§4.2 串的存储结构 串是特殊线性表,节点是单个字符,故有特殊技巧 静态存储分配的顺序串 直接用定长字符向量来表示,上界预先给定 #define MaxStrSize 256 //用户定义 Typedef char SeqString[MaxStrSize]; SeqString S; //S是可容纳255个字符的顺序串 终结符:‘\0’是串终结符,放在串值尾部 串长属性:若不设终结符 typedef struct { char ch[MaxStrSize]; //可容纳256字符 int length; }SeqString

§4.2 串的存储结构 动态存储分配的顺序串 用C的malloc和free动态申请和释放向量空间,有两种形式: typedef char *string; //C中串库相当于使用此类//似定义 typedef struct { char *ch; //若串非空,则按串实际长度分配,否则为NULL int length; }Hstring

§4.2 串的存储结构 链串 块链存储 结点大小 大小为1: 大小为3: 存储密度d d=数据大小/结点大小

§4.3 串的模式匹配算法(串定位运算) 朴素的定位算法(串匹配) 主串:目标串(正文串Target,Text) 子串:模式(串)(子串,Pattern) 设T=“t0t1…tn-1” P=“p0p1…pm-1” (0≤m≤n) 通常m<<n 应用:文本编辑,基因匹配等

对合法的位置0≤i≤n-m(合法位移),依次将目标串中的子串T[i..i+m-1]和模式串P[0..m-1]进行比较 §4.3 串的模式匹配算法 思想: 对合法的位置0≤i≤n-m(合法位移),依次将目标串中的子串T[i..i+m-1]和模式串P[0..m-1]进行比较 若T[ i .. i+m-1]=P[0 .. m-1](即:“titi+1…ti+m-1”=“p0p1…pm-1”) 则称从位置i开始的匹配成功; 否则,存在某个0≤j≤m-1,使‘ti+j’≠‘pj’,则称从位置i开始的匹配失败

§4.3 串的模式匹配算法 有时需在T中找到所有有效位移 有效位移:若T[i..i+m-1]=P[0..m-1],则i称为有效 位移 总结:朴素的串匹配算法是对合法位移检查其是否 为有效位移 有时需在T中找到所有有效位移 通常找首次出现的有效位移

§4.3 串的模式匹配算法 int NaiveStrMatch ( SeqString T, SeqString P ) { //顺序串上实现 int i, j, k; int m = P.length, n = T.length; for (i = 0; i<=n-m; i++) { //i为合法位移,检查其是否为有效位移 j = 0; k=i; //j指向模式,k指向目标 while(j<m && T.ch[k] == P.ch[j]){ //检查i是否为有效位置 k++; j++; //依次检查相应位置是否匹配 } if (j == m) //即T[i..i+m-1]=P[0..m-1],i为有效位移 return i; //返回首次出现的有效位移i,匹配成功 } //end for return -1; //匹配失败,所有合法位移均不是有效位移

§4.3 串的模式匹配算法 该算法是将模式串看作是在目标串上向右滑动的模板

§4.3 串的模式匹配算法 时间: 最坏情况:对所有合法位移,均要比较到模式的最后一个字符,才能确定位移无效 即:O((n-m+1)m)≈O(n*m) // n>>m 最坏情况发生在: 目标串是 an-1b 模式串是 am-1b // 最后一次成功 用链串表示时定位运算类似

T:…ti-j+1…ti… ti-j+1ti-j+2 …titi+1 P: p1……pj p1……pj-1pj §4.3 串的模式匹配算法 KMP算法(不带回溯) 下标仍从1算 原因分析 P右移1位 T:…ti-j+1…ti… ti-j+1ti-j+2 …titi+1 P: p1……pj p1……pj-1pj 原因:没有利用部分匹配的结果 若能将模式串右移一段距离,则速度更快 回溯 比较点

§4.3 模式匹配算法 T: a b b a b a P: a b a 失败时有:p1=t1,p2=t2,p3≠t3 §4.3 模式匹配算法 T: a b b a b a P: a b a 失败时有:p1=t1,p2=t2,p3≠t3 若将P右移1位,则p1?t2,因为 p1≠p2, p2=t2 p1≠t2 ,故右移1位后仍失败 ②若将P右移2位,则p1?t3,因为 p1=p3,p3≠t3 p1≠t3,故右移2位后仍失败 结论:上图比较失败时应直接将P右移3位(即i=1,2,3均为无效 位移),即直接比较p1和t4,比较点不回溯。 Note:上述观察告诉我们,分析模式本身,就可知道潜在的有效 位移

§4.3 模式匹配算法 若使比较点不回溯(i不回溯),则当 ti≠pj(T[i-j+1..i-1]=P[1..j-1], §4.3 模式匹配算法 若使比较点不回溯(i不回溯),则当 ti≠pj(T[i-j+1..i-1]=P[1..j-1], 即P的前j-1个字符与相应T上字符相等: ti-j+1…ti-1=p1…pj-1)时,P中哪个字符应与ti继续比较? 因为i不动时,必定是将模式右移一段距离,所以不妨设pk(k<j)应与ti 继续比较。 Knuth发现,k值仅依赖于P的前j个字符的构成,与目标T无关。 采用next[1..m]数组,用next[j]=k表示当ti≠pj时,下一 个应与ti比较的是pk 若P中任何字符均无需与ti比较,则将p1与ti+1比较,此时令next[j]=0。P右移最大

…ti-j+1 …ti… ti-j+1…ti-k+1……ti p1……pj … p1……pk…pj… §4.3 模式匹配算法 P的右移位数为:j-next[j] …ti-j+1 …ti… ti-j+1…ti-k+1……ti p1……pj … p1……pk…pj… j-k 右移j-k ? 右移i-k+1-(i-j+1)=j-k

§4.3 模式匹配算法 算法 若已知next[1…m],则匹配算法如下: int KMPMatch ( char T[] ,char P[] ) { //T[0]和P[0]分别表示长度 n=T[0] ; m=P[0] ; //长度 i=j=1; //开始 t1~p1 while (i<=n && j<=m) if (T[i]==P[j]) { i++; j++; //继续比较下一位 } else { //ti≠ pj k=next[j]; if (k>0) j=k ; //比较ti和pk: ti~pk else { j=1; i++; } //比较ti+1和p1:ti+1~p1 } //endif,endwhile

§4.3 模式匹配算法 算法 if (j>m) //匹配成功 return i-m; //注意成功时,i和j均多加了1 else return 0; //匹配失败 } 时间:循环主要取决于i只增不减,因为n>>m,所以时间为O(n)

整数数组:0≤next[j]<j,即0 ≤k<j 当ti≠pj时,若next[j]=k>0,则比较ti和pk,此时有: §4.3 模式匹配算法 next数组的性质 整数数组:0≤next[j]<j,即0 ≤k<j 当ti≠pj时,若next[j]=k>0,则比较ti和pk,此时有: T[ i-k+1..i-1 ]=P[ 1..k-1 ] //长度为k-1 T[ i-j+1..i-1 ] =P[ 1..j-1 ] //失败前部分匹配,长度为j-1 P[ j-k+1..j-1 ]=P[1..k-1] // “p1…pk-1”=“pj-k+1…pj-1” 当ti≠pj时,k的值应等于串P[1…j-1]中前后缀相等的子串的长度加1 T:…ti-j+1… ti-k+1 … ti-1 ti… p1……pj-k+1…pj-1pj… // 前j-1个字符相等 P右移j-k位: p1……pk-1pk… // 前k-1个字符相等 ?

当满足性质2的k有多个(即前后缀相等的子串有多个)时,应取最大的k值。 原因:k最大,模式P右移j-k最少,不丢失任何匹配机会。 §4.3 模式匹配算法 当满足性质2的k有多个(即前后缀相等的子串有多个)时,应取最大的k值。 原因:k最大,模式P右移j-k最少,不丢失任何匹配机会。 例: j 1 2 3 4 T a a a a b b b b P a a a b 在P[1..3]中,k=3最大,j-k=1位右移最少,k=2,k=1时失去匹配机会 即P[1..3]中,前后缀相等的最大真子串为P[1..2]=P[2..3],长度+1=3=k P右移1位,匹配成功 P右移2位、3位均失败

§4.3 模式匹配算法 真子串不包括自身,但包括空串 真子串:”aa” , “a” , “” 长度: 2 1 0 k : 3 2 1

§4.3 模式匹配算法 若P[1…j-1]不存在首尾相同的字符串,或者说仅存在长度为零的相同前后缀(空串)子串,则k=1,即p1与ti继续比较 特别地,若j=1(即ti≠p1),则P中任何字符无法与ti继续比较,P右移1位,将p1和ti+1继续比较。按next定义,可取next[1]=0(对任何P成立)。 综上所述,当ti ≠pj时 0 j=1 P[1…j-1]中前后缀相等的最大真子串的长度加1(包括空串),即: Max{k|1≤k<j 且”p1…pk-1”=“pj-k+1…pj-1”} //k=1时,为空串 例: j 1 2 3 4 5 6 7 8 P a b a a b c a c next[j] 0 1 1 2 2 3 1 2 next[j]=

§4.3 模式匹配算法 next数组生成(递推法) 设next[i]=j已知,求next[i+1] (i≥1) §4.3 模式匹配算法 next数组生成(递推法) 设next[i]=j已知,求next[i+1] (i≥1) 由性质4告知我们,对任何模式P,总有next[1]=0 成立,给出了递推基础 ∵next[1]~next[i]已知,且已知next[i]=j ∴P[1…i-1]中有: “p1…pj-1”=“pi-j+1…pi-1” //最大真子串长度为j-1 扩充一个字符pi后,比较pj~pi 若pi=pj,则P[1…j]=P[i-j+1…i] 即P[1…i]中前后缀的最大真子串长度为j,故 next[i+1]=j+1 或者 next[i+1]=next[i]+1

§4.3 模式匹配算法 若pi≠pj,则将求next值的问题看成是模式匹配问题,即P既为主串又为模式串 §4.3 模式匹配算法 若pi≠pj,则将求next值的问题看成是模式匹配问题,即P既为主串又为模式串 将P右移,用next[j]=k作下标,比较pk~pi 即:令j←next[j],如此反复比较pi~pj 至pi=pj(情况①)或者 j=0,令next[i+1]=1为止 //没有一个字符与pi比较 例子自己分析 目标串: p1…pi-j+1…pi-k+1…pi-1 pi… 模式串: p1……pj-k+1…pj-1 pj… p1……pk-1 pk ?

§4.3 模式匹配算法 void GetNext (char p[] , int next[]) { §4.3 模式匹配算法 void GetNext (char p[] , int next[]) { //求模式串P的next数组(递推法)i-主串指针 i=1; j=0; next[1]=0; m=P[0]; //模式串长度 while (i<m) //求next[i+1] if (j==0) next[++i]=++j; //next[i+1]=1 else //j>0 if (P[i]==P[j]) next[++i]=++j; //next[i+1]=j+1 else //pi≠pj j=next[j]; } //可改进为书上一样的算法

§4.3 模式匹配算法 时间:O(m) KMP算法的时间加上求next数组后为O(n+m) §4.3 模式匹配算法 时间:O(m) KMP算法的时间加上求next数组后为O(n+m) 当n>>m时,它远远优于朴素匹配,尤其是模式串 中存在很多“部分匹配”时 但当n≈m时,朴素匹配可能更好 next数组的改进 next性质5:若ti≠pj时,设next[j]=k>0,应比较ti~pk 若已知pk=pj,则必有ti ≠pk,此时应使用next[k]=k’ (k’>0)为下标继续比较:ti~pk’

§4.3 模式匹配算法 即可用下述方式节省时间: 当pj=pk时,将next[j]置为next[k] 此过程可重复! 例: §4.3 模式匹配算法 即可用下述方式节省时间: 当pj=pk时,将next[j]置为next[k] 此过程可重复! 例: j 1 2 3 4 5 j P next[j] nextval[j] P a a a a b 1 a 0 0 next[j] 0 1 2 3 4 2 a 1 0 改进 nextval[j] 0 0 0 0 4 3 a 2 0 pj p2 p3 p4 p5 4 a 3 0 pk p1p2 p3 p4 5 b 4 4 ti≠p2,比较ti~pnext[2] ∵p2=p1,next[2] ←next[1] ti ≠p3,ti~pnext[3], ∵p3=p2∴next[3]←next[2]

§4.3 模式匹配算法 求nextval算法 与书上不一样的算法,请比较 §4.3 模式匹配算法 求nextval算法 与书上不一样的算法,请比较 void GetNextVal (char P[], int nextval[]) { //求nextval i=1; j=0; nextval[1]=0; m=P[0]; while (i<m) { //已知nextval[i],求nextval[i+1] while (j>0 && P[i] != P[j]) j=nextval[j]; // 出循环时j=0或P[i]=P[j] i++; j++; if (P[i] ==P[j]) nextval[i] = nextval[j]; // 性质5 else nextval[i] = j; // nextval[i+1] = j+1 } 时间仍为O(m)