최대가 정렬보다 느린 이유는 무엇입니까?


92

나는 그것이 파이썬 2와 3 max의 sort함수 보다 느리다 는 것을 발견했습니다 .

파이썬 2

$ python -m timeit -s 'import random;a=range(10000);random.shuffle(a)' 'a.sort();a[-1]'
1000 loops, best of 3: 239 usec per loop
$ python -m timeit -s 'import random;a=range(10000);random.shuffle(a)' 'max(a)'        
1000 loops, best of 3: 342 usec per loop

파이썬 3

$ python3 -m timeit -s 'import random;a=list(range(10000));random.shuffle(a)' 'a.sort();a[-1]'
1000 loops, best of 3: 252 usec per loop
$ python3 -m timeit -s 'import random;a=list(range(10000));random.shuffle(a)' 'max(a)'
1000 loops, best of 3: 371 usec per loop

( )이 함수 ( ) 보다 느린 이유 는 무엇 입니까?maxO(n)sortO(nlogn)


3
Python 2 분석을 한 번 실행했는데 Python 3 코드가 정확히 동일합니다.
— erip

9
a.sort()제자리에서 작동합니다. 시도sorted(a)
— 안드레아 Corbellini에게

문제를 해결했다면 문제를 해결하기 위해 무엇을했는지 다시 게시 해주세요.
— Pretzel

4
@Pretzel OP는 문제가 수정 된 것이 아니라 게시물이 수정되었음을 의미합니다.
— erip

2
@WeizhongTu하지만 sort다음 종류의, 그리고 a영원히 정렬
— njzk2

답변:


125

timeit파이썬 에서 모듈을 사용할 때 매우 조심해야합니다 .

python -m timeit -s 'import random;a=range(10000);random.shuffle(a)' 'a.sort();a[-1]'

여기서 초기화 코드는 무작위 배열을 생성하기 위해 한 번 실행됩니다. a . 그런 다음 나머지 코드가 여러 번 실행됩니다. 처음에는 배열을 정렬하지만 다른 때마다 이미 정렬 된 배열에서 정렬 메서드를 호출합니다. 가장 빠른 시간 만 반환되므로 Python이 이미 정렬 된 배열을 정렬하는 데 걸리는 시간을 실제로 측정합니다.

파이썬의 정렬 알고리즘의 일부는 배열이 이미 부분적으로 또는 완전히 정렬되었는지 감지하는 것입니다. 완전히 정렬되면이를 감지하기 위해 어레이를 한 번만 스캔 한 다음 중지합니다.

대신 시도한 경우 :

python -m timeit -s 'import random;a=range(100000);random.shuffle(a)' 'sorted(a)[-1]'

그런 다음 정렬은 모든 타이밍 루프에서 발생하며 배열을 정렬하는 데 걸리는 시간이 단순히 최대 값을 찾는 것보다 훨씬 길다는 것을 알 수 있습니다.

편집 : @skyking의 대답 은 내가 설명하지 않은 부분을 설명합니다 a.sort(). 목록에서 작업 중이므로 요소에 직접 액세스 할 수 있습니다. max(a)임의의 이터 러블에서 작동하므로 일반 이터 레이션을 사용해야합니다.


10
잘 잡았습니다. 인터프리터 상태가 코드 실행 동안 유지된다는 것을 결코 깨달았습니다. 이제 나는 과거에 얼마나 많은 잘못된 벤치 마크를 만들 었는지 궁금합니다. :-}
— Frerich Raabe

1
저에게는 그 정도가 분명했습니다. 그러나 이미 정렬 된 배열을 정렬하더라도 모든 요소를 ​​확인해야합니다. 그것은 최대를 얻는 것만큼이나 많은 일입니다 .... 나에게 이것은 절반의 대답처럼 보입니다.
— Karoly Horvath

2
@KarolyHorvath, 당신이 맞습니다. @skyking이 답의 나머지 절반을 얻었다 고 생각 a.sort()합니다. 목록에서 작업 중이므로 요소에 직접 액세스 할 수 있습니다. max(a)일반 반복을 사용하지 않도록 임의의 시퀀스에서 작동합니다.
— Duncan

