Tarjan'ın sözde kodu nasıl çalışır (C veya Java ile aşina olan birine açıklanır)?


40

Kısa hikaye

Ünlü bir bilgisayar bilimcisi Tarjan , yıllar önce bir kitap yazdı. Kesinlikle tuhaf sözde kod içeriyor. Birisi lütfen açıklar mı?

Uzun Hikaye

Tarjan , yayvan ağaçlarının madalyonu olması da dahil olmak üzere birçok başarı ile tanınır . 1980'lerde " Veri Yapıları ve Ağ Algoritmaları " isimli bir kitap yayınladı .

Tarjan'ın kitabındaki tüm sahte kod kendi tasarladığı dilde yazılmıştır. Sözde kod kuralları çok alay edilir. Neredeyse gerçek bir dil ve bunun için bir derleyici yazmayı düşünebiliyordu. Tarjan, dilinin aşağıdaki üçe dayandığını yazıyor:

Yukarıdaki dillerden birini veya ikisini veya Tarjan'ın çalışmalarını bilen birisinin sorumu cevaplayabileceğini umuyorum.

Tarjan dilinde yazılmış bir fonksiyon örneği aşağıda gösterilmiştir:

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;

Çok fazla sahte kod gördüm, ancak Tarjan'ınki gibi bir şey hiç görmedim. Tarjan'ın sözde kodu nasıl çalışır? Tarjan'ın sahte kodunun örnekleri, C veya Java'ya benzeyen bir şey olarak nasıl yeniden yazılabilir? C ya da Java olmasına bile gerek yok. Tarjan dilindeki if-else yapısı yalnızca C ailesi dillerinden değil, Python, MATLAB ve diğerlerinden de farklıdır.


6
Özel olarak neyi anlamadınız? Kitapta sözdizimi ve anlambilimin ne açıklaması var?
Raphael

8
Örneği bir yerden kopyaladınız mı veya kendiniz transkripsiyon mu yaptınız? İşlev gövdesindeki son iki satır gerçekten daha fazla girintili değil mi? Ve gelmez returndeyimi gerçekten virgül sona?
Bergi

Yanıtlar:


63

İçindekiler

Tarjan'ın sahte kodunu açıklamamı aşağıdaki bölümlere ayıracağım:

  1. Tarjan's If-else Blokları ( ->& |operatörleri)
  2. Atama ve Eşitlik Testleri ( :=ve =)
  3. Yapı var else if, fakat elseyapı yok
  4. Tarjan'ın Koşullu Atama Operatörü := if
  5. Tarjan ifve:= if
    5.5'in Ek Örnekleri . Tarjan Dizileri (veya Listeleri)

  6. Operatörlerin Özeti

  7. Tarjan Çift Sivri Ok Operatörü ( )
  8. Tarjan'ın döngüleri C / Java while-döngülerine benzer
  9. Tarjan'ın Şartlı atama operatörü ile tüm yanlış şartlar

(1) Tarjan'nın If-else Blokları

(operatörler ve |)

if-elseYapı belki tarjan dilinde en temel kontrol yapıdır. C-benzeri if-bloklarına ek olarak, if-else davranışı Tarjan'ın görevlendirmelerinde ve Tarjan'ın döngülerinde neredeyse tamamen yerleşiktir. Tarjan'ın ok operatörü ->(veya →), if ifadesinin koşulu ile if ifadesinin yürütme bloğu arasında bir sınırlayıcıdır.

Örneğin, Tarjan’ın dilinde:

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

Biz ise kısmen C veya Java yukarıdaki Tarjan kod satırını çevirmek, aşağıdakileri olsun:

if (a = 4)
    x := 9
fi 

Sağ kaşlı ayraçlar yerine (C ve Java'da olduğu gibi) Tarjan if, ALGOL benzeri bir anahtar kelimesi ile yazım biter :fi

Yukarıdaki örneğimizi çevirmeye devam edersek, şunu elde ederiz:

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

(2) Atama ve Eşitlik Testleri ( :=ve =)

Tarjan bu operatörleri ALGOL'den alır (daha sonra Pascal'da da görülür).

Tarjan =eşitlik testleri için kullanır , ödevleri değil (Java gibi çalışır ==).

Atama için, Tarjan :=, Java gibi çalışır =.

Dolayısıyla, örneğimizi çevirmeye devam edersek, biz:

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

|Tarjan dilinde bir dikey çubuk (veya "boru" veya ) else if, C veya Java’daki anahtar kelimeye eşdeğerdir .
Örneğin, Tarjan’ın dilinde:

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

Yukarıdaki Tarjan kodu aşağıdakilere çevrilir:

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

(3) else ifsadece ve elseyapı yok

Daha önce, ifnüansları açıklamadan açıklamaların temellerini ele aldım. Ancak küçük bir detayı tartışmayacağız. Tarjan-ian if-elsebloğundaki son cümle daima bir arrow ( ) operatörü içermelidir . Gibi else, sadece Tarjan dilinde değildir else if. elseTarjan'ın dilinde bir bloğa en yakın şey, en doğru sınav koşulunu vermektir true.

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

