튜링 완료 라고 생각합니다 .이 트릭을 사용하여 UTM을 시뮬레이트하는 프로그램을 작성할 수 있습니다 (빠른 코드를 직접 작성하여 구문 오류가있을 수 있습니다 ...하지만 논리에 (주) 오류가 없기를 바랍니다. :-)
- 테이프 표현을위한 이중 연결 목록으로 사용할 수있는 구조 정의
typdef 구조체 {
cell_t * pred; // 왼쪽의 셀
cell_t * succ; // 오른쪽에있는 셀
int val; // 셀 값
} cell_t
는 head
A와 포인터 될 것입니다 cell_t
구조
- 현재 상태 및 플래그를 저장하는 데 사용할 수있는 구조 정의
typedef 구조체 {
int 상태;
int 플래그;
} info_t
- 그런 다음 헤드가 이중 연결 목록의 경계 사이에있을 때 Universal TM을 시뮬레이트하는 단일 루프 함수를 정의하십시오. 헤드가 경계에 도달하면 info_t 구조체의 플래그 (HIT_LEFT, HIT_RIGHT)를 설정하고 다음을 반환합니다.
void simulation_UTM (cell_t * head, info_t * info) {
while (true) {
head-> val = UTM_nextsymbol [정보-> 상태, 헤드-> val]; // 기호 쓰기
info-> state = UTM_nextstate [정보-> 상태, 헤드-> val]; // 다음 상태
if (info-> state == HALT_STATE) {// 프로그램을 수락하고 종료하면 인쇄
putchar ((info-> state == ACCEPT_STATE)? '1': '0');
이탈 (0);
}
int move = UTM_nextmove [정보-> 상태, 헤드-> val];
if (move == MOVE_LEFT) {
머리 = 머리-> 먹이; // 왼쪽으로 이동
if (head == NULL) {info-> flag = HIT_LEFT; 반환; }
} else {
머리 = 머리-> succ; // 오른쪽으로 이동해라
if (head == NULL) {info-> flag = HIT_RIGHT; 반환; }
}
} // 여전히 경계에 있습니다 ... 계속
}
- 그런 다음 먼저 시뮬레이션 UTM 루틴을 호출하고 테이프를 확장해야 할 때 재귀 적으로 호출하는 재귀 함수를 정의하십시오. 테이프를 맨 위에 확장해야 할 때 (HIT_RIGHT) 문제가없고 맨 아래에서 이동해야 할 때 (HIT_LEFT) 이중 링크 된 목록을 사용하여 셀 값을 위로 이동하면됩니다.
무효 스태커 (cell_t * top, cell_t * bottom, cell_t * head, info_t * info) {
시뮬레이션 _UTM (헤드, 정보);
cell_t 뉴셀; // 새로운 셀
newcell.pred = 상단; // 새로운 셀로 이중 연결리스트 업데이트
newcell.succ = NULL;
top-> succ = & newcell;
newcell.val = EMPTY_SYMBOL;
스위치 (정보-> 적중) {
case HIT_RIGHT :
스태커 (& newcell, bottom, newcell, info);
단절;
case HIT_BOTTOM :
cell_t * tmp = 뉴셀;
while (tmp-> pred! = NULL) {// 값을 위로 이동
tmp-> val = tmp-> pred-> val;
tmp = tmp-> pred;
}
tmp-> val = EMPTY_SYMBOL;
스태커 (& newcell, bottom, bottom, info);
단절;
}
}
- 초기 테이프는 이중 연결 목록을 작성
stacker
하고 입력 테이프의 마지막 기호를 읽을 때 함수 를 호출하는 간단한 재귀 함수로 채워질 수 있습니다 (readchar 사용).
void init_tape (cell_t * top, cell_t * bottom, info_t * info) {
cell_t 뉴셀;
int c = readchar ();
if (c == END_OF_INPUT) 스태커 (& top, bottom, bottom, info); // 더 이상 기호가 없습니다. 시작
newcell.pred = 상단;
if (top! = NULL) top.succ = & newcell; else bottom = & newcell;
init_tape (& newcell, 하단, 정보);
}
편집 : 그것에 대해 조금 생각한 후 포인터에 문제가 있습니다 ...
재귀 함수의 모든 호출이 stacker
호출자에 로컬로 정의 된 변수에 대한 유효한 포인터를 가질 수 있다면 모든 것이 정상입니다 . 그렇지 않으면 내 알고리즘이 무제한 재귀에서 유효한 이중 연결 목록을 유지할 수 없습니다 (이 경우 재귀를 사용하여 무제한 무작위 액세스 저장소를 시뮬레이션하는 방법을 보지 못함).