宁波seo优化专栏

宁波seo优化:从根结点到该叶子所经历的边的所有

发布时间:2018-09-22 18:48:27

  //////////////串类的findG方法KMP匹配算法////////////1
  intCMyString::find(constCMyString*S){
  inti,j,*next-newint[s->length];
  GenKMPNext(next,s);

从根结点到该叶子所经历的边的所有标识串联起来后恰好拼出S的从i位置开始的后缀的图片123

  for(i-0,j-0;ilength&&j  if(s->str[i]--str[j]){i++,j++;}elseif(next[i]>=0)i=next[i];
  else
  
  }
  if(i>=s->length)
  returnj-s->length;
  else
  return-1;

从根结点到该叶子所经历的边的所有标识串联起来后恰好拼出S的从i位置开始的后缀的图片125

  BM算法
  BM(Boyer-MOOre)算法是一个精确字符串匹配的算法,它可以实现髙效率的模式匹配。BM算法的关键和KMP类似,也是构造一个辅助数组,不过,不同于KMP算法的是,BM算法的辅助数组大小只和匹配串的字符集大小相关(一般情况下也就是ASCII字符集,256个字符),其内容和模式串相关,辅助数组的内容即是模式串的索引。
  给定一个特定的字串P(通常又称为模式),在一个大的文本T中进行査找,确定P是否在T中出现,出现则给出相应位置。BM算法的基本思想是先对模式P进行预处理,计算两个偏移函数:BadChar(坏字符)和Goodsuffix(好后缀),然后将文本和模式对齐,从右往左进行匹配,当文本字符与模式字符不匹配时,根据函数BadChar和Goodsuffix计算出的偏移值,取两者中的大者。将文本指针往右移,匹配成功则予以输出。
  BadChar[a]=min{j11^j^m-1andP[m-1-j]=a}
  如果a未在模式字符中出现,则
  BadChar[a]=m
  suff[i]-max{k|T[i-k+1i]=P[m-k..m-1],即suff是P[0..i]和T的最长一般后缀。计算suff数组使得计算Goodsuffix函数变得简洁。
  Goodsuffix[m-1-suff[i]]=m-1-i
  在某次匹配中,文本字符T[i+j]与模式字符P[j]匹配不成功,按BM算法,则比较BadChar[T[i+j]]—(m—l—j)与Goodsuf£ix[j]的值,取大者作为偏移量,然后将文本指针i往后移动偏移量,然后再从后往前进行比较。
  如果模式被扫描完,则找到了模式的一次出现,文本指针右移Goodsuffix[0]。
  以上述方式处理文本直至文本末尾,可以找出模式的所有出现位置。

从根结点到该叶子所经历的边的所有标识串联起来后恰好拼出S的从i位置开始的后缀的图片124

  从上面可以看出,BM算法用了3种有效的方法,从右到左扫描、坏字符规则和好后缀规则,从右到左扫描的意思是从最后一个字符开始向前匹配,而不是习惯上的从开头向后匹配。
  坏字符规则是,从右到左的扫描过程中,发现I与巧不同,如果P中存在一个字符pk与乃相同,且k  T:abcbadf
  P:cbaxad
  P:cbaxa
  图5-4比较过程一
  用R表示字符x在P中出现的最右位置,此例中R(。b)=2。可以看出使用从右到左扫描和坏字符规则可以跳过T中的很多位置不去检査,从而使时间复杂度低于线性。
  好后缀规则是,从右到左的扫描过程中,发现Ti与0不同,检査一下相同的部分t是否在P中的其他位置出现。
  如果t与t’的前一个字母不相同,就将P向右移,使?与T中的t对齐。

从根结点到该叶子所经历的边的所有标识串联起来后恰好拼出S的从i位置开始的后缀的图片126

  如果t‘没有出现,则找到与t的后缀相同的P的最长前缀X,向右移动P,使x与T中t的后缀相对应(见图5-5)。
  N:123456789101112131415161718
  T:abcbadftbcfaqVtbce
  P:cbcabceabc
  P:cbcabceabc£
  图5-5比较过程二
  可见,并不是将P向右移让P5与T9对齐,而是让P2与T9对齐,因为P1与P8不相同。用L表示t’的最大位置,此例中,L=3(见图5-6)。
  Ns123456789101112131415161718
  T:abcbadfTbcfaqvtbce
  PsbccabceTbc
  Psbccabcetbc
  图5-6比较过程三
  可见,当P向左找不到tbc时,就找到tbc的最长与P的前缀匹配的后缀,并将P向右移。用L表示这个最长后缀的长度,这个例子中i=8o下面是用C语言实现BM算法的程序。
  #include
  #include
  #include
  /*辅助数组,取决于字符集,默认为采用ASCII字符集,256个元素*/#defineLEN256
  intBMMatcher(char*srchar*p,intindex,intposition[])参数说明:
  char*s:匹配串
  char*p:模式串
  intindex:模式串匹配的起始位置,是四配串的索引intposition[]:辅助数组
  #/
  {
  intlen=strlen;inti,j,nextindex;i=strlen-1;j=index+strlen-1;for(;i>=0;i--,j--){
  if(s[j]!=p)break;
  }
  if(i<0)return0;/*匹配成功*/
  elseif(position[s[j]]>0)nextindex=index+i-position[s[j]];elsenextindex=index+1;
  if(nextindex>LEN-strlen)return-1;elsereturnnextindex;/*测试,匹配串和模式串都使用小写字符*/
  /*匹配失败,无法进行下一次匹配*/*四配失败,需要下一次匹配*//*辅助数组*/
  /*四配串*/?
  /*模式串*/
  /*构造辅助数组,关键的一步*/
  intmain()

从根结点到该叶子所经历的边的所有标识串联起来后恰好拼出S的从i位置开始的后缀的图片118

  {
  intposition[LEN]={0};
  char*src=“itisjustatest,whatwouldyoudo?‘?;char*patten=”whatwould“;inti,nextindex,index=-2,pos=0;for(i=0;i  nextindex=index;
  index=BMMatcher(src,patten,nextindex,position);if(index=--l)
  printf(”Cannotfindit “);
  if(index==0)
  printf(”Findit,theindexis:%d. ,,znextindex);system(“PAUSE”);return0;Hi倒卵篛訓
  倒排文档是一种面向单词的索引机制,相对顺排文档而言,是将顺排文档中可检索字段的作者名、关键词、分类号等取出,按一定规则排序,归并相同词汇,并把在顺排文档中相关记录的记录号集合赋予其后,以保证通过某一特征词能够快速、方便地获取相关记录。

从根结点到该叶子所经历的边的所有标识串联起来后恰好拼出S的从i位置开始的后缀的图片120

  由于倒排文档的组成特点,使得许多数学检索模型(如布尔模型、集合运算等)能够方便地用于信息检索中,它把两个检索词的逻辑运算转换成了两个检索词之间的记录号集合的运算。目前最常见的倒排文档索引为逆波兰展开法。
  倒排索引
  倒排文档的检索算法一般分成如下3步进行。
  词汇査找
  将査询串中的单词和模式分割成独立的部分,短语和近似查询串被分割成单个词汇。
  査找铒ec出璟的情况
  获取与査询串中所有词汇相关的出现情况列表。
  谓汇出现情况的橾作
  主要是通过对上一步中获取的词汇出现情况的操作实现短语查询、近似査询和布尔査询。如果词汇出现情况采用的是块寻址方式,那么在执行这些操作的时候就必须对这些块中的文本进行检索,以获取所查询的词汇在文本中的具体位置。

从根结点到该叶子所经历的边的所有标识串联起来后恰好拼出S的从i位置开始的后缀的图片122

  这样,在对倒排文档进行检索的时候总是从词汇表开始査询。因为一般说来,词汇表可以与倒排文档分开存放,而且它的空间需求比较少,适合于放置在内存中。
  对于单个词汇的査询来说,只要从词汇表中找到对应的单词就可以找到指向该单词的出现情况列表。因此在倒排文档中对于单个的词汇查询来说,其查询的时间复杂度为O,其中,n为词汇表的长度。对于单个词汇的查询,该词汇的出现情况列表可以直接作为检索结果返回给用户,而对于多个词汇的査询,还需要对这些列表进行一系列相关的操作。
  在倒检索中进行上下文査询(査询串由多个单词构成,这种情况在査询过程中比较常见)相对于单词汇査询要复杂得多。首先获取查询串中每个词汇的出现情况列表,然后遍历所有这些获取的列表,看看査询串中的词汇是否在文本中顺序出现或者比较靠近。这些列表的合并和交叉运算需要花费的时间比单词汇査询长得多。

从根结点到该叶子所经历的边的所有标识串联起来后恰好拼出S的从i位置开始的后缀的图片119

  如果词汇出现情况是以块的方式来呈现的,在上下文搜索中就必须对这些块寻址方式的出现情况列表进行合并和交叉运算,对于符合条件的块所对应的文本再进行文本检索,并确定词汇出现的具体位置s
  倒排文档
  倒排文档的组成元素主要包括关键字(作者、主题词、分类号等)、目长(含有该关键字记;录的条数)、记录号集合(所有与该关键字有关的记录号)。倒排文档的建立是建筑在顺排文I档(主文档)的基础之上,它是从主文档中提取可检索字段内容,也有采取自动从标题、文摘j或全文中提取关键词,利用所得到的这些属性词来建立倒排文档。:
  倒棑文精的结构
  倒排文档可视为主文档的辅助索引,它从不同的角度提供了对主文档的快速査询,一般来说,不同属性的数据构成不同的倒排索引文档,下面给出了10篇文献(见表5.14)的作者倒排文档(见表5.15)和索引词倒排文档(见表5.16)。
  文載部分属性
  记录号篇名作者索引词
  网络安全技术的探讨A网络安全、防火墙、黑客2网络教育课程开发研究B网络、课程开发、教学设计3构建视频会议系统技术浅析C网络、视频会议、多媒体通信4网络安全在IP城域网的应用A网络安全、城域网、黑客5智能光网络在城域网中的应用B网络、城域网、IP技术6浅谈电信网络的安全A网络安全、通信、IP技术7网络存储技术的研究C网络、存储技术、网络安全8无线接人在网络融合中的应用c网络、无线网、IP技术9网格研究及其面临的问题B网格技术、网络安全10宽带光纤接人网的发展趋势A网络、宽带网、光纤。

从根结点到该叶子所经历的边的所有标识串联起来后恰好拼出S的从i位置开始的后缀的图片116

  由表5.15、表5.16可以看出,倒排文档主要有3个字段,作者或索引词字段主要为快速检索提供索引,记录号集合主要作用是为了在检索中进行集合运算和对命中结果的直接调用,目长在检索中起辅助作用。
  倒棑文格的邃立
  由顺排文档构造倒排文档需要经过抽词、排序、归并和组织等过程,具体实现步骤如下:
  选择需要做索引的字段属性(如作者、关键词等),抽出其中的内容,并在其后附上其记录号。
  对抽出的内容’进行排序,使之便于归并相同内容。
  对相同内容进行归并,把合并后的内容放人倒排文档的主键字段(如标引词、作者等),统计每一数据的频次作为目长,把每一内容后的记录号顺序放在记录号集合字段。
  在建立倒排文档的过程中还有两个问题需要注意:
  ①上述的过程是批处理的过程,在实际的数据库建设中是不断地追加数据的过程。因此,倒排文档的建立应具有及时更新的功能,所以对批处理创建倒排文档的过程需要更改。首先,从增加的记录中取出倒排索引的字段内容,然后,査询倒排索引。若命中,则将该记录的目长加1,并将增加记录的记录号追加进倒排文档的记录号集合字段。若没有命中,则将该字段内容以及记录号增加到倒排文档之中,并将目长置1。
  ②由于每一个关键字所对应的记录数相差很大,因此对于只能处理定长字段的数据库或文件系统,需建立溢出文档来解决不定长问题。
  逆波兰表达式
  逻辑提问式类似于算术表达式,对于检索而言,这种表达式并不是最优和最简洁的形1
  式,需要进行必要的转换。1929年波兰的逻辑学家卢卡西维兹提出了将运算符放在运算项后面的逻辑表达式,又称“逆波兰表达式”。这种表达式能非常方便地进行检索运算。
  逆波兰表达式又叫做后缀表达式,是一种没有括号,并严格遵循“从左到右”运算的后缀式表达方法,如表5.17所示。
  正常的表达式与逆波兰表达式对照表
  正常的表达式逆波兰表达式正常的表达式逆波兰表达式a+ba,b,+a=1+3a—1,3
  a+(b-c)a,b,c,—,+a*(b+c)+da,b,c,+,*,d,+a+(b—c)*da?d,b,c,一,*,+
  逆波兰表达式的优势在于只用两种简单操作,人桟和出栈就可以完成任何普通表达式的运算。其运算方式如下:
  如果当前字符为变量或者为数字,则压栈,如果是运算符,则将栈顶两个元素弹出作相应运算,结果再人栈,最后当表达式扫描完后,栈里的就是结果。
  将一个普通的顺序表达式转换为逆波兰表达式的一般算法是:
  首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越髙的原则。
  读人一个简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号井。

从根结点到该叶子所经历的边的所有标识串联起来后恰好拼出S的从i位置开始的后缀的图片117

  从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析S该数字串的结束并将该数字串直接输出。
  如果不是数字,该字符则是运算符,此时需比较优先关系。
  具体做法如下,将该字符与运算符桟顶的运算符的优先关系相比较。如果该字符优先关系高于此运算符栈顶的运算符,则将该运算符人栈。若不是的话,则将栈顶的运算符从栈中弹出,直到栈顶运算符的优先级低于当前运算符,将该字符人栈。
  直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,便可以将简单算术表达式转化为逆波兰表示的简单算术表达式。
  不论是算术表达式还是逻辑提问式中,运算符均有其运算优先级,这就决定了表达式转换具有一定的复杂度。在逻辑提问式中,其运算符的优先次序分别为一、*、+,另外括号内的运算优先级最髙。因此,在转换处理过程中,宁波seo优化对运算符的优先级做如下定义(见表5.18)。
  运算符的优先级
  运算符优先处理的级别运算符优先处理的级别
  *3
  +2—4
  那么计算机怎样通过后缀式来进行运算呢?这里首先假设读取分析表达式的准备工作都已经做好了,那么首先需要做的是把表达式转换成后缀式,也就是逆波兰表达式的构建过程。“构建器由两个主要组件组成,一个是目标表达式的存储器,另一个是一个符号栈。与源表达式的扫描顺序一样,存储器是从左向右存储数据的,而符号栈则遵守后进先出的原则:
  首先读人一个数据。
  如果是单目运算符,直接人符号栈。
  如果是运输量,则直接写人存储器;检査符号栈顶是否有单目运算符,有的话则全部出栈,并写人存储器。
  如果是左括号(,则直接人符号栈。
  ,则弹出符号栈数据,写人存储器,直到左括号弹出。
  如果是普通运算符,则与栈顶符号比较优先级,若大于栈顶优先级,则人栈;否则弹出栈顶符号并写人存储器,直到栈顶符号的运算优先级较小为止。
  如果是结束符(表示表达式已全部读完),则符号栈全部弹出并写人存储器,否则读取数据进人下个过程。
  此外还有一些处理的技巧,比如定义一个优先级最低的运算符作为表达式结束的标志,在符号栈里首先加入一个结束标志,那么表达式读完时则自动弹出栈中所有符号,并写人存储器结尾表示成功。
  为表达式A*B+C*(D+E)构建的过程。
  逆波兰表达式构建过程
  序号表达式目标数据堆栈说明
  a*b+c*(d+e)軲井#表示结束符
  a*b+c*(d+e)并aa写人内存
  *b+c*(d+e)#a#**>#
  b+c*(d+e)井ab并*b写入内存
  +c*(d+e)井ab*林+<*
  c*(d+e)井ab*井++〉林
  c*(d+e)并ab*c弁+C写人内存
  *(d+e)#ab*c拌+**〉十
  (d+e)井ab*c井+*左括号(送人堆栈
  d+e)材ab*cd井+*(d写人内存
  +e)井ab*cd并+*(++〉(
  e)井ab*cde并+*(+e写人内存
  #ab*cde+#+*右括号)遇左括号(弹出堆栈14井ab*cde+*+并#弹出堆找
  检索指令表的生成
  ‘逻辑提问式的逆波兰表达式不能直接用于检索,还需要将其转换成一组检索指令才能进行检索操作。转换工作是直接针对逆波兰表达式进行的,通过逐行扫描逆波兰输出表,根据其具体内容实现从逆波兰表到检索指令表的转换。
  操作指令表由4列元素组成:第一列为操作码,指定本行操作类型,如输人操作、运算操作、转储操作等;以后3列为操作数属性,根据操作码来决定3个操作数之间的关系,具体处理如下。
  若为检索词,操作码置1,第一操作数存放从逆波兰输出表中取出的检索同地址,第三操作数放置在放该检索词记录号集合的工作区代号。如表5.20表明检索词表的03号关键词的记录号集合存放在第2工作区。
  检索词操作指令表示
  操作码第一操作数第二操作数第三操作数
  
  若为运算符,操作码为3、4、5,分别代表运算符+、*、一,第一、第二操作数指定的两个工作区的记录号集合根据操作码进行相关运算,其结果送第三操作数指定的工作区。如表5.21所示第3、第4两个工作区的记录号集合进行”与“运算,其结果存放第1工作区。
  运算操作指令表示
  操作碣第一操作数第二操作数第三操作数
  
  若为结束行,将操作码置2,表示转储操作,把检索运算结果送第7工作区。因此,第一操作数放检索结果占用的工作区,将第三操作数置7,表示把检索的最终结果转移到第7工作区,参见表5.22。
  转備操作指令表示
  操作码第一操作数第二操作数第三操诈数
  
  转储操作结束,将最后一行的操作码置为0,表示终止操作,其他操作数为空,参见表5.23。
  转储操作指令表示
  操作供第一操作数第二操作教第三操作数
  
  由于计算机内存资源的有限,在检索指令表的生成过程中可设定工作区为7个,工作区的使用从前向后遇空闲即分配,从而保证了7个工作区能够满足检索过程的需要。
  检索实施
  当检索指令表生成后,就进人实际检索处理阶段,整个检索过程主要依赖检索词表和检索操作指令表,执行步骤按照检索指令表的顺序进行,具体操作如下。
  若操作码为1,应进行査找和输入操作。将该行第一操作数中数据取出,根据获得的数据来得到检索词,以该检索词去査倒排索引文档,得到的记录号集合存储到第三操作数指定的工作区中。
  若操作码为2,说明应进行转储操作。须将第一操作数指定的工作区中的记录号集合存储到第三操作数指定的工作区中。
  若操作码大于2,表示须进行逻辑运算操作,应将第一、第二操作数指定的工作区中的记录号集合,按操作码代号进行响应的逻辑运算,运算结果存放到第三操作数指定的工作区中。
  若操作码为0,则表示该逻辑提问式检索结束,须根据第7工作区的内容(命中结果)到主文档中调出命中记录,显示或打印给用户。
  爵扁鈕穎訓

从根结点到该叶子所经历的边的所有标识串联起来后恰好拼出S的从i位置开始的后缀的图片115

  后缀树和后缀数组是一种较新的建立全文索引的方法。它由某个文本的所有半无限串(起点在文本任意位置,终点在文本尾的字符串)字典排序而得,具有较高的检索效率并且更适合如范围査找、模糊査找等较复杂的查找方式。当前,在基因组分析、文本压缩、字符检索等应用领域,后缀数组都表现出了极大的潜力。
  后缀树概念
  后缀树是一种数据结构,它支持有效的字符串匹配和查询。一个具有m个词的字符串S的后缀树T,就是一个包含一个根结点的有向树,该树恰好带有m个叶子,这些叶子被赋予从1到m的标号。每一个内部结点,除了根结点以外,都至少有两个子结点,而且每条边都用S的一个非空子串来标识。出自同一结点的任意两条边的标识不会以相同的词开始。后缀树的关键特征是,对于任何叶子/,从根结点到该叶子所经历的边的所有标识串联起来后恰好拼出S的从i位置开始的后缀,即SD’,…,m]。树中结点的标识被定义为从根到该结点的所有边的标识的串联。
  后缀树原理
  一棵后缀树包含了一个或者多个字符串的所有后缀。空字符串也算其中一个后缀。对于字符串banana,其所有后缀为bananaananananaananaa空。通常为了更清楚地表示出后缀,在字符串末尾添加一个特殊字符作为结束标记,在这里使用$。因此banana的所有后缀就可以表示为banana$anana$nana$ana$na$a$$。
  banana所对应的后缀树如图5-7所示。
  Trie是一种搜索树,可用于存储并査找字符串。Trie的每一条边都对应一个字符。在Trie中査找字符串S时,只需依次枚举S的每个字符,同时从Trie的根结点开始选择相应的边往下走。如果枚举完的同时到达Trie的叶子结点,说明S存在于Trie中。如果未到达叶子结点或者枚举中途发现没有任何对应的边,说明S没有被包含在Trie中。图5-8是一个典型的Trie。
  我们可以对Trie进行压缩,对只有一个树枝的结点进行合并,如图5-9所示。后缀树就是一个压缩后的Trie,存储了字符串所有的后缀。
  査找一个字符串S是否包含了字串如果S包含那么T必定是S的某个后缀的前缀。因为S的后缀树包含了所有的后缀,因此只需对S的后缀树使用和Trie相同的查找方法即可。例如,在banana中査找an。
  统计S中出现T的次数。每出现一次T,必定对应着一个不同的后缀,而这所有的后缀又都有着共同的前缀T。因此这些后缀在S的后缀树中必定属于某一棵子树。这棵子树的叶子数便等于丁在S中出现的次数。例如,统计banana中出现an的次数,如图5-10所示。
  找出S中最长的重复子串。所谓重复子串是指出现了两次以上的子串。首先定义结点的”字符深度“=从后缀树根结点到每个结点所经过的字符串总长。找出有最大字符深度的非叶结点,则从根结点到该非叶结点所经过的字符串即为所求。例如,banana的最长重!复子串为ana,如图5-11所示。

从根结点到该叶子所经历的边的所有标识串联起来后恰好拼出S的从i位置开始的后缀的图片114

  后缀树存储

从根结点到该叶子所经历的边的所有标识串联起来后恰好拼出S的从i位置开始的后缀的图片121

  为了避免不必要的空间浪费,不要在边上存储字符串,而是存储该字符串在原串中的起止位置。空间复杂度O,如图5-12所示。
  后缀树的构造
  最简单的构造方法是:使用类似于Trie的构造方法。此时算法复杂度为O(?A2)。后缀树可以用0(?)的算法构造出来,但是它们都十分复杂。这里介绍其中一种比较常见的方法。
  基本思路是:先往树中插人最长的后缀,即字符串本身。然后插入次长的后缀,再然后插人第三长的后缀,如此反复一直到空后缀被插入为止。这个过程也可以这样描述,插人S本身;
  若上一个插人的后缀为(这里a表示S的第一个字符,w表示S去掉a以后所得到的后缀),往树中插人w。重复本操作直到S=$。
  每次插人一个后缀,会产生一个新的叶结点,同时可能产生一个新的非叶结点。如图5-13所示,可能出现的是由图5-13至图5-13、由图5-13至图5-13两种情况,但不可能出现由图5-l3至图5-13这种情况。
  本文转载自
  宁波seo优化www.leseo.net
  补充词条:宁波seo外包  宁波网络seo  宁波seo推广公司  宁波网站优化推广  宁波网站排名优化