2011-08-28 36 views
18

Tôi đã thực hiện một thử nghiệm nhỏ và phát hiện ra rằng array.sort(function(a, b) { return a - b; }); nhanh hơn rất nhiều so với array.sort(); trong JavaScript.JavaScript, sắp xếp với thông số thứ hai nhanh hơn

Kết quả khá sốc, nhanh hơn khoảng 1,7 lần trong IE9, 1,6 lần trong FF7 và 6,7 lần trong Chrome.

Ngoài ra, bằng cách thực hiện quicksort một mình trong JS, tôi thấy nó thậm chí còn nhanh hơn cả hai phương pháp được đề cập ở trên. (Hai cách triển khai khác nhau, một hàm chấp nhận hàm so sánh làm tham số, hàm kia không. Cả hai đều nhanh hơn.)

Có giải thích hợp lý nào không?

EDIT: hiện thực của tôi:

Không Comparer:

function quickSort(array, from, to) { 
    if(typeof from === 'undefined') { 
     from = 0; 
     to = array.length - 1; 
    } 
    else if(typeof to === 'undefined') { 
     to = array.length - 1; 
    } 

    if(to - from < 1) { 
     return; 
    } 

    var i = from, pivot = to, t; 

    while(i < pivot) { 
     if(array[i] > array[pivot]) { 
      t = array[i]; 
      array[i] = array[pivot - 1]; 
      array[pivot - 1] = array[pivot]; 
      array[pivot] = t; 
      pivot--; 
     } 
     else { 
      i++; 
     } 
    } 

    quickSort(array, from, pivot - 1); 
    quickSort(array, pivot + 1, to); 
} 

Với Comparer:

function quickSortFunc(array, sortfunc, from, to) { 
    if(typeof from === 'undefined') { 
     from = 0; 
     to = array.length - 1; 
    } 
    else if(typeof to === 'undefined') { 
     to = array.length - 1; 
    } 

    if(to - from < 1) { 
     return; 
    } 

    var i = from, pivot = to, t; 

    while(i < pivot) { 
     if(sortfunc(array[i], array[pivot]) > 0) { 
      t = array[i]; 
      array[i] = array[pivot - 1]; 
      array[pivot - 1] = array[pivot]; 
      array[pivot] = t; 
      pivot--; 
     } 
     else { 
      i++; 
     } 
    } 

    quickSortFunc(array, sortfunc, from, pivot - 1); 
    quickSortFunc(array, sortfunc, pivot + 1, to); 
} 
+0

đó là một khả năng rằng các chức năng sắp xếp được điều hành từ trung bình. Làm thế nào lớn là mảng mà bạn sử dụng? – Matt

+3

Sắp xếp "bình thường" hoạt động trên biểu diễn chuỗi của các phần tử. Đó có thể là một chi phí có thể. –

+0

Matt, tôi đã thử nghiệm nó trên các mảng 100, 1000, 10000 và 100000 phần tử. Felix, tôi mặc dù về hai, nó vẫn không giải thích tại sao việc thực hiện của tôi với một so sánh nhanh hơn so với việc thực hiện bản địa với một so sánh. –

Trả lời

1

Có hai yếu tố mà đi vào chơi:

Thứ nhất, như Felix Vua được đề cập trong các nhận xét, phương thức sắp xếp gốc chuyển đổi từng thành viên mảng thành chuỗi trước khi so sánh. Sử dụng function(a, b) { return a - b; } là cách nhanh hơn nếu tất cả (hoặc hầu hết) thành viên mảng là số.

Thứ hai, thuật toán sắp xếp là implementation dependent. Như bạn có thể hoặc có thể không biết, quicksort thực hiện thực sự xấu nếu bạn chèn một phần tử mới vào một mảng đã được sắp xếp. Có lẽ đó là lý do tại sao WebKit quyết định triển khai Selection Sort thay thế.

Nhưng đừng sợ, giúp đỡ ở gần! Ai đó đã có forked WebKit to fix this

