本篇文章主要介绍了如何使用 Java 来模拟 XN*2 图灵机,下面是具体的实现过程,供大家参考,希望对大家的学习和工作能够有所帮助!
题目描述:
对于XN*2图灵机进行模拟,任意给定的十进制数,转换为收缩扩展二进制的编码,再编程模拟此Turing机的运行过程,要求输出从开始运行起的每一步骤的结果。用C或C++或Java或Python语言实现程序解决问题。
要求:1. 程序风格良好(使用自定义注释模板);
2. 提供友好的输入输出,并进行输入数据的正确性验证。
算法分析:
1. 将十进制数转换为二进制数;
2. 将二进制数转换为收缩扩展二进制的编码;
3. 根据当前的内态和输入执行XN*2图灵机的指令;
4. 将结果的二进制编码转换为二进制数;
5. 将二进制数转换为十进制数,实现乘2运算功能。
概要设计:
算法流程图如下:
测试:
输入的十进制数 |
正确的二进制编码 |
输出的二进制编码 |
正确的运算结果 |
输出的运算结果 |
0 |
0011000 |
0011000 |
0 |
0 |
3 |
0101011000 |
0101011000 |
6 |
6 |
18 |
0100010011000 |
0100010011000 |
36 |
36 |
运行结果:
调试:
①对调用指令的方法进行调试,开始时binCodeList的size为0,导致执行binCodeList.set(i, “0”)时出现错误,进过调试后发现是因为没给方法设置binCodeList的参数,导致方法中用的是类中空的binCodeList。在方法的参数中加上List<String> binCodeList就可以解决。
②对将二进制编码转换为十进制数的方法进行调试,开始时运算结果出现错误,调试后发现是判断第i个字符为1,第i+1个字符为0后,没有将i再加1,导致下次循环又遍历到i+1的0,于是有些步骤结果就会多出0。在if (binCode.charAt(i + 1) == '0'){…}代码块中加上i++就可以解决。
源代码:
import java.util.*; /** * @description: 该类模拟XN*2图灵机,对任意给定的十进制数,转换为收缩扩展二进制的编码,并可输出运行中每一步骤的结果 */ public class TuringMachine { private int internalState; // 图灵机的内态 private String binCode; // 二进制编码 Function f = new Function(); // 需要用到的方法 List<String> binCodeList = new ArrayList<>(); // 用来存放二进制编码 static int r = 0; // 当r为1时机器向右移动一格 static int s = 0; // 当s为1时机器停止运行 TuringMachine() { internalState = 0; binCode = "0"; } public int getInternalState() { return internalState; } public void setInternalState(int internalState) { this.internalState = internalState; } public String getBinCode() { return binCode; } public void setBinCode(String binCode) { this.binCode = binCode; } /** * @description: 模拟图灵机的运行过程 * @param: [binCode 二进制编码] * @return: void */ public void runProcess(String binCode) { binCodeList = f.toArrayList(binCode); // 将二进制码binCode转换为ArrayList类型存放在binCodeList中 // for循环对binCodeList进行遍历,根据当前内态的值判断该执行哪条指令 for (int i = 0; i < binCodeList.size(); i++) { r = 1; // 当s==1时机器停止,跳出循环 if (s == 1) { break; } switch (getInternalState()) { // 内态为0时执行指令1 case 0: instruction_1(binCodeList.get(i), i, binCodeList); break; // 内态为1时执行指令2 case 1: instruction_2(binCodeList.get(i), i, binCodeList); break; // 内态为10时执行指令3 case 10: instruction_3(binCodeList.get(i), i, binCodeList); break; // 内态为11时执行指令4 case 11: instruction_4(binCodeList.get(i), i, binCodeList); break; default: break; } } System.out.println("XN*2图灵机计算的最终结果为:"); f.toDecNum(f.toString(binCodeList)); // 将binCodeList转换为String类型的二进制编码binCode,再转换为int类型的十进制数decNum } /** * @description: 根据指令对每一步骤结果进行打印 * 指令1: 0 0 -> 0 0 R * 0 1 -> 1 0 R * 指令2: 1 0 -> 0 1 R * 1 1 -> 10 0 R * 指令3: 10 0 -> 11 1 R * 指令4: 11 0 -> 0 1 STOP * @param: [input 输入, i 循环的次数从0开始, binCodeList 存放二进制编码binCode] * @return: void */ private void instruction_1(String input, int i, List<String> binCodeList) { System.out.println("当前的内态为:" + getInternalState() + ",输入为:" + input); if (input.equals("0")) { System.out.println("执行此条指令后的内态为:" + getInternalState() + ",输入为:" + binCodeList.get(i) + ",右移"); System.out.println("此步骤的结果为:"); System.out.println(f.toString(binCodeList)); } if (input.equals("1")) { setInternalState(1); binCodeList.set(i, "0"); System.out.println("执行此条指令后的内态为:" + getInternalState() + ",输入为:" + binCodeList.get(i) + ",右移"); System.out.println("此步骤的结果为:"); System.out.println(f.toString(binCodeList)); } System.out.println(); } private void instruction_2(String input, int i, List<String> binCodeList) { System.out.println("当前的内态为:" + getInternalState() + ",输入为:" + input); if (input.equals("0")) { setInternalState(0); binCodeList.set(i, "1"); System.out.println("执行此条指令后的内态为:" + getInternalState() + ",输入为:" + binCodeList.get(i) + ",右移"); System.out.println("此步骤的结果为:"); System.out.println(f.toString(binCodeList)); } if (input.equals("1")) { setInternalState(10); binCodeList.set(i, "0"); System.out.println("执行此条指令后的内态为:" + getInternalState() + ",输入为:" + binCodeList.get(i) + ",右移"); System.out.println("此步骤的结果为:"); System.out.println(f.toString(binCodeList)); } System.out.println(); } private void instruction_3(String input, int i, List<String> binCodeList) { System.out.println("当前的内态为:" + getInternalState() + ",输入为:" + input); if (input.equals("0")) { setInternalState(11); binCodeList.set(i, "1"); System.out.println("执行此条指令后的内态为:" + getInternalState() + ",输入为:" + binCodeList.get(i) + ",右移"); System.out.println("此步骤的结果为:"); System.out.println(f.toString(binCodeList)); } System.out.println(); } private void instruction_4(String input, int i, List<String> binCodeList) { System.out.println("当前的内态为:" + getInternalState() + ",输入为:" + input); if (input.equals("0")) { setInternalState(0); binCodeList.set(i, "1"); System.out.println("执行此条指令后的内态为:" + getInternalState() + ",输入为:" + binCodeList.get(i) + ",STOP"); System.out.println("此步骤的结果为:"); System.out.println(f.toString(binCodeList)); } s = 1; System.out.println(); } public static void main(String[] args) { TuringMachine tm = new TuringMachine(); // 创建TuringMachine的实例tm System.out.println("请输入一个十进制数:"); Scanner scanner = new Scanner(System.in); try { int decNum = scanner.nextInt(); tm.setBinCode(tm.f.toBinCode(decNum)); // 将十进制数转换为二进制编码并赋值给binCode System.out.println(); tm.runProcess(tm.getBinCode()); // 运行图灵机 } catch (InputMismatchException ex) { System.out.println("输入有误!"); } } } /** * @description: 该类具有图灵机TuringMachine运行过程中所需要的一些方法 */ class Function { /** * @description: 将十进制数转换为二进制编码 * @param: [decNum 十进制数] * @return: java.lang.String */ public String toBinCode(int decNum) { String binCode = ""; String binNum = Integer.toBinaryString(decNum); // 十进制数转换为二进制数 binNum += ","; // 用,标识此二进制数到此已完整,后面的0都忽略不计 System.out.println("这个数的二进制表示为:" + binNum); // 利用for循环对二进制数binNum中的字符进行遍历,根据其中的每个字符得出二进制编码binCode for (int i = 0; i < binNum.length(); i++) { // 0 -> 0 if (binNum.charAt(i) == '0') { binCode += "0"; // 1 -> 10 } else if (binNum.charAt(i) == '1') { binCode += "10"; // , -> 110 } else if (binNum.charAt(i) == ',') { binCode += "110"; } } binCode = "0" + binCode + "00"; System.out.println("这个数的二进制编码为:" + binCode); return binCode; } /** * @description: 将二进制编码转换为十进制数 * @param: [binCode 二进制编码] * @return: int */ public int toDecNum(String binCode) { int decNum = 0; String binNum = ""; // 先利用for循环对ArrayList类型的binCode进行遍历,根据其中的每个元素得出二进制编码binCode for (int i = 0; i < binCode.length(); i++) { // 0 -> 0 if (binCode.charAt(i) == '0') { binNum += "0"; } else if (binCode.charAt(i) == '1') { // 10 -> 1 if (binCode.charAt(i + 1) == '0') { binNum += "1"; i++; // 110 -> , } else if (binCode.charAt(i + 1) == '1') { binNum += ","; break; } } } System.out.println("二进制表示:" + binNum); decNum = Integer.parseInt(binNum.substring(0, binNum.length() - 1), 2); // 将二进制编码binCode转化为十进制数 System.out.println("十进制表示:" + decNum); return decNum; } /** * @description: 将二进制编码binCode存放到binCodeList中 * @param: [binCode 二进制编码] * @return: java.util.List<java.lang.String> */ public List<String> toArrayList(String binCode) { binCode = binCode.replaceAll("", " ").trim(); // 将binCode中的每个字符用空格分隔开,并去掉首尾的空格 // 根据分隔符空格分隔出binCode中的每个字符存放到binCodeList中 List<String> binCodeList = new ArrayList<>(Arrays.asList(binCode.split(" "))); return binCodeList; } /** * @description: 将binCodeList转换为二进制编码binCode * @param: [binCodeList 存放binCode的容器] * @return: java.lang.String */ public String toString(List<String> binCodeList) { String binCode = String.join("", binCodeList); return binCode; } }
总结
本次测试是模拟图灵机对十进制数进行乘2运算,并输出每一步骤的结果。
本次测试的关键问题在于图灵机运行过程和算法的理解,图灵机判断当前内态和输入后执行指令,在这里我才用switch语句根据内态的值判断执行哪个指令方法,再根据输入判断具体执行什么指令,通过for循环模拟右移操作。
到此这篇关于如何用Java模拟XN*2图灵机的文章就介绍到这了,想要了解更多相关Java内容,请搜索W3Cschool以前的文章或继续浏览下面的相关文章,希望大家以后多多支持!