문제

최근 프로그래밍 수업의 경우, 우리는 주어진 언어로 프로그램을 작성하도록 과제를 받았습니다. N, 배열에 대한 가능한 모든 derangements를 생성합니다. 크기 N 그렇게 I]! = I : I : 0 <= i <n. 우리는 반복자를 사용해야했습니다 yield.

예 : n = 3, [0, 1, 2]는 혼란이 아니지만 [2, 0, 1]은 [1, 2, 0]입니다.

나는 효과가있는 의사 코드 솔루션을 생각해 냈지만 문제는 전원 루프가 필요하다는 것이었다. N 중첩 루프는 어디에 있습니다 N 런타임에만 알려져 있습니다). 이를 위해, 나는 생성했다 N 문자열로 루비 코드의 중첩 루프, 그런 다음 eval-문자열. 내 솔루션이 효과가 있었지만 교수는 몇 가지를 사용한다고 생각했습니다. gotoS는 동적 코드 생성보다 더 나은 솔루션 (적어도 읽기 쉬운)이었을 것입니다.

나는 그 인상을 받았다 goto 항상 나쁜 선택이었습니다. 동적으로 생성 된 코드의 런타임 평가가 왜 goto? 생성 된 코드는 깨끗하고 간단하며 주어진 문제에 대해 상당히 효율적인 것 같습니다. 코드 생성이 의존하는 유일한 사용자 입력은 다음과 같습니다. N, 이는 사전에 정수 값인지 확인합니다. 그것 yield독특한 독창적 인 경멸 만하면됩니다.

나는 프로그래밍 과제에 대한 해결책을 요구하지 않고 사용의 이유를 알고 싶습니다. goto 동적 코드 평가를 통해 또는 그 반대도 마찬가지입니다.

편집하다: 명확히하기 위해, 과제에는 반복자와 다른 재귀를 사용하여 프로그램을 작성하는 것이 포함되었으므로 반복 버전이 반드시 효율적이어야 할 것은 아닙니다.

도움이 되었습니까?

해결책

정말 흥미로운 질문입니다. 결정적인 대답이 있는지 잘 모르겠습니다.

GOTO의 문제점은 구조화되지 않은 방식으로 사용하는 것입니다. GOTO는 "거대한 임의의 도약"이므로 일반적인 경우 점프 후 어디에서 왔는지 알 수 없습니다. 디버깅 및 유지 가능성 및 코드의 "정확성"을 증명하는보다 공식적인 의미에서. 물론 코드에 구조를 부과하는 시점에 옵션이없는 언어 (한동안)가 있습니다. 결론은 Goto가 Goto가 사용되는 방식 (그리고 학대)만큼 나쁘지 않다는 것이 좋지 않다는 것입니다.

코드 생성을 사용한 다음 결과를 평가하는 것은 영리합니다 :) 그러나 "영리한"것이 항상 좋은 것은 아니며 부분적으로 그것을 솔루션으로 사용하는 문제는 실제로 의도 된대로 문제를 해결하는 것은 아니라고 생각합니다. 그것은 적어도 교수와 관련하여 "부정 행위"일 수 있습니다. 적어도 교수와 관련하여 해결책을 무효화하지는 않지만 "무능한"을 렌더링 할 수 있습니다. 디버깅 및 유지 관리 문제도 코드와 관련하여 발생합니다.

재귀 솔루션 - 특히 25 년 전 (약 25 년 전에) 모호하게 기억하는 것을 기억하는 것처럼 보통 리퍼스에 재귀를 풀 수 있다는 것이 아마도 가장 우아 할 것입니다.

확실히 흥미로운 질문!

다른 팁

Goto와 Code Generation은 모두이 문제 IMO에 대한 무능한 솔루션입니다. 아마도 재귀 알고리즘이 있습니다 오른쪽 여기서 답하십시오.

당신의 코드를 보지 않고 나는 교수와 함께하는 경향이 있습니다. Goto와 Dynamic Code 사이의 선택이라면 전자에 기대어 있습니다. GOTO는 아닙니다 언제나 나쁜 선택.