C / Java’da şunları yapardık:

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

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

Örneklerin anlaşılması genel açıklamalardan daha kolaydır. Bununla birlikte, şimdi kemerimizin altında bazı örneklere sahip olduğumuza göre, bir Tarjan'ın if-else yapısının genel resminin şu şekilde olduğunu biliyoruz:

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

Karakter |gibiif else

Karakter , test koşulunu yapılacak işlerden ayırır.

(4) Tarjan'ın Şartlı Atama Operatörü := if

Tarjan'ın ifiki farklı yolu kullanılabilir. Şimdiye kadar Tarjanyalıların kullanımlarından sadece birini tanımladık if. Biraz kafa karıştırıcı olan Tarjan if, ikinci tür- ifkonstrüksiyon için notasyonu / sözdizimini kullanıyor. Kullanılan hangi ifbağlamda dayanmaktadır. Bağlamı analiz etmek aslında çok kolaydır çünkü ikinci Tarjan tipi ifbir atama operatörü tarafından her zaman önceden sabitlenmiştir.

Örneğin, aşağıdaki Tarjan koduna sahip olabiliriz:

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

Basmaya Başla

Bir süre Tarjan kodu ile çalıştıktan sonra, işlemlerin sırasına alışırsınız. Yukarıdaki örnekte test koşulunu parantez içinde alırsak, şunları elde ederiz:

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

a = 4bir atama işlemi değil. a = 4gibidir a == 4- doğru ya da yanlış döndürür.

Son Basamağı

:= ifTek bir operatör için sözdizimi olarak düşünmeye yardımcı olabilir , farklı :=ve ifaslında, := ifoperatöre "koşullu atama" operatörü diyeceğiz.

İçin ifbiz listelemek (condition → action). İçin := ifbiz listelemek (condition → value)nereye valuebiz sol tarafı atayabilirsiniz teh sağ tarafı değeridirlhs

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

C veya Java gibi görünebilir:

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

Tarjan kodunda aşağıdaki "koşullu atama" örneğini düşünün:

# Örnek Beşin Tarjan Tanıtımı x: = a = 4 → 9 | a> 4 → 11 | doğru → 99 fi

C / Java’da şunları yapardık:

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

(5) İşletmecilerin Özeti:

Şimdiye kadar biz var:

  • :=....... Atama operatörü (C / Java =)

  • =...... Eşitlik testi (C / Java ==)

  • ...... if if bloğunun test durumu ile if bloğunun gövdesi arasındaki sınırlayıcı

  • | ..... C / Java-başka bir deyişle

  • if ... fi ..... eğer-else bloğu

  • := if... fi ..... Bir if-else bloğuna dayalı koşullu atama

(5.5) Tarjan Listeleri / Dizileri:

Tarjan Dili, yerleşik dizi benzeri kapsayıcılara sahiptir. Tarjan dizileri için sözdizimi, Tarjan if elseifadelerinin gösterimlerinden çok daha sezgiseldir .

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

Tarjan dizi öğelerine ()köşeli parantez içinde değil parantez içinde erişilir[]

Endeksleme başlıyor 1. Böylece,

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

Aşağıda, 1. ve 5. unsurları içeren yeni bir dizinin nasıl oluşturulacağı gösterilmektedir. [1, 2, 3, 4, 5, 6, 7]

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

Eşitlik operatörü diziler için tanımlanmıştır. Aşağıdaki kod yazdırılıyortrue

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

Tarjan'ın bir dizinin boş olup olmadığını test etmesinin yolu, onu boş bir diziyle karşılaştırmaktır.

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

Biri, operatöre ()birleştirilmiş birden çok dizin sağlayarak, bir alt dizinin bir görünümünü oluşturabilir (kopyalanamaz)..

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) Ek Tarjan örnekleri ifve:= if

Aşağıdaki bir Tarjan koşullu atamasının ( := if) başka bir örneğidir :

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

(true --> b)(cond --> action)Gerçek bir koşula sahip olan en soldaki madde. Böylece, orijinal Atama Örnek Six aynı atama davranışına sahiptira := b

Şimdiye dek en karmaşık Tarjan kodu örneğimiz:

# 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;

Aşağıdaki iki sıralı listeyi birleştirmek için Tarjan kodunun bir çevirisidir. Aşağıdakiler tam olarak C veya Java değildir, ancak C / Java'ya Tarjan versiyonundan daha yakındır.

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..]);
    }
}

Aşağıda bir başka Tarjan kodu örneği ve C veya Java'ya benzer bir çeviri örneği verilmiştir:

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;

Aşağıda C / Java çevirisi:

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'nın Çift Köşeli Ok Operatörü ( <-->)

Aşağıda bir Tarjan kodu örneği verilmiştir:

x <--> y    

Double Arrow ( ) Operatörü Tarjan Dilinde Ne Yapar ?
Peki, Tarjan'ın dilinde neredeyse tüm değişkenler işaretçilerdir. <-->takas işlemidir. Aşağıdaki baskılartrue

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

Yaptıktan sonra x <--> y, xişaret eden nesneye yişaret eder ve yişaret eden nesneye xişaret eder.

