有穷自动机【DFA】【编译原理】识别字符串的实现-编程

题目

将通过以下有穷自动机DFA的图,识别输入的字符串,并判断输入的字符串是否符合该DFA图。

请添加图片描述

分析

输入aab如何判断aab是否符合DFA图?
首先DFA图肯定是从起始位置(始态-双箭头指向的状态)-1位置开始执行,如果输入aab,首先从字符串头开始遍历,例如a符号在1位置转换为2,a(第二个a)又在2位置状态下4,b又在4状态下转换为2状态,然后字符串遍历结束。这个时候我们可以发现最终DFA的状态停在了2状态也就是终态(双圆圈的状态),所以DFA也停止,因次aab可以被DFA识别。
由上发现只要最终DFA的状态为终态,则该字符串遍能被该DFA识别,例如输入ab,不能识别最终状态为1不是终态。

特殊情况

输入的字符串中含有DFA中不存在的符号,例如输入acb,DFA中无对应的c符号,肯定不能识别。

思路

每个状态写一个子程序,相互调用
上代码
package BianYi;
/*
 * DFA
 * 本方法只适应该DFA图
 * I  Ia Ib  
 * 1  2   3  0
 * 2  4   1  1
 * 3  1   5  0
 * 4  4   2  0
 * 5  2   3  1
 * */
import java.util.Scanner;

public class Demo_02 {
	public static  int count=0;//全局计数器 用于遍历输入的字符串
	public static boolean flag=false;//记录输入的字符串是否能被DFA识别,默认为false 全局变量
	public static void main(String[] args) {	
	  
		Scanner  input=new Scanner(System.in);
		System.out.print("请输入一串字符串:");
		String str=input.next();//接收该字符串
		//先排除简单的情况 即输入的字符串中存在某个字符在DFA符号中无对应 例如输入aac c无对应(符号为a b)
		for(int i=0;i<str.length();i++) {//遍历输入的字符串 一一对比
			if(str.charAt(i)!='a'&&str.charAt(i)!='b') {//遍历的字符在DFA中无对应
				System.out.println("字符串:"+str+"不能被当前的DFA识别!");
				System.exit(0);//终止程序
			}
		}
		
		//遍历输入的字符串
		
			fun_01(str.charAt(count),str);
			if(flag) {
				System.out.print("字符串:"+str+"能被当前的DFA识别!");
			}else {
				System.out.println("字符串:"+str+"不能被当前的DFA识别!");
			}

		
	}
	public static boolean funCtion(String str,int t) {
		
		if((t==5||t==2)&&count==str.length()) {//如果此时count的值等于字符串的长度-即已经遍历到了最后一个字符了
			flag=true;//因为此处会调用fun_02或fun_05,而且fun_02或fun_05为终态,并且已经是遍历的最后一个字符 所以该字符串能被DFA识别
			return true;//让程序不再往下执行,不然会造成str.charAt(count)下标越界	
		}
		if((t==1||t==3||t==4)&&count==str.length()){
			flag=false;//因为此处会调用fun_03||04||01,而且都不为终态,并且已经是遍历的最后一个字符 所以该字符串不能被DFA识别
			return true;//让程序不再往下执行,不然会造成str.charAt(count)下标越界
		}
		return false;	
	}
	public static void fun_01(char ch,String str) {//DFA中的1状态
		if(ch=='a') {
			count++;
			if(funCtion(str,2)) {
				return;
			}
			
			fun_02(str.charAt(count),str);
		}else {//ch=='b'
			count++;
			if(funCtion(str,3)) {
				return;
			}
			
			fun_03(str.charAt(count),str);
		}
	}
	public static void fun_02(char ch,String str) {//DFA中的2状态-终态
		
		if(ch=='a') {
			count++;


			if(funCtion(str,4)) {
				return;
			}
			fun_04(str.charAt(count),str);
		}else {//ch=='b'
			count++;

			if(funCtion(str,1)) {
				return;
			}
			fun_01(str.charAt(count),str);
		}
	}
	public static void fun_03(char ch,String str) {//DFA中的3状态
		if(ch=='a') {
			count++;

			if(funCtion(str,1)) {
				return;
			}
			fun_01(str.charAt(count),str);
		}else {//ch=='b'
			count++;

			if(funCtion(str,5)) {
				return;
			}
			fun_05(str.charAt(count),str);
		}
	}
	public static void fun_04(char ch,String str) {//DFA中的4状态
		if(ch=='a') {
			count++;

			if(funCtion(str,4)) {
				return;
			}
			fun_04(str.charAt(count),str);
		}else {//ch=='b'
			count++;

			if(funCtion(str,2)) {
				return;
			}
			fun_02(str.charAt(count),str);
		}
	}
	public static void fun_05(char ch,String str) {//DFA中的5状态-终态
		if(ch=='a') {
			count++;

			if(funCtion(str,2)) {
				return;
			}
			fun_02(str.charAt(count),str);
		}else {//ch=='b'
			count++;

			if(funCtion(str,3)) {
				return;
			}
			fun_03(str.charAt(count),str);
		}
		
	}
}


