当前位置:
文档之家› 数据结构第7and 8讲--字符串与模式匹配
数据结构第7and 8讲--字符串与模式匹配
链串(字符链表) struct StrNode; //结点类型 typedef struct StrNode *PStrNode; //指针类型 struct StrNode
{ char c; //字符 PStrNode link; //指针
};
typedef struct StrNode *LinkString; //链串指针类型
河海大学计算机与信息学院
第3章 字符串
第7、8讲:字符串与模式匹配
回顾
线性表:有限个、类型相同的元素组成的 有序序列
k0 k1 k2 k3 k4
-- 顺序表(逻辑相邻<=>物理相邻) 便于按序号随机访问;存储密度大;
-- 链表 H k0
k1
k2
k3
k4 ∧
方便插入、删除结点;无惧表长变化;
3.1 字符串
2) 则j在主串上回溯,i在模式串上亦回溯
jj 如何减少回溯, 或
t: a b b a b a 提高右移位数? p: a ab ba a
i ii
提高匹配速度
减少回溯的可行性
”不等”, 即pi ≠ tj , 等价于:前面都等, 当前不等
p0= tj-i, p1= tj-i+1, …, pi-1= tj-1, pi ≠ tj
q->c=p->c; q->link=NULL; //置结点q
t->link=q; t=q; //在s1的尾巴t之后插入结点q p=p->link; } return s1; } //s1的长度<=j
字符串的表示 – 小结
顺序表示 顺序串 链接表示 链串
特殊线性表的不同实现
• 许多编程语言提供了标准的字符串库, 例如,C语言标准库 (string.h)
5) String subStr(String s1, int i, int j) //求子串 //求串s1中从第i个起连续j个字符组成的序列
6) int index(String s1, String s2) //求子串位置 //若s2是s1的子串,则返回s2在s1中的位置
7) String StrCopy(String T, String S) //复制S到T
• 空串:长度为0的串,记为s=“”, 注意与“ ”(空格构成的串)进行区别;
• 字符串相等:每一个位置处的字符都相等; 长度相等;
• 字典序关系:若字符集上有全(线)序关系, 设A=“a0a1…an-1”, B =“b0b1…bm-1”,
1) 若存在k使ai==bi (i=0,…,k-1)且ak<bk
else printf(“Out of space! \n”); //报错 return(pst); }
• 已知带头结点的链串s, 求其子串(第i个字符开始、连续j个字符组成的串) 1) 创建空链串s1; 2) 判断i与j的值是否都 >0;否, 则返回空串; 3) 查找s的第i个结点: 4) 未找到,则返回空串; 5) 找到,则依次取j个字符、从尾部插入到s1中, (若不够j个字符,则有多少取多少到s1中);
或 2) ai==bi (i=0,…,n-1)且n<m 则 A<B 例 A=“abc”, B=“abd” 或 B=“abcd”
子串、主串、子串位置
子串:s串中任意个、连续的字符所组成的 串s1称为原串s的子串,s称为s1的主串
“Hohai Universtiy”
-- 空串是任意串的子串;
“University”
11) delete(String s, int i) //删除串s中、位置i处的字符
12) replace(String s, int i, char c) //将串s中、位置i处的字符用c替换
3.2 字符串的表示/实现
字符串:数据元素为字符的线性表 -- 顺序表示 (顺序串): 将所有字符顺序地存储在一组地址连续的 内存单元,字符数组
j=2
p0= t0, p1= t1, p2 ≠ t2
t: a b b a b 若a 已知 p0≠ p1, p0=p2
p: a b a
i=2
p0≠ t1, p0≠ t2
朴素匹配省略两步
else return 0; }
代价分析
最坏情况 (例如t=“00……01”, p=“0001”) 每次都在p的最后一个字符处匹配失败
主串长度n, 模式串长度m; 最多比较 n-m+1 趟, 每趟最多比较 m 次; 时间复杂度O(m*n)
朴素匹配小结
朴素模式匹配的特点:遇到”不等”, 即pi ≠ tj 1) p相对于t 仅右移1位
-- 链接表示 (链串): 字符链表
3.2 字符串的顺序表示
顺序串定义
struct SeqString { int MaxNum; //最大长度
int n; //实际字符个数 char *c; }; //指向字符数组的指针 typedef struct SeqString *PSeqString; //顺序串指针类型
• C语言中的字符串直接由字符数组表示, 以” \0”作为串结束的标志
3.3 模式匹配
• 模式匹配:在目标串t中查找与模式串p相同的
子串 例 t = t0 t1 t2 t3 t4…tn-1 目标(target)
p = p0p1…pm-1
模式(pattern)
• 求串s2在串s1中第一次出现的位置: int index(String s1, String s2)
• 创建空顺序串 (与课本p71程序逻辑相同)
PSeqString creatNullStr_seq(int m)
{ PSeqString pstr = (PSeqString)malloc //申请顺序串空间 (sizeof(Struct SeqString));
if (pstr==Null) {printf(“out of !\n”); return Null;}
8) DestroyString (String S) //销毁串S
9) int StrCompare (String S, String T) //比较大小 //若S=T,返回0; 若>, 返回值>0; 若<, 返回值<0
3.1 字符串的抽象数据类型
串与字符之间的操作:
10) insert(String s1, int i, char c) //在串s中、位置i处插入字符c
j=2
p0= t0, p1= t1, p2 ≠ t2
t: a b b a b 若a 已知 p0≠ p1, p0=p2
p: a b a
i=2
p0≠ t1, p0≠ t2
朴素匹配省略两步
直接p0与t3开始比较
减少回溯的可行性
利用”不等”及其之前包含的”相等信息” ,以及 模式p中的”相等和不等信息” 可减少回溯
字符串:数据元素为字符的线性表;
计算机可以执行
数值计算
非数值计算 例如,关键词搜索
图像搜索 语音搜索
3.1 字符串
一个字符串可以记为:S=“s0s1s2s3” -- S是串的名字; -- 字符序列s0s1s2s3是串的值; -- 字符个数是串的长度; -- 串中元素可以是字母、数字、其他字符 (空格、%,=,@ 等键盘可以输入的) -- 双引号是串的定界符,不是串的一部分;
}
实际结点
t=s1; // p指向s的第i个结点, t指向子串s1的尾巴 for(k=1;k<=j; k++) //复制j个结点, 尾插到s1中
if(p != NULL) {q=(PStrNode)malloc(sizeof(struct StrNode));
if(q==NULL) {printf(“Fail !\n”); return s1;}
• 应用:搜索引擎, 病毒特征码匹配, DNA匹配
3.3 模式匹配
• 朴素的模式匹配 j j jjjj j
t: a b b a b a p: pa: abp: bap: ab ba a 下标i>= p的长度
i i i i i i i 找到
• 无回溯的模式匹配
3.3 朴素的模式匹配
jj j
t: a b b a b a p: pa: ab ba a
{ if(s->n < i+j-1) j=s->n-i+1; //s不够长, 重置j for(k=0; k<j; k++)
s1->c[k] = s->c[i-1+k];//复制到s1中 s1->n = j; //设置子串的实际长度 }
return s1; } 时间代价: O(j)
3.2 字符串的链接表示
else //s不够
while(p!=NULL && k<=i) {p=p->link; k=k+1;}
return s1; if (p==NULL || k!=i+1)
if (p==NULL)
{ printf(“i is illegal !\n”);
return s1;
return s1;
//s只有i-1个
while(i<p->n && j<t->n)//下标有意义 if (p->c[i]==t->c[j]) //相等, 则继续向后 { i++; j++;} else { j=j-i+1; i=0;}//不等, 则重新定位i, j
if (i >= p->n) //(第1次)匹配成功的标志 return (j- p->n +1);//返回出现位置下标+1