Tại sao max chậm hơn sắp xếp?


92

Tôi thấy rằng hàm maxnày chậm hơn sorthàm trong Python 2 và 3.

Python 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

Python 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

Tại sao max ( O(n)) chậm hơn so với các sortchức năng ( O(nlogn))?


3
Bạn đã chạy phân tích Python 2 một lần và mã Python 3 hoàn toàn giống nhau.
erip

9
a.sort()hoạt động tại chỗ. Hãy thửsorted(a)
Andrea Corbellini

Nếu bạn đã sửa nó, hãy đăng lại những gì bạn đã làm để sửa nó, xin vui lòng.
Pretzel

4
@Pretzel OP có nghĩa là bài đăng đã được chỉnh sửa, không phải là sự cố đã được khắc phục.
erip

2
@WeizhongTu nhưng sortcác loại, và sau đó ađược sắp xếp mãi mãi
njzk2

Câu trả lời:


125

Bạn phải rất cẩn thận khi sử dụng timeitmô-đun trong Python.

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

Ở đây mã khởi tạo chạy một lần để tạo ra một mảng ngẫu nhiên a. Sau đó, phần còn lại của mã được chạy nhiều lần. Lần đầu tiên nó sắp xếp mảng, nhưng mọi lần bạn đang gọi phương thức sắp xếp trên một mảng đã được sắp xếp. Chỉ thời gian nhanh nhất được trả về, vì vậy bạn thực sự đang tính thời gian Python mất bao lâu để sắp xếp một mảng đã được sắp xếp.

Một phần của thuật toán sắp xếp của Python là phát hiện khi nào mảng đã được sắp xếp một phần hoặc hoàn toàn. Khi được sắp xếp hoàn toàn, nó chỉ cần quét một lần qua mảng để phát hiện điều này và sau đó nó dừng lại.

Nếu thay vào đó bạn đã thử:

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

thì việc sắp xếp xảy ra trên mọi vòng lặp thời gian và bạn có thể thấy rằng thời gian để sắp xếp một mảng thực sự lâu hơn nhiều so với việc chỉ tìm giá trị lớn nhất.

Chỉnh sửa: Câu trả lời của @ skyking giải thích phần tôi không giải thích được: a.sort()biết rằng nó đang hoạt động trên một danh sách để có thể truy cập trực tiếp vào các phần tử. max(a)hoạt động trên bất kỳ tệp nào có thể lặp lại tùy ý nên phải sử dụng phép lặp chung.


10
Nắm bắt tốt. Tôi chưa bao giờ nhận ra rằng trạng thái trình thông dịch được giữ lại qua các lần chạy mã. Bây giờ tôi tự hỏi tôi đã tạo ra bao nhiêu điểm chuẩn bị lỗi trong quá khứ. : -}
Frerich Raabe

1
Điều đó đã quá rõ ràng đối với tôi. Nhưng lưu ý rằng ngay cả khi bạn sắp xếp một mảng đã được sắp xếp, bạn phải kiểm tra tất cả các phần tử. Điều này cũng giống như việc đạt được mức tối đa .... Đối với tôi, điều này giống như một câu trả lời nửa vời.
Karoly Horvath

2
@KarolyHorvath, bạn đã đúng. Tôi nghĩ rằng @skyking đã có một nửa câu trả lời còn lại: a.sort()biết rằng nó đang hoạt động trên một danh sách để có thể truy cập trực tiếp các phần tử. max(a)hoạt động trên một trình tự tùy ý để có sử dụng lặp lại chung chung.
Duncan

1
@KarolyHorvath có thể dự đoán chi nhánh có thể giải thích tại sao nhiều lần sắp xếp một mảng được sắp xếp nhanh: stackoverflow.com/a/11227902/4600
marcospereira

1
@JuniorCompressor listsort.txtgiải thích "Nó có hiệu suất siêu phàm trên nhiều loại mảng có thứ tự một phần (cần ít hơn lg (N!) So sánh và ít như N-1)" và sau đó tiếp tục giải thích tất cả các loại tối ưu hóa gory. Tôi cho rằng nó có thể tạo ra rất nhiều giả định mà maxkhông thể, tức là sắp xếp không tiệm cận nhanh hơn.
Frerich Raabe

87

Trước hết, hãy lưu ý rằng max()sử dụng giao thức trình lặp , trong khi list.sort()sử dụng mã ad-hoc . Rõ ràng, sử dụng trình lặp là một chi phí quan trọng, đó là lý do tại sao bạn đang quan sát sự khác biệt đó về thời gian.

Tuy nhiên, bên cạnh đó, các bài kiểm tra của bạn không công bằng. Bạn đang chạy a.sort()trên cùng một danh sách nhiều lần. Các thuật toán được sử dụng bởi Python được thiết kế đặc biệt để được nhanh chóng cho rồi (một phần) được sắp xếp dữ liệu. Các thử nghiệm của bạn cho thấy rằng thuật toán đang hoạt động tốt.

Đây là những bài kiểm tra công bằng:

$ 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

Ở đây, tôi luôn tạo một bản sao của danh sách. Như bạn có thể thấy, thứ tự độ lớn của các kết quả là khác nhau: micro so với mili giây, như chúng ta mong đợi.

Và hãy nhớ: big-Oh chỉ định giới hạn trên! Giới hạn dưới cho thuật toán sắp xếp của Python là Ω ( n ). Là O ( n log n ) không tự động ngụ ý rằng mỗi lần chạy mất thời gian tỷ lệ với n log n . Nó thậm chí không ngụ ý rằng nó cần phải chậm hơn thuật toán O ( n ), nhưng đó là một câu chuyện khác. Điều quan trọng cần hiểu là trong một số trường hợp thuận lợi, thuật toán O ( n log n ) có thể chạy trong khoảng thời gian O ( n ) trở xuống.


31

Điều này có thể là vì l.sortlà một thành viên của listwhile maxlà một hàm chung. Điều này có nghĩa là l.sortcó thể dựa vào biểu diễn nội bộ của listwhile maxsẽ phải thông qua giao thức trình lặp chung.

Điều này làm cho mỗi phần tử tìm nạp l.sortnhanh hơn mỗi phần tử tìm nạp max.

Tôi giả sử rằng nếu bạn sử dụng thay vào đó sorted(a)bạn sẽ nhận được kết quả chậm hơn max(a).


5
Giả định đó chỉ còn một thời gian ngắn nữa là trở nên cụ thể hơn. Không đặt câu hỏi về kiến ​​thức của bạn, chỉ rằng một bổ sung như vậy là tầm thường đối với sự chứng minh của những người không biết nó.
Nghỉ hưu 43

Bạn đúng sorted(a)là chậm hơn max(a). Không có gì đáng ngạc nhiên là nó có cùng tốc độ a.sort(), nhưng phỏng đoán của bạn về lý do tại sao thì không - đó là do OP đã mắc lỗi trong thử nghiệm của họ như đã chỉ ra trong câu trả lời được chấp nhận.
martineau

Vấn đề là có khả năng giao thức trình lặp chung có đủ chi phí để bù đắp log(n)yếu tố về độ phức tạp. Đó là một O(n)thuật toán chỉ được đảm bảo là nhanh hơn một O(nlogn)thuật toán đủ lớn n(ví dụ: vì thời gian cho mỗi hoạt động có thể khác nhau giữa các thuật toán - nlognbước nhanh có thể nhanh hơn nbước chậm). Chính xác nơi hòa vốn không được xem xét trong trường hợp này (nhưng người ta cần lưu ý rằng log nyếu tố này không phải là yếu tố quá lớn đối với cá nhỏ n).
vọt
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.