Tarjanの擬似コードはどのように機能しますか(CまたはJavaに詳しい人に説明されています)?


40

短編小説

有名なコンピューター科学者、タージャンは数年前に本を書きました。絶対に奇妙な擬似コードが含まれています。誰か説明していただけますか?

ロングストーリー

タージャンは、彼がスプレーツリーの共同発明者であったという事実を含む、多くの成果で知られています。彼は1980年代に「データ構造とネットワークアルゴリズム」という本を出版しました。

Tarjanの本のすべての擬似コードは、彼自身が考案した言語で書かれています。擬似コードの規則は非常に統制されています。それはほとんど真の言語であり、そのためのコンパイラを書くことを想像することができます。Tarjanは、彼の言語は次の3つに基づいていると書いています。

上記の言語の1つまたは2つ、またはタージャンの仕事に精通している人が私の質問に答えられることを望んでいます。

Tarjanの言語で書かれた関数の例を以下に示します。

heap function mesh (heap nodes h1, h2);

    if key(h1) > key(h2) → h1 ⟷  h2 fi;

    right (h1) := if right(h1) = null → h2

                  |right(h1) ≠ null → mesh (right(h1), h2) fi;

    if rank (left (h1)) < rank (right (h1)) → left(h1) ⟷ right(h1) fi;

rank (h1) := rank(right(h1)) + 1;

return h1,

end mesh;

私は多くの擬似コードを見てきましたが、タージャンのようなものを見たことはありません。Tarjanの擬似コードはどのように機能しますか?Tarjanの擬似コードの例を、CやJavaに似たものに書き換えるにはどうすればよいですか?CやJavaである必要さえありません。Tarjanの言語のif-elseコンストラクトは、Cファミリー言語と異なるだけでなく、Python、MATLAB、その他多くの言語とも異なります。


6
具体的に何を理解していないのですか?この本には、構文とセマンティクスのどのような説明がありますか?
ラファエル

8
どこかからサンプルをコピーしましたか、それとも自分で転写しましたか?関数本体内の最後の2行は実際にはインデントされていませんか?そして、return文は本当にカンマで終わっていますか?
ベルギ

回答:


63

目次

