DFA极小化算法,矩阵扫描实现,编译原理
极小化算法
看了一下网上的方法基本上是使用“集合的分割”实现的极小化,刚好我们老师使用的是矩阵扫描,因此自己干脆使用java来实现。我直接封装了一个dfa的类,目前只写了“矩阵扫描”的极小化,有时间的话自己也会把“集合分割”的算法加上。下面就拿网上找到的例子做一个使用矩阵扫描的基本步骤。
矩阵扫描
关键步骤:
- 去除无用状态
- 合并等价状态
例子:

第一步:
画一个矩阵,可以是下面这样的。因为(A,C)和(C,A)一样,也就是说这是一个对角阵,所以只需要使用下三角(上三角)即可:

第二步
去除对角线,以-1作为去除的标记

第三步
终态和非终态是不能合并的,因此需要把终态和非终态去掉。由DFA知道,非终态集为{A,B,C,D},终态集为{E},在下三角中把(E,A),(E,B),(E,C),(E,D)去掉。这一步我使用1做为标记,因为在java里面Int型默认为0,所以这样做可以避免初始化的时候赋值。
注意:在程序中除了对角线使用-1,其余我都使用1和0作为标记,1表示不可合并,0为可合并。
下面是去掉后的结果:

第四步
开始做下三角的扫描,只需要扫描空白(程序中标记为0)的地方即可,当然在程序中循环扫描的时候,还是需要遍历下三角的。
第一遍:
- B,A
f(B,a) = B f(A,a) = B (解释:这既是跳转函数,B输入a跳到B状态,A输入a也跳转到B状态。因为B和B是同一个状态,所以保留B,A)
f(B,b) = D f(A,b) = C (D,C状态未知,保留) - C,A
f(C,a) = B f(A,a) = B
f(C,b) = C f(A,b) = C - C,B
f(C,a) = B f(B,a) = B
f(C,b) = C f(B,b) = D - D,A
f(D,a) = B f(A,a) = B
f(D,b) = E f(A,b) = C (解释:(E,C)已经被标记上1,所以(D,A)也要被标记为1) - D,B
f(D,a) = B f(B,a) = B
f(D,b) = E f(B,b) = D (同(D,A)) - D,C
f(D,a) = B f(C,a) = B
f(D,b) = E f(C,b) = C
第一遍扫描后的结果如下:

注意:因为在上一次的基础上,下三角的状态已经发生了变化,所以需要进行第二次扫描。如果第二次又发生变化,那么就需要第三次扫描。直至状态不在改变,这时候就是最小化的最终结果。
第二遍: - B,A
f(B,a) = B f(A,a) = B
f(B,b) = D f(A,b) = C (因为(D,C) == 1,所以(B,A) = 1) - C,A
f(C,a) = B f(A,a) = B
f(C,b) = C f(A,b) = C - C,B
f(C,a) = B f(B,a) = B
f(C,b) = C f(B,b) = D
本次扫描结果:

下三角状态发生改变,进行第三遍扫描:
第三遍:
- C,A
f(C,a) = B f(A,a) = B
f(C,b) = C f(A,b) = C
这一遍后,下三角的状态没有发生改变,不需要在进行第四遍扫描。这说明扫描已经结束了,而最终结果便是上一次扫描的结果:

从图中可以看出,(C,A)处留空,说明A,C是可合并的状态,其他状态不可以合并
**结果:**可合并的状态为{A,C}
需要说明的是,扫描的步骤中,我每一步的跳转都写出来了,这只是为了更好的理解和阐述,同时说明了在程序中实现的过程。但是在实际的手动扫描时,很多重复的步骤是可以省略的。
JAVA程序实现的例子
因为把dfa封装成了类,所以在get和set方法上花了很大的篇幅。因此下面只粘出“矩阵扫描”的方法。源代码的下载链接,博文最后有附上。
/**
* 采用矩阵扫描法
* @return 成功:下三角矩阵,失败:null
*/
public int[][] matrixScan() {
//定义一个下三角矩阵,存储结果
//可合并为0
//否则为1
int[][] matrix = new int[getSSet().size()][];
for (int i = 0; i < matrix.length; i++) {
matrix[i] = new int[i + 1];
//去掉对角线
matrix[i][i] = 1;
}
//去掉终态
for (int i = 1; i < matrix.length; i++) {
// 判断i是否是终态
if (!isSSetItem(i)) {
for (int j = 0; j < i; j++) {
//判断j是否是终态
//不是终态则matrix[i][j] = 1;
if (isSSetItem(j))
matrix[i][j] = 1;
}
}else{
for (int j = 0;j < i;j++){
if (!isSSetItem(j))
matrix[i][j] = 1;
}
}
}
// 最后的扫描
// 局部内部类
class ScanMatrix {
void scan() {
// 记录扫描状态
boolean status = true;
while (status) {
status = false;
for (int i = 1; i < getSSet().size(); i++) {
for (int j = 0; j < i; j++) {
//判断是否已经为1
if (matrix[i][j] == 0) {
for (int ci = 0; ci < getCSet().size(); ci++) {
int max = getFunItem(i, ci);
int min = getFunItem(j, ci);
if (max < min) {
int temp = max;
max = min;
min = temp;
}
// 注意max和min不应该相等
// 既不能是对角线上的1
if (matrix[max][min] == 1 && max != min) {
matrix[i][j] = 1;
status = true;
break;
}
}
}
}
}
}
}
}
new ScanMatrix().scan();
return matrix;
}
程序运行例子得到的结果
测试数据:
A:0,B:0,C:0,D:0,E:1
a,b
B,C,B,D,B,C,B,E,B,C
结果:

源代码下载:
点击跳转
运行结果肯定是和分析的结果一样,但是在编写的时候难免会有疏漏的地方,敬请指正!

浙公网安备 33010602011771号