중첩 된 루프에서 벗어나는 방법?


96

break문을 사용하면 내부 루프 만 중단되고 일부 플래그를 사용하여 외부 루프를 중단해야합니다. 그러나 중첩 된 루프가 많으면 코드가 좋지 않습니다.

모든 루프를 끊는 다른 방법이 있습니까? (사용하지 마십시오 goto stmt.)

for(int i = 0; i < 1000; i++) {
   for(int j = 0; j < 1000; j++) {
       if(condition) {
            // both of the loops need to break and control will go to stmt2
       }
   }

}

stmt2

2
루프가 시작되기 전에 int i 및 int j를 시도한 다음 조건에 따라 1001 루프가 다음을 반복하지 않습니다.
Khurram Ijaz

답변:


43

사용하다:

if (condition) {
    i = j = 1000;
    break;
}

49
작동하지만 추악하고 일반적이지 않습니다. 누군가 제한을 2000으로 변경하면 어떻게됩니까 (코드가 더 길어서 즉시 알아 차리지 못함)?
ugoren

1
@ugoren 그럼 너무 간단합니다. const int count =1000 전역 초기화에서 를 사용했다면 어떻게 될까요? 또는 #define매크로로.
Laksith

4
@ugoren이 지적했듯이 일반적인 해결책이 아닙니다. 이 질문에 대한 첫 번째 Google 히트이므로 일반적인 솔루션을 선택했다면 좋을 것입니다. 어쨌든 사람들은 # 2를 확인하는 데 익숙합니다.
BeeOnRope

1
i = 1000 만 필요한 것 같아요?
Peter Wu

189

아니요, break. 이것은 마지막으로 남아있는 유효한 사용입니다 goto.)

그렇지 않은 경우 플래그를 사용하여 깊은 중첩 루프에서 벗어날 수 있습니다.

중첩 루프에서 벗어나는 또 다른 방법은 두 루프를 분리하여 별도의 함수로 분리하고 종료하려는 경우 해당 함수에서 반환하는 것입니다.

요약-중첩 된 루프에서 벗어나려면 :

  1. 사용하다 goto
  2. 플래그 사용
  3. 루프를 별도의 함수 호출로 분해

여기에 xkcd를 포함하여 저항 할 수 없었습니다. :)

여기에 이미지 설명 입력

출처

Goto는 유해한 것으로 간주 되지만 댓글에있는 많은 사람들이 그럴 필요가 없다고 제안합니다. 신중하게 사용하면 훌륭한 도구가 될 수 있습니다. 적당히 사용하는 것은 무엇이든 재미 있습니다.


29
Goto는 당신이 여기에 올 것만 큼 분명합니다. exit 변수를 1000으로 설정하는 것은 훨씬 더 복잡합니다.
correnos

3
나는 gotos가 명시 적으로 악한 것이 아니라 악을 위해 사용될 수 있다는 것을 덧붙이고 싶습니다. 예를 들어 이것이 최상의 솔루션 인 경우가 꽤 많다는 것을 알았습니다. "고토를 사용하지 마십시오"는 좋은 시작이지만, 다음 단계에서는 "장거리 고토를 사용하지 마십시오"라고 생각합니다.
Aatch

1
나는 이것에 동의하지 않는다 : "함수를 생성하면 스택 포인터의 더하기 / 빼기의 기하 급수적 인 양이 발생한다". 프로그램 흐름의 한 지점에서만 호출되는 로컬 (정적) 함수가있는 경우 반 수준의 컴파일러가이를 인라인하고 결과 코드는 본질적으로 goto와 동일합니다. 이것은 아마도 모든 컴파일러에 대한 가장 쉬운 최적화 사례입니다.
DrV

1
리팩토링은 일반적으로 가장 깨끗한 솔루션입니다. 그러나 내부 루프 중에 루프 외부 변수가 변경되면 상황이 복잡해집니다. 한 가지 가능성은 참조 (포인터)를 통해 내부 함수에 변수를 전달하는 것이지만 이로 인해 컴파일러 최적화가 혼동되고 불필요한 추가 코드가 생성 될 수 있습니다. 또 다른 가능성은 이러한 변수를 모듈 수준에서 정적으로 만드는 것입니다.하지만 그다지 아름답지는 않습니다. C는 안타깝게도이 문제를 해결할 수있는 중첩 함수가 누락되어 있습니다. 확장 기능을 제공하는 gcc를 사용하는 데 기꺼이 참여하지 않는 한.
DrV

1
+1. Go to Statements ( wiki.c2.com/?StructuredProgrammingWithGoToStatements ) 를 사용한 Donald E. Knuth의 구조화 프로그래밍 은 Dijkstra의 균형을 맞추는 흥미로운 기사입니다.
kmkaplan

40
bool stop = false;
for (int i = 0; (i < 1000) && !stop; i++)
{
    for (int j = 0; (j < 1000) && !stop; j++)
    {
        if (condition)
            stop = true;
    }
}

해결 방법은 여전히에 의해 두 변수를 증가 휴식 문제가 발생할 수있는
TheSola10

7
"stop = true"로 설정할 수 있습니다. 그리고 "break;". 그런 다음 내부 "for"루프의 끝 바로 뒤에 "if (stop) break;"를 수행합니다.
Jeff Grigg

