Tarjan의 의사 코드는 어떻게 작동합니까 (C 또는 Java에 익숙한 사람에게 설명)?


40

단편

유명한 컴퓨터 과학자 Tarjan 은 몇 년 전에 책을 썼습니다. 그것은 절대적으로 기괴한 의사 코드를 포함합니다. 누군가 설명해 주시겠습니까?

긴 이야기

타잔 은 그가 놀이 나무 의 공동 창업자라는 사실을 포함하여 많은 업적으로 유명합니다 . 그는 1980 년대에 " 데이터 구조 및 네트워크 알고리즘 "이라는 책을 출판했습니다 .

Tarjan의 책에있는 모든 의사 코드는 자신이 고안 한 언어로 작성되었습니다. 의사 코드 규칙은 매우 체계적입니다. 그것은 거의 진정한 언어이며 컴파일러를 작성하는 것을 상상할 수 있습니다. Tarjan은 그의 언어가 다음 세 가지를 기반으로한다고 썼다.

위의 언어 중 하나 또는 두 가지 언어 또는 Tarjan의 작업에 익숙한 사람이 내 질문에 대답 할 수 있기를 바랍니다.

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의 유사 코드는 어떻게 작동합니까? Tarjan의 의사 코드의 예를 어떻게 C 또는 Java와 유사한 것으로 다시 작성할 수 있습니까? C 나 Java 일 필요도 없습니다. Tarjan 언어의 if-else 구문은 C 계열 언어뿐만 아니라 Python, MATLAB 및 기타 여러 언어와 다릅니다.


6
구체적으로 무엇을 이해하지 못합니까? 이 책에서 구문과 의미에 대한 설명은 무엇입니까?
Raphael

8
어딘가에서 샘플을 복사했거나 직접 기록 했습니까? 함수 본문 내부의 마지막 두 줄이 실제로 더 들여 쓰기되지 않습니까? 그리고 그 return진술은 실제로 쉼표로 끝나나요?
Bergi

답변:


63

목차

Tarjan 의 의사 코드에 대한 설명을 다음 섹션으로 나누겠습니다 .

  1. Tarjan의 If-else 블록 ( ->|연산자)
  2. 과제 및 평등 시험 ( :==)
  3. else if이지만 else구성 은 없습니다
  4. Tarjan의 조건부 할당 연산자 := if
  5. Tarjan if:= if
    5.5 의 추가 예 . 타잔 배열 (또는리스트)

  6. 연산자 요약

  7. 타잔의 이중 화살표 연산자 ( )
  8. Tarjan의 do 루프는 C / Java while-loop와 같습니다.
  9. 모든 잘못된 조건을 가진 Tarjan의 조건부 할당 연산자

(1) 타잔의 If-else 블록

(연산자 |)

if-else구조는 아마도 Tarjan의 언어에서 가장 기본적인 제어 구조 일 것입니다. C와 같은 if-block 외에도, if-else 행동은 Tarjan의 할당과 Tarjan의 while 루프에 거의 내장되어 있습니다. Tarjan의 화살표 연산자 ->(또는 →)는 if 문의 상태와 if 문의 실행 블록 사이의 구분 기호입니다.

예를 들어 Tarjan의 언어에는 다음이있을 수 있습니다.

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

우리가 경우 부분적으로 C 또는 Java로 위의 Tarjan 코드의 라인을 번역, 우리는 다음을 얻을 :

if (a = 4)
    x := 9
fi 

오른쪽 중괄호 대신 (C 및 Java에서와 같이) Tarjan if은 키워드의 ALGOL과 유사한 역순으로 -block을 종료합니다 .fi

위 예제를 계속 번역하면 다음과 같은 결과를 얻습니다.

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

(2) 과제 및 평등 시험 ( :==)

Tarjan은이 연산자를 ALGOL (나중에 Pascal에서도 볼 수 있음)에서 가져옵니다.

Tarjan은 =할당이 아닌 동등성 테스트에 사용 하므로 Java처럼 작동합니다 ==.

할당을 위해 Tarjan은 :=Java처럼 작동하는을 사용합니다 =.

따라서 우리의 예를 계속 번역하면 다음과 같은 결과가 나타납니다.

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

|Tarjan 언어 의 세로 막대 (또는 "pipe"또는 ) else if는 C 또는 Java 의 키워드 와 같습니다 .
예를 들어 Tarjan의 언어에는 다음이있을 수 있습니다.

# 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블록 의 마지막 절 에는 항상 화살표 ( ) 연산자가 포함되어야합니다 . 따라서 elseTarjan의 언어 는 없습니다 else if. elseTarjan의 언어에서 블록에 가장 가까운 것은 가장 올바른 테스트 조건을 만드는 것 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
} 

예는 일반적인 설명보다 이해하기 쉽습니다. 그러나 이제 우리는 벨트 아래에 몇 가지 예가 있으므로 Tarjan의 if-else 구문의 일반적인 형식은 다음과 같습니다.

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

캐릭터 |if else

캐릭터 는 테스트 조건을 수행 할 작업과 분리합니다.

(4) Tarjan의 조건부 할당 연산자 := if

