一、题目分析
目的:掌握图灵机的概念和基本结构,理解图灵机的基本指令和编码方式;
掌握图灵机的编程方法。
内容:对于任意给定的一台Turing机和任意给定的字符串w ( w不含空格),编程模拟此Turing机的运行过程,要求输出从开始运行起的每一步骤的结果。
二、算法构造
实现模拟图灵机计算自然数乘二
00→00R
01→10R
10→01R
11→100R
100→111R
110→01 STOP
按照上述计算步骤计算自然数的二倍
三、算法实现
package turing;
import java.util.Scanner;
import java.util.ArrayList;
import java.util.Arrays;
public class DoubleTheNumber {
//将输入的数字转化为二进制数
public static String transform(String num){
int number = Integer.parseInt(num);
String str ="";
while(number!=0){
str = number%2+str;
number = number/2;
}
return str;
}
//将二进制数转化为二进位码
public static ArrayList changeto(char[] a){
ArrayList b = new ArrayList();//定义了一个动态数组
b.add('0');
int i=0;
while(i<=a.length-1){
if(a[i]=='1'){
b.add(a[i]);
b.add(0);
i = i+1;
}
else{
b.add(a[i]);
i = i+1;
}
}
b.add(1);//在最后的二进位码后键入110为结尾
b.add(1);
b.add(0);
return b;
}
//将所得的二进位码输出并计算为两倍的过程输出
public static char[] calculate(ArrayList un){
int is = 0;
char[] n = new char[un.size()+10];
for(int ak=un.size();ak<un.size()+10;ak++)
n[ak] = '0';
for(int i=0;i<un.size();i++){//将动态数组(其元素为Object类)转化为字符串
Object m = un.get(i);
String cr=String.valueOf(m);
n[i] = cr.charAt(0);
}
System.out.println("这个数字的扩展的二进位码为");
for(int y=0;y<n.length;y++)
System.out.print(n[y]);
System.out.println();
for(int j=0;j<n.length;j++){
if(is==0){
if(n[j]=='0'){
is=0;
n[j]='0';
System.out.println("内态由 0 变为 0,输入为0,输出为0,右移 ");
}
else if(n[j]=='1'){
is=1;
n[j]='0';
System.out.println("内态由 0 变为 1,输入为1,输出为0,右移 ");
}
}
else if(is==1){
if(n[j]=='0'){
is=0;
n[j]='1';
System.out.println("内态由 1 变为 0,输入为0,输出为1,右移 ");
}
else if(n[j]=='1'){
is=10;
n[j]='0';
System.out.println("内态由 1 变为 10,输入为1,输出为0,右移 ");
}
}
else if(is==10){
if(n[j]=='0'){
is=11;
n[j]='1';
System.out.println("内态由 10 变为 11,输入为0,输出为1,右移 ");
}
}
else if(is==11){
if(n[j]=='0'){
is=0;
n[j]='1';
System.out.println("内态由 11 变为 0,输入为0,输出为1,停机!! ");
break;
}
}
}
return n;
}
//将最后所得的数的二进位码及其对应的十进制数输出
public static void output(char[] fl){
int i=0;
while(i<fl.length){
if(fl[i]=='1'&&fl[i+1]=='1'&&fl[i+2]=='0'){//如果读到110时,即读到,结束并退出
i = i + 2;
break;
}
i = i + 1;
}
i = i + 1;
char[] ing = new char[i];
for(int j=0;j<i;j++)
ing[j]=fl[j];
char[] out = new char[10];
int n = 0;
for(int m=0;m<ing.length-2;m++){
if(ing[m]=='0'&&ing[m+1]=='1'&&ing[m+2]=='0'){//如果在二进位码中读到010,则向结果数组中输入一个1
out[n] = '1';
n = n + 1;
}
else if(ing[m]=='0'&&ing[m+1]=='0'){//如果在二进位码中读到00,则向结果数组中输入一个0
out[n] = '0';
n = n + 1;
}
}
int k=0;
while(out[k] == '1'||out[k] == '0'){//计算最后需要多长的数组
k = k + 1;
}
char[] hz = new char[k];
for(int h=0;h<k;h++){
hz[h] = out[h] ;
}
int[] zh = new int[hz.length];
for(int x=0;x<hz.length;x++)
zh[x] = Integer.parseInt(String.valueOf(hz[x]));
int ans=0;
for(int t=0;t<zh.length;t++){
ans = (int) (ans + zh[zh.length-t-1] * Math.pow(2, t));
}
System.out.print("这个结果的扩展的二进位码为");
for(int w=0;w<ing.length;w++)
System.out.print(ing[w]);
System.out.println(",计算结果为 "+ans);
}
public static void main(String[] args){
System.out.print("请输入一个数字:");
Scanner input = new Scanner(System.in);
String number = input.next();
number = transform(number);
char[] num = number.toCharArray();//将所得二进制数转化为字符数组
ArrayList changed =changeto(num);
char[] answer = calculate(changed);
output(answer);
}
}
四、调试、测试及运行结果
1) 调试过程
2) 测试运行过程
五、经验总结
1) 学习到了字符串和字符数组的使用,以及将类型强制转化的各种方法
2) 对图灵机有了更加深刻的认识
3) 对于动态数组有了新的认识,学习到了动态数组的使用方法
ps 动态数组的使用:
1)构造器
ArrayList提供了三个构造器:
public ArrayList();
默认的构造器,将会以默认(16)的大小来初始化内部的数组
public ArrayList(ICollection);
用一个ICollection对象来构造,并将该集合的元素添加到ArrayList
public ArrayList(int);
用指定的大小来初始化内部的数组
2)IsSynchronized属性和ArrayList.Synchronized方法
IsSynchronized属性指示当前的ArrayList实例是否支持线程同步,而ArrayList.Synchronized静态方法则会返回一个ArrayList的线程同步的封装。
如果使用非线程同步的实例,那么在多线程访问的时候,需要自己手动调用lock来保持线程同步,例如:
ArrayList list = new ArrayList();
//…
lock( list.SyncRoot ) //当ArrayList为非线程包装的时候,SyncRoot属性其实就是它自己,但是为了满足ICollection的SyncRoot定义,这里还是使用SyncRoot来保持源代码的规范性
{
list.Add( “Add a Item” );
}
如果使用ArrayList.Synchronized方法返回的实例,那么就不用考虑线程同步的问题,这个实例本身就是线程安全的,实际上ArrayList内部实现了一个保证线程同步的内部类,ArrayList.Synchronized返回的就是这个类的实例,它里面的每个属性都是用了lock关键字来保证线程同步。
3)Count属性和Capacity属性
Count属性是目前ArrayList包含的元素的数量,这个属性是只读的。
Capacity属性是目前ArrayList能够包含的最大数量,可以手动的设置这个属性,但是当设置为小于Count值的时候会引发一个异常。
4)Add、AddRange、Remove、RemoveAt、RemoveRange、Insert、InsertRange
这几个方法比较类似
Add方法用于添加一个元素到当前列表的末尾
AddRange方法用于添加一批元素到当前列表的末尾
Remove方法用于删除一个元素,通过元素本身的引用来删除
RemoveAt方法用于删除一个元素,通过索引值来删除
RemoveRange用于删除一批元素,通过指定开始的索引和删除的数量来删除
Insert用于添加一个元素到指定位置,列表后面的元素依次往后移动
InsertRange用于从指定位置开始添加一批元素,列表后面的元素依次往后移动
另外,还有几个类似的方法:
Clear方法用于清除现有所有的元素
Contains方法用来查找某个对象在不在列表之中
其他的我就不一一累赘了,大家可以查看MSDN,上面讲的更仔细
5)TrimSize方法
这个方法用于将ArrayList固定到实际元素的大小,当动态数组元素确定不在添加的时候,可以调用这个方法来释放空余的内存。
6)ToArray方法
这个方法把ArrayList的元素Copy到一个新的数组中。