题目概述
编写上下文无关文法的变换算法,用于消除文法中的空产生式、单产生式以及无用符号
算法解析
-
消除空产生式
空产生式的消除采用的方法是找到直接置空和间接置空的生成式,例如:
S -> bA1 | A2 | A1
A1 -> null | a
那么A1为直接置空元素,S通过生成A1再置空那么为间接置空元素;
通过遍历我们可以将直接置空和间接置空元素放入一个集合,下一步是替换元素,将替换情况用组合算出来再加入原生成式集合;
bA1元素有两种组合方式,分别为b和bA1,所以替换为b | bA1, A1元素替换为A1 | null:
S-> b | bA1 | A2 | A1 | null
A1 -> a | null
再次遍历消去null;
S-> bA1 | A2 | A1 | b
A1 -> a
如果起始符置空则需要引入S1,所以可以得到:
S1 -> null | S
S-> bA1 | A2 | A1 | b
A1 -> a -
消去单产生式
单产生式的消除采用的方法是先找到单元素,例如:
S -> A | aB
A -> c | a
B -> ab
可以得到S - > A,A为单元素,把A集合中的元素和S集合做并集,可以得到S -> A | aB | c | a;重复操作,直至所有含单元素的生成式都经过并集;
之后删去每个生成式的单元素即可;
S -> aB
A -> c | a
B -> ab -
消去无用符号
无用符号包括两部分,一部分是不可达符号,另一部分是非产生符号;
产生符号指的是起始符生成式包含的非终止符,例如:
S->Ab | B
则A与B为产生符;
可达符号指的是生成式中含有只含终结符的生成串,例如:
S -> ab | A | C
ab是只含终结符的串,所以S是可达符号;
因此我们将无用符号通过条件遍历出来删除就可,记得含有无用符号的串都需要删除;
数据结构
这里我采用了JAVA中的hashmap进行生成式的存储,例如:
S -> Ab | B
A -> a | Bb
B -> b | aA
hashmap中的key是一个集合,存储生成式左端,则有key = {S,A,B},
hashmap中的value用 List< List < String > >来填充,例如:
外层List中含有生成式的右端,里层的List为单个元素组成的集合,一个 List< List < String > >具体表示为:
[[A,b],[B]]
一些小提醒
这个算法流程有大量的JAVA集合操作,因为数据结构的关系,遍历到每个单元素基本需要三层for循环,复杂度较高,而且由于需要边遍历边进行集合操作,元素的位置会改变会导致for循环失效报错,需要另辟蹊径,总得来说用JAVA写该程序需要耐心和细心。
代码网址
网络上大多公开的算法程序都是用python写的,python集合操作相当简单。
创作不易,我将JAVA版本开源,希望大家点赞支持一下博主的头发(hhh)。
https://gitcode.net/flag_wkx/experiment