矩阵法-二维数组

开辟一个二维数组存在每个状态经过输入的符号转后后的状态
其中行为状态的个数,列为DFA中的符号个数+1,最后一列存储当前的状态是否为终态-01标记 1-为终态。
为了能使程序通用其他DFA图,将DFA状态之间的相关关系写入了文本中
文本存储规则:状态标识用阿拉伯数字表示,符号用字母表示
请添加图片描述

文本存储代码

package BianYi;
import java.io.BufferedReader;
import java.io.File;//导入包
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
//读取文本中的信息
public class FileText {
	public static int hang;//二维数组的行数
	public static int lie;//二维数组的列数
	private static int  i=1;//目的是标记文本中的第一行,因为第一行只有2个数字,其他行有三个数字,且均以空格分离
	private static String path="C:\\Users\\wsg\\Desktop\\编译原理.txt";//定义文本的名称,
	private static File file;//定义一个File(File读取文件的流)的变量名
	static {//static 为静态代码块 程序运行只执行一次
	       file = new File(path);
	        if(!file.exists()){
	            try {//捕获创建、读取文件时可能发生的异常
	                file.createNewFile();//文件如果不存在会创建如果存在不会创建

	            } catch (IOException e) {
	                e.printStackTrace();
	            }
	        }
	}
	
	public  static int[][] fun(int[][]  array) {
		 try {
	            array=readDataFromFile4(file,array);      
	        } catch (IOException e) {
	            e.printStackTrace();
	        }
	        //返回权限
		return array;
	}
	   private static int[][]  readDataFromFile4(File file,int[][] array) throws IOException {//声明为staic可用类名访问 throws表示该方法可能抛出IOException异常
	        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));//缓冲流-读取
	        String str = "";//局部变量需要先赋值后引用
	       
	        int  count=0;//数组行数的统计
	        while((str = reader.readLine())!=null){//如果没有读取到最后一行
	            String[] stuInfo= str.split("\\s+");//按照空格正则分割,全部读取
	            if(i==3) {
	            	Demo_01.chArry=stuInfo;
	            }
	             if(i==1) {//第一行存取的是行数和列数
	            	 hang=Integer.valueOf(stuInfo[1]).intValue();//将读取的行数转换为整数类型
	            	 lie=Integer.valueOf(stuInfo[3]).intValue(); 
	            	 //堆区开辟数组空间
	            		array=new int[FileText.hang][FileText.lie+1];//声明一个二维数组,行数和列数从文本中读取  其中行为状态的个数,列为输入的符号个数和初始态0 1	                		
	             }
	             if(i>3){//当读取的行数大于三时,此时读取的便是状态之间的转换关系,将其存储在二维数组中 
	            	 array[count][0]=Integer.valueOf(stuInfo[0]).intValue();//存储某个状态经过输入某个字符转换后的状态
	            	 array[count][1]=Integer.valueOf(stuInfo[1]).intValue();//存储某个状态经过输入另一个字符转后的状态
	            	 array[count][2]=Integer.valueOf(stuInfo[2]).intValue();//存储此时状态是否为初始态 0 1
	              
	            	 count++;
	             }
	            i++;
	           
	            
	        }
	        return array;//将新开辟的数组空间返回 便于调用 不返回会造成访问数组为null-即只能在该方法中访问该数组
	   }
}


矩阵代码

package BianYi;

import java.util.Scanner;
/*
 * 文本中的存储规则:
 * 如果DFA的输入字符在图中为数字 则用字母a b c...代替
 * 如果DFA的状态在图中为字母,则用数字 1 2 3....代替
 * */