34

한 가지 방법은 모든 중첩 루프를 함수에 넣고 모든 루프에서 벗어나야 할 경우 가장 안쪽 루프에서 반환하는 것입니다.

function() 
{    
  for(int i=0; i<1000; i++)
  {
   for(int j=0; j<1000;j++)
   {
      if (condition)
        return;
   }
  }    
}

1
것 나를 위해 최고의 솔루션
루카 Steeb

20

나는 goto문제를 해결할 것이라고 생각한다

for(int i = 0; i < 1000; i++) {
    for(int j = 0; j < 1000; i++) {
        if (condition) {
            goto end;
        }
    }
}

end:
stmt2 

@chikuba 나는 cprogramming.com/tutorial/goto.html에서 대답을 얻었고 내가 당신의 게시물을 보지 않는 이유와 같은 일을 할 때 당신의 대답이 게시되지 않습니다
Renjith KN

15

읽을 수 있도록하려면 부울 변수가 필요합니다.

bool broke = false;
for(int i = 0; i < 1000; i++) {
  for(int j = 0; j < 1000; i++) {
    if (condition) {
      broke = true;
      break;
    }
  }
  if (broke)
    break;
}

덜 읽기 원한다면 부울 평가에 참여할 수 있습니다.

bool broke = false;
for(int i = 0; i < 1000 && !broke; i++) {
  for(int j = 0; j < 1000; i++) {
    if (condition) {
      broke = true;
      break;
    }
  }
}

궁극적 인 방법으로 초기 루프를 무효화 할 수 있습니다.

for(int i = 0; i < size; i++) {
  for(int j = 0; j < 1000; i++) {
    if (condition) {
      i = size;
      break;
    }
  }
}


4

주의 :이 답변은 정말 모호한 구조를 보여줍니다.

GCC를 사용하는 경우이 라이브러리를 확인하십시오 . PHP와 마찬가지로 break종료하려는 중첩 루프 수를 허용 할 수 있습니다. 다음과 같이 작성할 수 있습니다.

for(int i = 0; i < 1000; i++) {
   for(int j = 0; j < 1000; j++) {
       if(condition) {
            // break two nested enclosing loops
            break(2);
       }
   }
}

그리고 후드가 참으로 사용goto :
jacobq

@ iX3 도움이된다면 인라인 어셈블러와 jmp 명령어를 사용할 수 있습니다.
DaBler

@DaBler, 당신이 그 도서관의 저자라는 것을 몰랐습니다. 내 의견은 피드백이 아니라이 라이브러리가 수락 된 답변 과 동일한 방법을 사용한다는 점에 주목했습니다 . 언어 기능 (심지어 goto) 을 사용하는 것이 asm을 인라인하는 것이 훨씬 바람직 하다고 생각하기 때문에 귀하의 의견이 농담으로 의미 되었기 를 바랍니다.
jacobq

3
for(int i = 0; i < 1000; i++) {
   for(int j = 0; j < 1000; i++) {
       if(condition) {
            goto end;
   }
} 

end:

3

i와 j의 값이 필요하면 작동하지만 다른 것보다 성능이 떨어집니다.

for(i;i< 1000; i++){    
    for(j; j< 1000; j++){
        if(condition)
            break;
    }
    if(condition) //the same condition
        break;
}

조건이 종속 된 경우 조건 j의 값이 계속 작동하려면 어떤 방식 으로든 저장해야합니다.
SuperBiasedMan

1
당신 말이 맞지만 break 후에 j 의 값은 변하지 않고 조건의 값도 변하지 않습니다.
Ali Eren Çelik 2015-06-04

이것은 깨진 솔루션이며 일반적으로 유효하지 않습니다. 어느 J는 루프 밖에 정의되지 않거나 for (int i = 0; i < 1000; i++) { for (int j = 0; j < 1000; j++) { if (workComplete[i][j]) break; /* do work */ workComplete[i][j] = true; } if (workComplete[i][j]) break; ... }하려고 항상 내부 루프의 첫 번째 반복 후에, 외부 루프의 탈출.
Chai T. Rex

-3
int i = 0, j= 0;

for(i;i< 1000; i++){    
    for(j; j< 1000; j++){
        if(condition){
            i = j = 1001;
            break;
        }
    }
}

두 루프를 모두 끊습니다.


-3
for(int i = 0; i < 1000; i++) {
    for(int j = 0; j < 1000; i++) {
       if(condition) {
          func(para1, para2...);
          return;
       }
    }
}

func(para1, para2...) {
    stmt2;
}

그래서 기본적으로 (1) 많은 추가 함수 호출을 한 다음 (2) 나머지 시간 동안 condition거짓이 될 때 회전해야한다고 말하는 것입니다 . 이 증가하기 때문에 아, 그리고 두 번째 루프는 영원히 실행됩니다 i대신 j으악 ...
jacobq

-4
i = 0;

do
{
  for (int j = 0; j < 1000; j++) // by the way, your code uses i++ here!
  {
     if (condition)
     {
       break;
     }
  }

  ++i;

} while ((i < 1000) && !condition);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.