<-->Operatörü kullanan bir Tarjan deyimi aşağıdadır :

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

Aşağıda, yukarıdaki Tarjan kodundan alternatif sözde koduna yapılan bir çeviri verilmiştir:

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; 

Alternatif olarak şunları yapabiliriz:

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;
} 

Aşağıda, işlecini kullanan Tarjan işlevlerinden birine örnek verilmiştir :

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;

Aşağıda, Tarjan'ın meshişlevinin C olmayan, fakat daha çok C'ye benzeyen (nispeten konuşulan) sahte koda çevrilmesidir. Bunun amacı, Tarjan operatörünün nasıl çalıştığını göstermektir.

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'ın döngüleri C / Java iken while döngüleri

Tarjan dili ifve foryapıları C / Java programcılarına aşinadır. Ancak, bir süre döngüsü için Tarjan anahtar sözcüğüdür do. All- doloop'lar od, geriye doğru yazım denetimi yapan anahtar kelime ile sona erer do. Aşağıda bir örnek:

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

C tarzı sahte kodda:

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

Yukarıdaki aslında tam olarak doğru değil. Bir Tarjan do-döngüsü gerçekten, while(true)içinde if-else bloğu bulunan bir C / Java'dır . Tarjan kodunun daha tam anlamıyla çevirisi şöyledir:

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

Aşağıda daha karmaşık bir Tarjan do-loop var:

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

C / Java tarzı karmaşık Tarjan do-loop için sahte kod şöyle:

sum = 0;
while(true) {

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

(9) Tarjan'ın Şartlı atama operatörü, tüm yanlış koşullarla

Yukarıdaki uzun açıklama çoğu şeyi kapsamasına rağmen, birkaç husus hala çözülmeden bırakılmıştır. Umarım bir başkası bir gün bu quandriğe cevap veren benimkine göre yeni geliştirilmiş bir cevap yazacaktır.

Özellikle, koşullu atama operatörü := ifkullanıldığında ve hiçbir koşul doğru olmadığında, değişkene hangi değerin atandığını bilmiyorum.

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

Emin değilim, ancak aşağıdakilere hiçbir atama yapılmaması mümkündür x:

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

Bir := ififadede görülen sol taraf değişkeninin daha önce bildirilmesini isteyebilirsiniz . Bu durumda, tüm koşullar yanlış olsa bile, değişken hala bir değere sahip olacaktır.

Alternatif olarak, belki de tamamen yanlış koşullar çalışma zamanı hatasını temsil eder. Başka bir alternatif özel bir nulldeğer döndürmek nullve ödevin sol argümanında saklamaktır .


7
Bence basitçe bir tercüman / tercüman uygulamak ve / veya operasyonel bir anlambilim yazmak, zamanınızı bu konuda kullanmanın daha değerli bir yolu olacağını düşünüyorum.
Derek Elkins

2
Bu özelliklerden bazılarının diğerlerinden daha "egzotik" olduğunu belirtmekte fayda var. Örneğin, bir çok dilde olduğu gibi orada muhtemelen =o atama anlamına gelirken olarak araç karşılaştırma (şimdiye kadar bir dil yazdım, Size onun bir sözdizimi hatası yapmak ve sadece olurdu :=ve ==). Öte yandan, takas operatörü, yalnızca ortak bir operasyon olduğu özel dillerde gerçekleşebilecek bir şeydir; Diğer dillerde ise, her zaman uygulamayı yazmak swapyerine h1 ⟷ h2, sadece bir kitaplık fonksiyonunu üstlenip swap(h1, h2)yerine kullanabilirsiniz.
IMSoP

2
Neden [1, 2] = [1, 2, 3, 4, 5]doğru?
Erhannis

3
|Operatör bir olduğunu bekçi . Haskell'de (ve diğer işlevsel dillere inanıyorum) işlev tanımlarında kullanılırlar: f x | x == 0 = 1; x == 1 = 1; otherwise = f (x-1) + f(x-2)işte fibonacci sayıları otherwiseiçin bir takma ad Trueve ftanımlar.
Bakuriu

2
@DerekElkins Neden böyle düşünüyorsun? Bir kişinin doğal dilindeki anlayışını (diğer insanlar tarafından anlaşılması için yeterli bir ayrıntı seviyesine kadar) basitçe yazmakla karşılaştırıldığında, bahsettiğiniz her iki aktivitenin de söyleyebileceğim kadar uzun sürmesi gerekiyordu. Zamanın daha değerli bir kullanımı olacağı açık değildir (özellikle de aranan hedef öncelikli bir anlayış ise ).
ShreevatsaR

7

Bunu daha önce hiç görmedim, ancak bağlamdan ne kastedildiğini anlayabileceğimi düşünüyorum. Muhtemelen bir takas işlemi olmalı ve C ve Java'daki if G1 -> S1 | G2 - >S2 | ... fiüçlü ?:operatör gibi bir değer döndüren if / then / else türünde bir yapıdır .

Bununla, yukarıdaki işlevi şu şekilde bir Java benzeri dilde yazabiliriz:

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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.