1
@KarolyHorvath 어쩌면 분기 예측은 왜 반복적으로 정렬 된 배열을 정렬 설명 할 수있는 것은 빠르다 : stackoverflow.com/a/11227902/4600
— marcospereira

1
@JuniorCompressor listsort.txt는 "많은 종류의 부분적으로 정렬 된 배열에서 초자연적 인 성능을 제공합니다 (LG (N!) 비교가 필요하지 않고 N-1만큼 적음)"라고 설명하고 계속해서 모든 종류의 최적화를 설명합니다. 나는 그것이 max불가능한 많은 가정을 할 수 있다고 생각합니다 . 즉, 정렬이 점근 적으로 더 빠르지 않습니다.
— Frerich Raabe

87

먼저 max()반복자 프로토콜 을 사용하고 list.sort()임시 코드 를 사용합니다 . 분명히 반복자를 사용하는 것은 중요한 오버 헤드이므로 타이밍의 차이를 관찰하는 것입니다.

그러나 그 외에는 테스트가 공정하지 않습니다. a.sort()동일한 목록에서 두 번 이상 실행 중 입니다. 파이썬 사용 알고리즘 특히 빠른 이미 용으로 설계된다 (부분적) 데이터를 분류. 테스트에 따르면 알고리즘이 제대로 작동하고 있습니다.

다음은 공정한 테스트입니다.

$ python3 -m timeit -s 'import random;a=list(range(10000));random.shuffle(a)' 'max(a[:])'
1000 loops, best of 3: 227 usec per loop
$ python3 -m timeit -s 'import random;a=list(range(10000));random.shuffle(a)' 'a[:].sort()'
100 loops, best of 3: 2.28 msec per loop

여기에서는 매번 목록의 복사본을 만듭니다. 보시다시피 결과의 크기는 우리가 예상하는대로 마이크로 초와 밀리 초로 다릅니다.

그리고 기억하세요 : big-Oh는 상한을 지정합니다! 파이썬 정렬 알고리즘의 하한은 Ω ( n )입니다. O ( n log n )이된다고해서 모든 실행이 n log n에 비례하는 시간이 걸린다는 것을 자동으로 의미하지는 않습니다 . 그것은 O ( n ) 알고리즘 보다 느려 야한다는 것을 의미조차하지 않지만 그것은 또 다른 이야기입니다. 이해해야 할 중요한 것은 일부 유리한 경우 O ( n log n ) 알고리즘이 O ( n ) 시간 이하로 실행될 수 있다는 것 입니다.


31

이는 while l.sort의 멤버 가 일반 함수 이기 때문일 수 있습니다 . 이것은 while 의 내부 표현에 의존 할 수 있다는 것을 의미 하며 일반 반복기 프로토콜을 거쳐야합니다.listmaxl.sortlistmax

이것은 각 요소 가져 오기가 수행하는 각 요소 가져 오기 l.sort보다 빠릅니다 max.

대신 사용 sorted(a)하면 결과가 max(a).


5
그 가정은 좀 더 구체적이되기까지 한 줄의 시간 일뿐입니다. 당신의 지식에 의문을 제기하지 않고, 그러한 추가는 그것을 모르는 사람들의 시연에 사소한 것입니다.
— Reti43

sorted(a)보다 느린 것이 맞습니다 max(a). 당연히 그것은와 거의 같은 속도 a.sort()이지만 그렇지 않은 이유에 대한 귀하의 추측입니다. OP가 허용 된 답변에서 지적한대로 테스트에서 실수를했기 때문입니다.
— martineau

요점은 일반 반복기 프로토콜이 log(n)복잡성 요소 를 상쇄하기에 충분한 오버 헤드를 가질 가능성이 있다는 것입니다 . 즉, O(n)알고리즘은 O(nlogn)충분히 큰 알고리즘 보다 빠르다는 것이 보장됩니다 n(예를 들어 각 작업에 대한 시간이 알고리즘마다 다를 nlogn수 있으므로 빠른 단계가 n느린 단계 보다 빠를 수 있음 ). 이 경우 손익분기 점이 정확히 어디에 있는지는 고려되지 않았습니다 (그러나 log n작은 요소에 대해서는 그 요소가 그다지 큰 요소가 아님을 알아야합니다 n).
— skyking
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.