Gotos를 사용하지 않고 거의 모든 문제를 해결할 수 있습니다. 특히 루프를 사용하면 Code Standard가 여전히 유지되는 동안 브레이크 및 계속 명령문을 사용할 수 있습니다.

N 중첩 루프는 나쁜 계획처럼 들리며 대신 재귀 기능을 살펴 보는 것이 좋습니다. N- 루프를해야 할 때마다 항상 재귀를 생각해야합니다.

동적 코드는 컴파일 타임을 확인할 수 없으므로 실행 시간까지 오류가 감지되지 않습니다. 잠재적으로 찾기가 더 어려워집니다. 루비의 경우, 이는 IDE 또는 편집자가 구문 오류를 찾지 못한다는 것을 의미합니다. 그것은 Goto를 선택하는 플러스입니다.

이 경우 결정을 내리려면 두 가지를 모두보아야한다고 생각합니다. 코드를 보지 못했지만 동적 코드 또는 Goto 's를 사용하지 않는 좋은 솔루션이 있다고 생각합니다. Goto는 항상 나쁘지는 않지만, 당신이 그것을 사용하려고 생각한다면 아마도이 시점까지 최고의 디자인 결정을 내리지 않았으며 아마도 솔루션을 다시 방문하고 싶을 것입니다.

대학에서의 할당 중 하나에서, 나는 한 번 비교적 비슷한 일을해야했던 솔루션은 재귀 함수를 사용하여 배열, 배열의 크기 및 둥지 레벨을 인수로 전달하는 것이 었습니다. 그런 다음 함수는 중첩 레벨이 배열 크기와 같을 때까지 중첩 레벨 +1로 호출합니다. GOTO, 코드 평가도없고 깨끗한 코드 만!

예시

function computeDerangement(yourArray, loopLevel, arraySize)
{
    //We check to see if the loop level is the same as the array size
    //if true, then we have executed exactly n loop
    if (loopLevel == arraySize) {
         display(yourArray); //Display being some kind of function that show the array,
                             //you get the idea
    } else {
        while(something) {
            //Here you put the logic that you execute at one level of the loop

            //Then you call yourself with one more level of nesting
            computeDerangement(yourArray, loopLevel + 1, arraySize);
        }
    }
}

도움이되기를 바랍니다!

나는 내 인생에서 goto를 사용한 적이 없어서 항상 그들을 피할 수있는 방법이 있다고 확신합니다.

사람들이 GOTO 진술을 피하는 주된 이유는 프로그램을 이해하기 어렵게 만들 수 있기 때문입니다.

당신의 코드를 보지 못했을 때, 나는 goto를 사용하는 동등한 프로그램보다 이해하기가 더 어렵다고 생각합니다 ...

GOTO 솔루션 - 기능 호출을 시뮬레이션 할 때 GOTO가 편리합니다. 다음은 스택과 GOTO 레이블을 사용하여 재귀 솔루션을 단순히 시뮬레이션하여 기능 호출이 발생한 지점으로 돌아가는 비 재생 솔루션입니다.

비교를 위해 재귀 절차 (이것을 별도의 답변으로 게시 함)를 참조하십시오.

옵션에 대한 옵션 옵션 명시 적으로 엄격합니다

모듈 모듈 1 Dim X는 스택으로 Dim X입니다

Private Sub printGeneratedList(ByVal generatedList As List(Of Integer))
    For Each el In generatedList
        Console.Write(el & " ")
    Next
    Console.WriteLine()
End Sub
Private Sub generateAux(ByVal i As Integer, ByVal n As Integer, _
                        ByVal generatedList As List(Of Integer))
    Dim stackI As Stack(Of Integer) = New Stack(Of Integer)
    Dim stackJ As Stack(Of Integer) = New Stack(Of Integer)


    Dim j As Integer

StartLabel :

    j = 0

    If i >= n Then
        printGeneratedList(generatedList)
        If stackI.Count = 0 Then
            Return
        Else
            GoTo ReturnLabel
        End If
    End If

     While j < n
        If Not j = i Then
            If Not generatedList.Contains(j) Then
                generatedList.Add(j)
                stackI.Push(i)
                stackJ.Push(j)
                i = i + 1
                GoTo StartLabel