//有穷自动机DFA程序
public class Demo_01 {
	public static String[] chArry;//将有DFA的输入符号存储在chArry中 例如 a b
	public static void main(String[] args) {	
		Scanner input=new Scanner(System.in);//输入语句
		int[][] array = null;//首先定义一个二维数组,赋值为空 ,在读取的文件类FileText中赋值
		array=FileText.fun(array);//传递数组名称,分配空间,并且读取文本中的内容(各状态转换之间的关系)	
		System.out.print("I  ");
		for(String st:chArry) {//将DFA中的输入字符打印出来 例如 a b
			System.out.print("I"+st+" ");//空格分割
		}
		System.out.println();//换行
		for(int i=0;i<FileText.hang;i++) {//将二维表中的状态关系全部打印出来 最后一列存储的是该状态是否终态0-1
			System.out.print((i+1)+"  ");
			for(int j=0;j<FileText.lie+1;j++) {
				System.out.print(array[i][j]+"  ");//以空格隔开
			}
			System.out.println();//换行
		}
		System.out.print("请输入一串字符串:");
		String str=input.next();//输入用户需要识别的字符串		
		if(funCtion(str,array)) {//调用funCtion函数,传递用户输入的字符串以及存储各状态转换关系的二维数组,识别成功返回ture
			System.out.print("字符串:"+str+"可以被该有穷自动机识别");
		}else {
			System.out.print("字符串:"+str+"不可以被该有穷自动机识别");
		}
	}

	public static boolean funCtion(String str,int[][] array) {//如果识别成功 返回true 否则返回false
		char[] strArray=str.toCharArray();//将要用户输入的字符串转换为char[]类型,便于一个一个比较与转换
		boolean  flag=false;//记录用户输入的字符串与DFA中的字符号是否一模一样,默认不一样
		//第一种情况 输入的字符在DFA中找不到该字符 例如 DFA中的符号是a b 用户输入的是abc c不存在
		String s;//char[]类型和String[]类型无法比较,需要转换,s存储strArray[i]
		for(int i=0;i<strArray.length;i++) {//遍历用户输入的字符串
			flag=false;//用户输入的字符串中每一个字符都默认为在DFA符号中无对应
			s=String.valueOf(strArray[i]);//将字符char类型转换为string类型便于比较
			for(int j=0;j<chArry.length;j++) {//遍历DFA中的字符号
				if(s.equals(chArry[j])) {//如果用户输入的字符串中的每一个字符在DFA中有相应的字符号对应,改变flag的状态
					flag=true;//如果用户输入的字符串的每个字符在DFA中都有符号对应,则flag一直为true
					break;//只要当前的该单个字符在DFA中有对应的字符号就不需要再遍历当前查找了,退出内层循环
				}
			}		
			if(!flag) {//表明用户输入的字符串的字符存在与DFA中的字符号不一致;则该字符串肯定不能被该机器识别 则不需要再查找,直接返回false
				return false;
			}
		}
		int num=1;//如果输入的是aab a在某一列 则num存储某一列的DFA转换状态
		for(int i=0;i<strArray.length;i++) {//遍历用户输入的字符串
			int n=-1;//记录当前遍历的字符在二维表中对应的列数(根据DFA中的符号判断)
			s=String.valueOf(strArray[i]);//将字符char类型转换为string类型便于比较
			for(int j=0;j<chArry.length;j++) {//遍历DFA中的符号
				if(s.equals(chArry[j])) {//如果当前遍历的字符与当前遍历的DFA中的符号相等
					n=j;//将s在二维表中的列数赋予n
					num=array[num-1][j];//将要这列中的
					break;
				}
			}
			if(i==strArray.length-1&&array[num-1][2]==1) {//已经扫描完最后一个字符,并且当前该字符所在的状态为1 则说名该字符符合该有穷自动机
				return true;
			}
			
			//System.out.println(n);
		}
		
		
	
		return  false;
	}
}

结果

请添加图片描述
请添加图片描述
请添加图片描述
注:此程序对于一些DFA图可能识别不了,例如某个状态转换为其他状态只有一种输入符号,那么DFA中的其他符号在二维数组中的存储值应该为空(可置为0,增加判断即可)。
如下图,如果输入abca字符串则结果为识别不成功,因为第输入a转换为2状态后,2状态没有与b字符有关的操作。
请添加图片描述

  • 5
    点赞
  • 73
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值