Tarjanの擬似コードの説明を次のセクションに分けます。

  1. TarjanのIf-elseブロック(->|演算子)
  2. 割り当てと同等性のテスト(:=および=
  3. がありますがelse ifelseコンストラクトはありません
  4. タージャンの条件付き割り当て演算子 := if
  5. Tarjan ifおよび:= if
    5.5 の追加例Tarjan配列(またはリスト)

  6. オペレーターの概要

  7. タージャンの両方向矢印演算子(
  8. TarjanのdoループはC / Java whileループのようなものです
  9. すべての偽条件を持つタージャンの条件付き代入演算子

(1)タージャンのIf-elseブロック

(オペレータ|

if-elseコンストラクトは、おそらくTarjanの言語の中で最も基本的な制御構造です。Cのようなifブロックに加えて、if-elseの動作はTarjanの割り当てとTarjanのwhileループにほぼ組み込まれています。Tarjanの矢印演算子->(または→)は、ifステートメントの条件とifステートメントの実行ブロックの間の区切り文字です。

たとえば、タージャンの言語では次のようになります。

# Example One
if a = 4 → x := 9 fi    

上記のTarjanコードの行を部分的にCまたはJava 変換すると、次のようになります。

if (a = 4)
    x := 9
fi 

(CやJavaのように)右中括弧の代わりに、タージャンifは、キーワードのALGOLのような逆スペルで-blockを終了します。fi

上記の例を翻訳し続けると、次のようになります。

if (a = 4) {
    x := 9
}

(2)割り当ておよび平等テスト(:=および=

Tarjanはこれらの演算子をALGOLから取得します(後でPascalでも見られます)。

Tarjanは=、割り当てではなく同等性テストに使用します(したがって、Javaのように機能します==)。

割り当てには、Tarjanは:=Javaのように機能するを使用します=

したがって、例を翻訳し続けると、次のようになります。

if (a == 4) {
    x = 9
}

|Tarjanの言語の垂直バー(または「パイプ」または)はelse if、CまたはJavaのキーワードと同等です。
たとえば、タージャンの言語では次のようになります。

# Example Two
if a = 4 → x := 9 |  a > 4  → y := 11 fi 

上記のTarjanコードは次のように変換されます。

if (a == 4) {
    x = 9
}
else if (a > 4)  {
    y = 11
}

(3)else ifのみなしelse構築

前に、ifニュアンスを説明せずに- ステートメントの基本を説明しました。ただし、詳細については説明しません。Tarjan-ian if-elseブロックの最後の句には、常に矢印()演算子を含める必要があります。そのためelse、タージャンの言語にはありませんelse ifelseTarjanの言語のブロックに最も近いのは、一番右のテスト条件を作成することtrueです。

if a = 4 → x := 9 |  a > 4  → y := 11 | true  → z := 99  fi

C / Javaでは、次のようになります。

if (a == 4) {
    x = 9
}

else if (a > 4)  {
    y = 11
}
else { // else if (true)
    z = 99
} 

例は一般的な説明よりも理解しやすいです。ただし、今ではいくつかの例がありますが、タージャンのif-elseコンストラクトの一般的な形式は次のとおりであることを知っています。

if condition
    → stuff to do
 | condition
    → stuff to do
 [...] 
 | condition 
    → stuff to do
fi       

キャラクター |if else

キャラクターは、テスト条件とスタッフの仕事を分けます。

(4)タージャンの条件付き割り当て演算子 := if

Tarjanのは、if2つの非常に異なる方法を使用することができます。これまでのところ、タルヤニア語の使用法の1つだけを説明しましたif。やや紛らわしいことに、Tarjanはまだ-constructのif2番目のタイプに表記法/構文を使用していますif。どちらifが使用されているかは、コンテキストに基づいています。2番目のタイプのTarjan- ifは常に代入演算子によって事前に固定されているため、コンテキストの分析は実際には非常に簡単です。

たとえば、次のTarjanコードがあるとします。

# Example Three
x := if a = 4 → 9 fi 

余談を開始

Tarjanコードをしばらく使用した後、操作の順序に慣れます。上記の例でテスト条件を括弧で括ると、次のものが得られます。

x := if (a = 4) → 9 fi 

a = 4割り当て操作ではありません。a = 4のようなものa == 4です。trueまたはfalseを返します。

余談を終わらせる

それは考えるのを助けることができる:= ifとは別個の、単一のオペレータのための構文として:=およびif実際には、我々が参照する:= if「条件付き代入」演算子と演算子。

以下のためのif私たちのリスト(condition → action):= if我々はリスト(condition → value)ところvalue、我々は左手側に割り当てることができますtehの右辺値でありますlhs

# Tarjan Example Four
lhs := if (a = 4) → rhs fi 

CまたはJavaの場合は次のようになります。

# Example Four
if (a == 4) {
    lhs = rhs
}

Tarjanianコードの「条件付き割り当て」の次の例を考えてみましょう。

#例5のタージャンのインスタンス化x:= a = 4→9 | a> 4→11 | true→99 fi

C / Javaでは、次のようになります。

// C/Java Instantiation of Example Five
if (a == 4) {
    x = 9
}
else if (a > 4)  {
    x = 11
}
else if (true) { // else
    x = 99
} 

(5)オペレーターの要約:

これまでのところ、次のものがあります。

  • :=......代入演算子(C / Java =

  • =......同等性テスト(C / Java ==

  • ...... ifブロックのテスト条件とifブロックの本体の間の区切り文字

  • | ..... C / Java else-if

  • if ... fi ..... if-elseブロック

  • := if... fi ..... if-elseブロックに基づく条件付き割り当て

(5.5)タージャンリスト/配列:

Tarjanの言語には、配列のようなコンテナが組み込まれています。Tarjan配列の構文は、Tarjan if elseステートメントの表記よりもはるかに直感的です。

list1  := ['lion', 'witch', 'wardrobe'];
list2a := [1, 2, 3, 4, 5];
list2b := [1, 2];
list3  := ["a", "b", "c", "d"];
list4  := [ ]; # an empty array

Tarjan配列elementaは()、角括弧ではなく括弧でアクセスされます[]

インデックス作成はから始まります1。したがって、

list3  := ["a", "b", "c", "d"]
# list3(1) == "a" returns true
# list3(2) == "b" return true 

以下は、の1番目と5番目の要素を含む新しい配列を作成する方法を示しています [1, 2, 3, 4, 5, 6, 7]

nums := [1, 2, 3, 4, 5, 6, 7]
new_arr := [nums(1), nums(5)]

等価演算子は配列に対して定義されます。次のコードは印刷しますtrue

x := false
if [1, 2] = [1, 2, 3, 4, 5] --> x := true
print(x)

配列が空かどうかをテストするタージャンの方法は、空の配列と比較することです

arr := [1, 2]
print(arr = [ ])
# `=` is equality test, not assignment

一つは、オペレータに複数の指標を提供することにより、サブアレイ(コピーしない)ビューを作成することができる()と組み合わせます..

list3  := ["a", "b", "c", "d"]

beg    := list3(.. 2)
# beg == ["a", "b"]
# beg(1) == "a"

end    := list3(3..)
# end == ["c", "d"]
# end(1) == "c"

mid    := list3(2..3)
# mid == ["b", "c"]
# mid(2) == "c"

# `list3(4)` is valid, but `mid(4)` is not 

(6)タージャンifおよび:= if

次に、タージャン条件付き割り当て(:= if)の別の例を示します。

# Tarjan Example Six
a  := (false --> a | true --> b | false --> c1 + c2 |  (2 + 3 < 99) --> d)  

(true --> b)(cond --> action)真の条件を持つ左端の句です。したがって、元の割り当て例6には、次と同じ割り当て動作があります。a := b

以下は、これまでで最も複雑なTarjanコードの例です。

# Tarjan Example -- merge two sorted lists

list function merge (list s, t);

return if s =[] --> t
        | t = [ ] --> s
        | s != [ ] and t != [] and s(l) <= t(1) -->
            [s(1)]& merge(s[2..], t)
        | s != [ ]and t != [ ] and s(1) > r(l) -->
            [t(1)] & merge (s,t(2..))
       fi
end merge;

以下は、ソートされた2つのリストをマージするためのTarjanのコードの翻訳です。以下は正確にCやJavaではありませんが、TarjanバージョンよりもC / Javaにはるかに近いものです。

list merge (list s, list t) { 

    if (s is empty) {
        return t;
    }
    else if (t is empty){
        return s;
    }
    else if  (s[1] <= t[1]) {
        return CONCATENATE([s[1]], merge(s[2...], t));
    else  { // else if (s[1] > t[1])
        return CONCATENATE ([t[1]], merge(s,t[2..]);
    }
}

以下は、Tarjanコードの別の例と、CまたはJavaに似た翻訳です。

heap function meld (heap h1, h2);

    return if h1 = null --> h2
            | h2 = null --> h1
            | h1 not null and h2 not null --> mesh (h1, h2) 
           fi
end meld;

以下はC / Javaの翻訳です。

HeapNode meld (HeapNode h1, HeapNode h2) {

    if (h1 == null) {
       return h2;
    }   
    else if (h2 == null) {
        return h1;
    } else {
        mesh(h1, h2)
    }
} // end function

(7)タージャンの両方向矢印演算子(<-->

以下はTarjanコードの例です。

x <--> y    

二重矢印()演算子はタージャンの言語で何をしますか?
タージャンの言語のほとんどすべての変数はポインターです。 <-->スワップ操作です。次のプリントtrue

x_old := x
y_old := y
x <--> y
print(x == y_old) # prints true
print(y == x_old) # prints true

を実行した後x <--> yxポイントしていたオブジェクトyをポイントし、yポイントしていたオブジェクトxをポイントします。

以下は、<-->演算子を使用したTarjanステートメントです。

x := [1, 2, 3]
y := [4, 5, 6]
x <--> y 

以下は、上記のタージャンコードから別の擬似コードへの翻訳です。

Pointer X     = address of array [1, 2, 3];
Pointer Y     = address of array [4, 5, 6];
Pointer X_OLD = address of whatever X points to;
X = address of whatever Y points to;
Y = address of whatever X_OLD points to; 

または、次のようにすることもできます。

void operator_double_arrow(Array** lhs, Array** rhs) {

    // swap lhs and rhs

    int** old_lhs = 0;
    old_lhs = lhs;
    *lhs = *rhs;
    *rhs = *old_lhs;
    return;
}

int main() {

    Array* lhs = new Array<int>(1, 2, 3);
    Array* rhs = new Array<int>(4, 5, 6);
    operator_double_arrow(&lhs, &rhs);
    delete lhs;
    delete rhs;
    return 0;
} 

以下は、演算子を使用したTarjanの関数の1つの例です。

heap function mesh (heap nodes h1, h2);
    if key(h1) > key(h2) → h1 ⟷  h2 fi;
    right (h1) := if right(h1) = null → h2
                   |right(h1) ≠ null → mesh (right(h1), h2)
                  fi;

    if rank (left (h1)) < rank (right (h1))
        → left(h1) ⟷ right(h1)
    fi;

    rank (h1) := rank(right(h1)) + 1;
    return h1;
end mesh;

以下はTarjanのmesh関数をCではない擬似コードに変換したものですが、Cに似ています(比較的言えば)。これの目的は、タージャンのオペレーターがどのように機能するかを説明することです。

node pointer function mesh(node pointers h1, h2) {

    if (h1.key) > h2.key) {

         // swap h1 and h2
            node pointer temp;
            temp = h1;
            h1 = h2;
            h2 = temp;
    }

    // Now, h2.key <= h1.key   

    if (h1.right == null) {
        h1.right = h2;

    } else // h1.key != null {
        h1.right = mesh(h1.right, h2);
    }



    if (h1.left.rank < h1.right.rank ) {
        // swap h1.left and h1.right

        node pointer temp;
        temp = h1;
        h1 = h2;
        h2 = temp;
    }

    h1.rank = h1.right.rank + 1;
    return h1;
}    

(8)TarjanのdoループはC / Java whileループに似ています

Tarjanの言語iffor構成体は、C / Javaプログラマーに馴染みがあります。ただし、while-loopのTarjanキーワードはdoです。すべてのdoループはキーワードodで終わりdoます。これは、の逆スペルです。以下に例を示します。

sum := 0
do  sum < 50 → sum := sum + 1 

Cスタイルの擬似コードには、次のものがあります。

sum = 0;
while(sum < 50) {
    sum = sum + 1;
}

上記は実際には正しくありません。Tarjan do-loopは、実際にはwhile(true)if-elseブロックが内部にネストされたC / Java です。Tarjanコードのより文字通りの翻訳は次のとおりです。

sum = 0;
while(true) {
    if (sum < 50) {
         sum = sum + 1;
         continue;
         // This `continue` statement is questionable
    }
    break;
}

以下に、より複雑なTarjan doループを示します。

sum := 0
do  sum < 50 → sum := sum + 1 | sum < 99 → sum := sum + 5

複雑なTarjan doループのC / Javaスタイルの擬似コードは次のとおりです。

sum = 0;
while(true) {

    if (sum < 50) {
         sum = sum + 1;
         continue;
    }
    else if (sum < 99) {
         sum = sum + 5;
         continue;
    }
    break;
}

(9)すべての偽条件を持つタージャンの条件付き代入演算子

上記の長い説明はほとんどのことをカバーしていますが、いくつかの問題は未解決のままです。いつか他の誰かがこれらの怒りに答える私のものに基づいて新しい改善された答えを書くことを願っています。

特に、条件付き代入演算子:= ifが使用され、条件が真でない場合、変数にどの値が割り当てられているかはわかりません。

x  := if (False --> 1| False --> 2 | (99 < 2) --> 3) fi

よくわかりませんが、次のものに割り当てられない可能性がありxます。

x = 0;
if (false) {
     x = 1;
}
else if (false) {
     x = 2;
}
else if (99 < 2) {
     x = 3;
}
// At this point (x == 0)

:= ifステートメントに見られる左側の変数は、事前に宣言する必要があります。その場合、すべての条件が偽であっても、変数にはまだ値があります。

あるいは、おそらくすべて偽の条件はランタイムエラーを表します。別の方法は、特別なnull値を返しnull、割り当ての左側の引数に格納することです。


7
私は、単にインタプリタ/翻訳機を実装すること、および/または操作上のセマンティクスを書くことは、これに関してあなたの時間を使うためのより価値のある方法だと思います。
デレクエルキンズ

2
これらの機能の中には、他の機能よりも「エキゾチック」なものがあることに注意してください。たとえば、=割り当てを意味する場所と比較することを意味する言語は、おそらく同じくらい多くあります(言語を書いたことがあれば、構文エラーにし、単にandを持っ:=ています==)。一方、スワップ演算子は、一般的な操作である特殊な言語でのみ発生する種類のものです。ただし、他の言語では、毎回実装を記述するのではなく、ライブラリ関数が呼び出されswapて置き換えられるh1 ⟷ h2と想定することができますswap(h1, h2)
IMSoP

2
なぜ[1, 2] = [1, 2, 3, 4, 5]本当ですか?
エルハニス

3
|オペレータはあるガード。これらはHaskell(および他の関数型言語)の関数定義で使用されます。f x | x == 0 = 1; x == 1 = 1; otherwise = f (x-1) + f(x-2)ここにフィボナッチ数のotherwiseエイリアスTruef定義があります。
バクリウ

2
@DerekElkinsなぜあなたはそう思いますか?自分の理解を自然言語で(他の人間が理解するのに十分な詳細レベルで)単に書くのに比べて、あなたが言う両方の活動は、私が知る限りかなり長い時間がかかるでしょう。それがより価値のある時間の使用になるかどうかは明確ではありません(特に、求められている目標が主に理解している場合)。
シュリーバツァー

7

これは前に見たことが ありませんが、コンテキストから何を意味するかを推測できると思います。おそらく、これはスワップ操作である必要があり、C / Javaのif G1 -> S1 | G2 - >S2 | ... fi三項?:演算子のような値を返すif / then / else-typeコンストラクトです。

それを手にして、上記の関数をJavaのような言語で次のように書くことができます。

HeapNode mesh(HeapNode h1, HeapNode h2)
{
  if(h1.key > h2.key)
  {
    // swap h1 and h2

    HeapNode t = h1;
    h1 = h2;
    h2 = t;
  }

  // One of the two cases has to hold in this case so we won't get to the
  // exception, but it'd be an exception if none of the cases were satisified
  // since this needs to return *something*.

  h1.right = (h1.right == null) ? h2 
             : (h1.right != null) ? mesh(h1.right, h2) 
             : throw new Exception();

  if(h1.left.rank < h1.right.rank)
  {
    // swap h1.left and h1.right

    HeapNode t = h1.left;
    h1.left = h1.right;
    h1.right = t;
  }

  h1.rank = h1.right.rank + 1;

  return h1;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.