0

Nhiều lý do sẽ được phát. Không phải kiểm tra loại biến là một trong số chúng và chỉ một trong số chúng. Và việc triển khai của bạn làm cho người tối ưu hạnh phúc. Nó hoạt động với các mảng dày đặc, nó chỉ hoạt động với các con số, các biến được sắp xếp và tái sử dụng tốt. Không có điều này, không có, không có eval, không có biến ma thuật, thuộc tính, chức năng hoặc loại. Nó sẽ tối ưu hóa tốt.

Tuy nhiên, nếu bạn đã cố gắng triển khai các phương thức mảng độc lập, độc lập với loại như reverse(), bạn cũng có thể thấy rằng việc triển khai của chính bạn nhanh hơn. Ít nhất là của tôi.

Tại sao?

JavaScript được tối ưu hóa nhiều nhất hiện nay, đặc biệt trên các vòng lặp và hoạt động lặp lại trên cùng một loại nội dung - số, chuỗi, thậm chí các đối tượng có cùng hình dạng (phức tạp). Trong trường hợp cực đoan, thời gian chạy sẽ chuyển nội dung của bạn, sẽ bỏ qua kiểm tra loại biến, và trong trường hợp Chrome, thậm chí sẽ giữ số của bạn trong sổ đăng ký sao cho vòng lặp của bạn có thể nhanh như C.

Wow.

Nhưng những tối ưu hóa này chỉ diễn ra trong những năm gần đây. Tại thời điểm này, các hàm gốc không được tối ưu hóa như mã người dùng. Họ không trải qua nhiều tối ưu hóa động như mã người dùng làm.

Ở đó, tôi đã nói.

Hiện tại, mã người dùng có thể chạy nhanh hơn sau đó thực hiện gốc, đặc biệt vì người lập trình biết luồng dữ liệu nào trong đó.Nhưng điều này có thể là tạm thời.

Tôi sẽ dừng lại ở đây và cho phép bạn quyết định xem bạn có muốn tạo thư viện mảng của riêng mình hay không. ;)

+0

Đó chỉ là một phần của sự thật. Lưu ý rằng hầu hết các phương thức Mảng được cố ý định nghĩa là chung chung, vì vậy chúng phải hoạt động trên các đối tượng không phải là mảng. Nếu việc triển khai của bạn nhanh hơn, có thể là do bạn đã quên một số trường hợp đặc biệt điên rồ. Ví dụ: 'Array.prototype.reverse.call ({'2': '2', '3': '3', chiều dài: '3,5', táo: 'cam'))' hoặc thậm chí 'var a = [] ; a [1] = 1; a.reverse(). hasOwnProperty (1) // false'. Đây là những thứ mà các nhà cung cấp trình duyệt không được tối ưu hóa. Nếu không jQuery sẽ phải làm việc trên một vé khác;) – user123444555621

+0

@ Pumbaa80: Chỉ cần kiểm tra thông số kỹ thuật, nhưng không nhìn thấy những gì cực đoan về ví dụ. Spec cho biết chiều dài, làm cho nó không dấu int, sau đó bắt đầu đảo ngược từ 0 đến length-1. Tôi có thể biết cái cạm bẫy ở đây là gì không? – Sheepy

+0

Tôi chưa thấy triển khai của bạn, nhưng [mỏ (xem xét trường hợp đặc biệt)] (http://jsperf.com/array-reverse) chắc chắn là chậm hơn. – user123444555621

0

Đây là một dự đoán ngẫu nhiên, nhưng hiệu suất có thể xảy ra do sắp xếp gốc, kiểm tra xem các thuộc tính được chuyển là trống hay không ... Do đó tìm kiếm hàm mặc định trên mỗi tìm kiếm (thay vì một lần) ...

Nó có thể là một vấn đề tối ưu hóa nhầm, mà có thể được giải quyết nếu đúng ... Hy vọng rằng ai đó trong firefox dev có thể trả lời này :)

Các vấn đề liên quan