java实现模拟图灵机实现自然数乘二

一、题目分析

目的:掌握图灵机的概念和基本结构,理解图灵机的基本指令和编码方式;
掌握图灵机的编程方法。
内容:对于任意给定的一台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到一个新的数组中。

猜你喜欢

转载自blog.csdn.net/qq_42302466/article/details/88702712