私はそれがチューリング完全だと思います:このトリックを使用してUTMをシミュレートするプログラムを書くことができます(私はすぐに手でコードを書いたので、おそらくいくつかの構文エラーがあります...しかし、私はロジックに(主要な)エラーがないことを望みます:-)
- テープ表現の二重リンクリストとして使用できる構造を定義する
typdef struct {
cell_t * pred; //左側のセル
cell_t * succ; //右側のセル
int val; //セル値
} cell_t
head
ポインタになりますcell_t
構造
- 現在の状態とフラグを保存するために使用できる構造を定義する
typedef struct {
int状態;
intフラグ。
} info_t
- 次に、ヘッドが二重リンクリストの境界の間にあるときにユニバーサルTMをシミュレートする単一ループ関数を定義します。頭が境界にぶつかると、info_t構造体のフラグ(HIT_LEFT、HIT_RIGHT)を設定して戻ります。
void Simulate_UTM(cell_t * head、info_t * info){
while(true){
head-> val = UTM_nextsymbol [info-> state、head-> val]; //シンボルを書く
info-> state = UTM_nextstate [info-> state、head-> val]; //次の状態
if(info-> state == HALT_STATE){//プログラムを受け入れて終了する場合に出力
putchar((info-> state == ACCEPT_STATE)? '1': '0');
exit(0);
}
int move = UTM_nextmove [info-> state、head-> val];
if(move == MOVE_LEFT){
head = head-> pred; //左に移動
if(head == NULL){info-> flag = HIT_LEFT; 戻り; }
} else {
head = head-> succ; // 右に動く
if(head == NULL){info-> flag = HIT_RIGHT; 戻り; }
}
} //まだ境界内にある...続行
}
- 次に、最初にシミュレーションUTMルーチンを呼び出し、次にテープを拡張する必要があるときに再帰的に自分自身を呼び出す再帰関数を定義します。テープを上部で拡張する必要がある場合(HIT_RIGHT)問題なく、下部でシフトする必要がある場合(HIT_LEFT)、二重リンクリストを使用してセルの値を上にシフトします。
void stacker(cell_t * top、cell_t * bottom、cell_t * head、info_t * info){
simulate_UTM(head、info);
cell_t newcell; //新しいセル
newcell.pred = top; //新しいセルで二重リンクリストを更新します
newcell.succ = NULL;
top-> succ =&newcell;
newcell.val = EMPTY_SYMBOL;
switch(info-> hit){
ケースHIT_RIGHT:
スタッカー(&newcell、bottom、newcell、info);
ブレーク;
ケースHIT_BOTTOM:
cell_t * tmp = newcell;
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 newcell;
int c = readchar();
if(c == END_OF_INPUT)stacker(&top、bottom、bottom、info); //記号はもう必要ありません、開始
newcell.pred = top;
if(top!= NULL)top.succ =&newcell; else bottom =&newcell;
init_tape(&newcell、bottom、info);
}
編集:それについて少し考えた後、ポインターに問題があります...
再帰関数のstacker
すべての呼び出しが、呼び出し側でローカルに定義された変数への有効なポインターを保持できる場合、すべてが正常です。そうしないと、私のアルゴリズムは、無制限の再帰で有効な二重リンクリストを保持できません(この場合、再帰を使用して無制限のランダムアクセスストレージをシミュレートする方法がわかりません)。