Tarjan if은 두 가지 다른 방식으로 사용될 수 있습니다. 지금까지 Tarjanian의 사용법 중 하나만 설명했습니다 if. 다소 혼란스럽게도 Tarjan은 여전히 if두 번째 유형의 if-construct에 표기법 / 구문 을 사용합니다 . 어떤 if컨텍스트를 기반으로 사용하고 있습니다. 두 번째 유형의 Tarjan- if은 항상 할당 연산자에 의해 미리 고정 되므로 컨텍스트 분석은 실제로 매우 쉽습니다 .

예를 들어 다음과 같은 Tarjan 코드가있을 수 있습니다.

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

침략을 시작하십시오

Tarjan 코드로 잠시 작업 한 후 작업 순서에 익숙해집니다. 위 예제에서 테스트 조건을 괄호로 묶으면 다음과 같은 결과를 얻습니다.

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

a = 4할당 작업이 아닙니다. a = 4같다 a == 4-참 또는 거짓을 돌려 준다.

엔드 디 펜션

그것은 생각하는 데 도움이 될 수 있습니다 := 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의 Tarjan 인스턴스화 x x : = a = 4 → 9 | a> 4 → 11 | 참 → 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-block의 테스트 조건과 if-block의 본문 사이의 구분자

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

  • if ... fi ..... if-else 블록

  • := if... fi ..... if-else 블록을 기반으로하는 조건부 할당

(5.5) Tarjan 목록 / 배열 :

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, 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)

배열이 비어 있는지 테스트하는 Tarjan의 방법은 빈 배열과 비교하는 것입니다.

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) Tarjan if:= if

다음은 Tarjan 조건부 할당 ( := if) 의 다른 예입니다 .

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

(true --> b)(cond --> action)조건 이 가장 왼쪽 인 절입니다. 따라서 원래 과제 Example Six는 다음과 같은 과제 동작을 갖습니다.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;

다음은 두 가지 정렬 된 목록을 병합하기위한 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-code의 또 다른 예이며 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    

이중 화살표 ( ) 연산자는 Tarjan의 언어로 무엇을합니까?
Tarjan 's Language의 거의 모든 변수는 포인터입니다. <-->스왑 작업입니다. 다음 인쇄true

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

수행 한 후 x <--> y, x목적으로 포인트 y와 포인트 사용 y목적에 지점 x을 가리키는 데 사용.

아래는 <-->연산자를 사용하는 Tarjan 문입니다 .

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

아래는 위의 Tarjan 코드에서 다른 유사 코드로의 변환입니다.

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의 기능 중 하나의 예입니다 .

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와 비슷해 보입니다 (상대적으로 말하면). 이것의 목적은 Tarjan의 운영자의 작동 방식을 설명하기위한 것입니다 .

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-loop와 같습니다.

Tarjan의 언어 iffor구문은 C / Java 프로그래머에게 친숙합니다. 그러나 while 루프의 Tarjan 키워드는 do입니다. 모든 do키워드에 끝 -loops 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-loop의 C / Java 스타일 의사 코드 는 다음과 같습니다.

sum = 0;
while(true) {

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

(9) 모든 잘못된 조건을 가진 Tarjan의 조건부 할당 연산자

위의 긴 설명은 대부분의 내용을 다루지 만 몇 가지 문제는 여전히 해결되지 않은 상태로 남아 있습니다. 언젠가 다른 사람들이 언젠가이 질문에 답하는 내 기반의 새로운 개선 된 답변을 쓰길 바랍니다.

특히 조건부 할당 연산자 := if를 사용하고 조건이 true가 아닌 경우 변수에 할당 된 값이 아닙니다.

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
이러한 기능 중 일부는 다른 기능보다 "이국적"이라는 점에 주목할 가치가 있습니다. 예를 들어, 많은 언어로 아마 거기 =가 할당을 의미 곳과 같은 방법 비교 (내가 언어를 쓴 경우, 나는 그것을 구문 오류 확인 및 단지 거라고 :=하고 ==). 반면 스왑 연산자는 일반적인 작업 인 특수 언어에서만 발생할 수있는 종류입니다. 다른 언어로,하지만, 당신은 단지라는 라이브러리 기능을 가정 수 swap와 교체 h1 ⟷ h2swap(h1, h2)오히려 구현마다를 작성하는 것보다.
IMSoP

2
[1, 2] = [1, 2, 3, 4, 5]사실입니까?
Erhannis

3
|연산자는이다 가드 . 그들은 하스켈에서 사용되는 (그리고 나는 다른 기능 언어 믿는다) 함수 정의의를 : f x | x == 0 = 1; x == 1 = 1; otherwise = f (x-1) + f(x-2)여기 otherwise의 별칭 Truef피보나치 수를 정의합니다.
Bakuriu

2
@DerekElkins 왜 그렇게 생각하십니까? 자연어로 이해 한 내용을 다른 사람이 이해할 수있을 정도로 상세하게 작성하는 것과 비교할 때 언급 한 두 가지 활동 모두 내가 알 수있는 한 훨씬 더 오래 걸릴 것입니다. 시간을보다 가치있게 사용한다는 것은 확실하지 않습니다 (특히 추구하는 목표가 주로 이해하는 경우 ).
ShreevatsaR

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.