returnLabel :

                i = stackI.Pop()
                j = stackJ.Pop()
                generatedList.Remove(j)
            End If
        End If
        j = j + 1
    End While
    If stackI.Count = 0 Then
        Return
    Else
        GoTo ReturnLabel
    End If
End Sub

Private Sub generate(ByVal n As Integer)
    Console.WriteLine("Generating for n = " & n.ToString())
    Dim l As List(Of Integer) = New List(Of Integer)
    If n < 0 Then
        Throw New Exception("n must be >= 0")
    End If
    generateAux(0, n, l)
End Sub

Sub Main()
    generate(0)
    Console.ReadLine()
    generate(1)
    Console.ReadLine()
    generate(2)
    Console.ReadLine()
    generate(3)
    Console.ReadLine()
    generate(4)
    Console.ReadLine()
End Sub

끝 모듈

Goto 's는 깨끗하지 않습니다. 그러나 고성능이 필요한 경우, 때때로 코딩 규칙 중 일부를 위반해야합니다 ...

속도가 실제로 중요한 문제 인 경우, 예를 들어 라이브러리 나 코드를 작성하려는 경우 많은 긴급 성이있는 경우 GOTO 사용을 고려할 수 있습니다. 확실히 모든 것이 잘 진행되도록주의를 기울여야합니다.

논평: 결국, 실행 CPU는 단순한 점프 외에는 아무것도하지 않습니다. 프로그래밍 언어 / 컴파일러가 작성하는 것만으로 만 가능합니다. 주의해서 사용하고 엉망이되지 마십시오.

GOTO 솔루션과 동적 코드 생성 아이디어는 모두 나쁩니다. 이것은 다른 사람들이 언급 한 바와 같이 재귀 솔루션으로 쉽게 해결할 수 있습니다. 당신은 단순히 모든 순열 (표준 재귀 솔루션)을 재귀 적으로 생성하고 생성이 완료되면 (즉, 재귀의 잎에서) 단순히 거부하지 않는 반환 순열을 건너 뜁니다.

재귀 솔루션 - 다음은 초기 가지 치기가있는 솔루션입니다. 나의 유일한 질문은 열거에 관한 것입니다. 그는 당신이 각각의 성공적인 통화에서 목록에서 다음 항목을 생성 할 열거자를 만들기를 원했습니까? 이 프로그램의 Lambda 버전을 만들어서 가장 쉬운 구현 일 것입니다. Prolog -Interpreter 스타일 쿼리를 수행 할 때 질문에 대한 다음 답변을 생성 할 쿼리 생성기를 작성할 때 항상 LISP 에서이 작업을 수행했습니다.

옵션에 대한 옵션 옵션 명시 적으로 엄격합니다

모듈 모듈 1

Private Sub printGeneratedList(ByVal generatedList As List(Of Integer))
    For Each el In generatedList
        Console.Write(el & " ")
    Next
    Console.WriteLine()
End Sub

Private Sub generateAux(ByVal i As Integer, ByVal n As Integer, _
                    ByVal generatedList As List(Of Integer))
    If i >= n Then
        printGeneratedList(generatedList)
        Return
    End If
    For j As Integer = 0 To n - 1
        If Not j = i Then
            If Not generatedList.Contains(j) Then
                generatedList.Add(j)
                generateAux(i + 1, n, generatedList)
                generatedList.Remove(j)
            End If
        End If
    Next
End Sub

Private Sub generate(ByVal n As Integer)
    Console.WriteLine("Generating for n = " & n.ToString())
    Dim l As List(Of Integer) = New List(Of Integer)
    If n < 0 Then
        Throw New Exception("n must be >= 0")
    End If
    generateAux(0, n, l)
End Sub

Sub Main()
     generate(0)

    Console.ReadLine()
    generate(1)

    Console.ReadLine()
    generate(2)

    Console.ReadLine()
    generate(3)

    Console.ReadLine()
    generate(4)

    Console.ReadLine()

End Sub

끝 모듈

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top