图灵机引言
图灵机是一种思想模型,是关于数据、指令、程序以及程序/指令自动执行的基本思想。按照计算规则(程序)对输入进行变换得到输出。输入/输出都是0和1 形式的表达,程序和指令也是0和1 的形式表达。
图灵机(XN×2)的运算指令(第一列为内态,第二列为读入字符,第三列为改变后指令运行后的内态,第四列为执行指令后读出的字符):
- 0 0 → 0 0 R
- 0 1 → 1 0 R
- 1 0 → 0 1 R
- 1 1 → 10 0 R
- 10 0 → 11 1 R
- 10 1 → 0 0 R
- 11 0 → 0 1 STOP
- 11 1 → 0 0 R
图灵机运行原理
其运算的原理大致为:
- 获得一个整数,转为二进制
- 再转为二进位编码(如数字3,其二进制为11,二进位编码为01001011)
- 再利用上述指令对“输入字符”进行读写,输出一个“输出字符串”
PS:扩展二进位编码,11表示逗号
设计思路
- 大体思路就是图灵机的运行原理。先从键盘获取一个整数,将输入数值转换为二进制,输出转换后的二进制。将二进制转换为二进位扩展编码并输出转换后的二进位扩展编码,将扩展编码字符串变量转为字符数组,通过if-else嵌套语句根据内态和读入的字符完成读写,输出每轮运行的字符串,最后输出最终的结果。
- 在设计十进制转为二进制的函数功能上,直接调用**Integer.toBinaryStr-ing()**函数可直接求得;
- 将二进制转为二进位数值编码,是本次实践的一个难点。先定义2个字符串,一个字符串储存转换后的二进制字符串,另一个字符串储存字符全为0的字符串(且这个全为0字符串的体积是源字符串体积的三倍,这是为了防止转为二进位扩展编码,字符串体积不够)。
- 这个功能采用对两个栈的操作来实现,第一个栈stack1存取二进制字符数组,第二个栈stack2存储所有字符全为0的字符数组。利用stack1的指针top读取arr数组的每一位字符元素。如果读取的字符为1,则往栈stack2中依次添加0、1、0字符;如果读取的字符为0,则往栈stack2中添加字符0。当栈stack1的指针top到达栈顶便停止,输出结果即为stack2存储的字符数组。
- 模拟图灵机的指令运行原理,利用if-else嵌套语句,对内态和读入的字符的八种情况进行判断,当执行到内态为内态为1 0,读入字符为1便停止。
流程图
源码实现
package com.Turin;
/**
* 定义一个栈,存储二进制字符
* @author 万物甦醒
* 编辑时间:2019年3月20日
*/
public class charStack1 {
public int volume;//定义数组的体积
public int top;
char[] elem=new char[volume];//定义字符数组
public charStack1(int volume, int top, char[] elem)
{
this.volume = volume;
this.top = top;
this.elem = elem;
}
}
package com.Turin;
/**
* 定义一个栈,里面字符全为1
* @author 万物甦醒
*编辑时间:2019年3月20日
*/
public class charStack2 {
public int volume;//定义数组的体积
public int top;
char[] elem=new char[volume];//定义字符数组
public charStack2(int volume, int top, char[] elem) {
this.volume = volume;
this.top = top;
this.elem = elem;
}
}
package com.Turin;
/**java
* 定义一个Transfer类用于实现一些数制转换的基本功能
* 主要来实现以下两个功能:
* 1.十进制转为二进制
* 2.将二进制转为二进位数值编码
* 2.1 2个字符串,一个字符串储存转换后的二进制字符串,另一个字符串储存字符全为0的字符串
* (且这个全为0字符串的体积是源字符串体积的三倍)
* 2.2 二进位数值编码采用对两个栈的操作来实现,第一个栈为二进制字符串,第二个栈字符全为0
*
* @author 万物甦醒
* 第1次编辑时间:2019年3月19日
* 第2次编辑时间:2019年3月20日
*/
public class Transfer {
String binaryConversion(int number) //十进制转为二进制
{
return Integer.toBinaryString(number);//将十进制转为二进制
}
String codingConversion(String arr)//将二进制转换为二进位编码
{
String arrs=expandStringSize(arr); //给字符串2倍扩容 ,在其基础上后被多添2倍的0
char[] ar1=arr.toCharArray();//将原字符串变量转为字符数组
char[] ar2=arrs.toCharArray();//将字符串变量转为字符数组,全为0
//定义两个栈,一个栈存源字符,另一个栈为字符全为0,且数组体积是原来的3倍,
charStack1 stack1=new charStack1(arr.length()+2,0,ar1);
charStack2 stack2=new charStack2(arrs.length()+2,0,ar2);
while(stack1.top<arr.length()) //栈指针到栈顶前
{
if(stack1.elem[stack1.top]=='1') //如果读取到字符为1
{
//往栈2中依次添加0、1、0;
stack2.elem[stack2.top]='0';
stack2.elem[++stack2.top]='1';
stack2.elem[++stack2.top]='0';
}
else if(stack1.elem[stack1.top]=='0')//如果读取到的字符为0
{
//往栈2中添加1个零
stack2.elem[++stack2.top]='0';
}
stack1.top++;//栈指针上移
}
stack2.elem[++stack2.top]='1';
stack2.elem[++stack2.top]='1';
String arra=String.valueOf(stack2.elem);//再将字符数组转为字符串
return arra;
}
public String expandStringSize(String arr)//扩容3倍字符串体积
{
String arrs=arr; //获取原先的字符串
char[] status = arrs.toCharArray(); //字符串转为字符数组
for(int m=0;m<arr.length();m++) //字符数组每位初始化为0
status[m]='0';
String status1=String.valueOf(status);//再将字符数组转为字符串
if(arr.length()<3)
{
return status1+status1+status1+status1+status1+status1;
}
else
{
return status1+status1+status1;
}//返回字符串
}
}
package com.Turin;
import java.util.Scanner;
/**
* 仿制图灵机原理(XN×2)由扩展的二进位依据指令输出
* 思路: 1.用户随机输入符合条件的二进位扩展编码
* 2.字符串类型arr保存输入编码,转为字符数组
* 3.根据内态和读入字符按照运算指定模仿图灵机工作
* @author 万物甦醒
* 第1次编辑时间:2019年3月19日
* 第2次编辑时间:2019年3月20日
*/
public class Turin {
public static void main(String[] args)
{
Transfer tran=new Transfer();//定义转化编码的自定义对象
Scanner scan=new Scanner(System.in);
System.out.println("请输入一个十进制整数");
int number=scan.nextInt();//键盘上获取一个整数
scan.close();
//将输入数值转换为二进制,输出转换后的二进制
System.out.println("数值转换成二进制为:"+tran.binaryConversion(number));
//将二进制转换为二进位扩展编码,输出转换后的二进位扩展编码
String arr=tran.codingConversion(tran.binaryConversion(number));
System.out.println("转换后的二进位扩展编码为:"+arr);
//将扩展编码字符串变量转为字符数组
char[] ar=arr.toCharArray();
int flag=0; //定义一个变量记录内态
/**
* 图灵机(XN×2)的运算指令
* 0 0 → 0 0 R
* 0 1 → 1 0 R
* 1 0 → 0 1 R
* 1 1 → 10 0 R
* 10 0 → 11 1 R
* 10 1 → 0 0 R
* 11 0 → 0 1 STOP
* 11 1 → 0 0 R
*/
for(int i=0;i<arr.length();i++) //根据内态值和读入字符值按指令输出
{
if(ar[i]==' ')
break;
if(ar[i]=='0'&flag==0)
{
flag=0;
ar[i]='0';
System.out.print("第"+(i+1)+"轮的结果为:");
System.out.println(ar);
}
else if(ar[i]=='1'&flag==0)
{
flag=1;
ar[i]='0';
System.out.print("第"+(i+1)+"轮的结果为:");
System.out.println(ar);
}
else if(ar[i]=='0'&flag==1)
{
flag=0;
ar[i]='1';
System.out.print("第"+(i+1)+"轮的结果为:");
System.out.println(ar);
}
else if(ar[i]=='1'&flag==1)
{
flag=10;
ar[i]='0';
System.out.print("第"+(i+1)+"轮的结果为:");
System.out.println(ar);
}
else if(ar[i]=='0'&flag==10)
{
flag=11;
ar[i]='1';
System.out.print("第"+(i+1)+"轮的结果为:");
System.out.println(ar);
}
else if(ar[i]=='1'&flag==10)
{
flag=0;
ar[i]='0';
System.out.print("第"+(i+1)+"轮的结果为:");
System.out.println(ar);
}
else if(ar[i]=='0'&flag==11)
{
flag=0;
ar[i]='1';
System.out.print("第"+(i+1)+"轮的结果为:");
System.out.println(ar);
System.out.println("字符串再第"+(i+1)+"位停止继续读入");
break;
}
else if (ar[i]=='1'&flag==11)
{
flag=0;
ar[i]='0';
System.out.print("第"+(i+1)+"轮的结果为:");
System.out.println(ar);
}
}
//输入读完后的字符串
System.out.print("图灵机最终输出字符串为:");
System.out.print(ar);
}
}
运行结果展示
心得
-
由于第一次用Java编写本学科的实验题目,在编译过程中发现了一些低级的语
法错误。和C/C++语法混淆,Java语言的与运算符是“&”,而非C/C++的“&&”。由于这个原因在调试过程中一直不明白是什么原因。另外while()语句括号里必须是布尔类型的表达式,而不能像C语言那样可以用一个非零值。 -
将二进制转为二进位数值编码,是本次实践的一个难点。先定义2个字符串,一个字符串储存转换后的二进制字符串,另一个字符串储存字符全为0的字符串,且这个全为0字符串的体积是源字符串体积的三倍,这是为了防止转为二进位扩展编码,字符串体积不够)。但也是因为字符数组的体积问题遇到了top的值显然溢出数组的体积大小的情况,导致的异常。改进方式如下:
在public String expandStringSize(String arr)函数中添加如下代码:
if(arr.length()< 3)
{return status1+status1+status1+status1+status1+status1; }
else
{return status1+status1+status1;}
- 通过扩大更大的字符串的长度解决溢出问题。所以在使用栈这个数据结构,要考虑好数组溢出的可能性。
- 尽管代码实现了要求,但在public String expandStringSize(String arr)这个扩容字符串显然这个不是最优算法,字符串字符数组来来回回的转化显得麻烦,增加程序的时间复杂度。
- 本次算法设计中涉及到最多的语法点,之前上前很少接触个如此巨大的和”字符”打交道”的程序,也遇到了不少的问题。以下是本人在本次编程总结的和字符串、字符数组有关的几个函数或语法:
字符串转化为字符数组:
char[] status = arrs.toCharArray();
(其中arrs是字符串对象,status是字符数组名)
字符数组转化为字符串:
String status1=String.valueOf(status);
(其中status是字符数组名)