2013-02-07 23 views
31

Đây là mã số quicksort tôi đã viết. Hàm này không hoạt động vì nó không thể đạt được trường hợp cơ sở. Nếu tôi đăng nhập trục, rl vào bảng điều khiển, chúng vẫn giữ nguyên cho dù chức năng sắp xếp được gọi bao nhiêu lần. Vì vậy, tôi tự hỏi, nếu đối số l, r không thực sự được chuyển vào hàm làm dữ liệu. Tại sao nó lại xảy ra?Truy cập vô hạn trong JavaScript quicksort?

function sort(data){ 
    if(data.length < 2){ 
     return data; 
    } 
    else{ 
     var l = []; 
     var r = []; 
     var pivot = parseInt(data.length/2); 
     for(i=0; i<data.length; i++){ 
      if(data[i] > data[pivot]){ 
       r.push(data[i]); 
      } 
      else{ 
       l.push(data[i]); 
      } 
     } 
     return sort(l).concat(sort(r)); 
    } 
} 
+3

Bạn đang ghi đè l và r mỗi cuộc gọi đệ quy. Bạn nên bắt đầu chúng bên ngoài chức năng sắp xếp của bạn. – marteljn

+0

@marteljn Có. Nhưng nếu tôi đặt console.log (l) trước khi trở về, nó in cùng một mảng.Vì vậy, tôi đang bối rối –

+2

Tôi phải hỏi: Có gì sai với chỉ cần gọi 'originalArray.sort()'? –

Trả lời

327

Tôi nghĩ rằng vấn đề ở đây là bước phân đoạn của bạn không nhất thiết phải thu hẹp mảng đầu vào. Ví dụ, chúng ta hãy theo dõi những gì sẽ xảy ra nếu bạn cố gắng phân loại [1, 2]. Trong trường hợp này, phần tử trục của bạn sẽ là phần tử 2. Vì 1> 2 là sai, 1 được thêm vào danh sách l. Vì 2> 2 là sai, 2 được thêm vào danh sách l. Kết quả là, cuộc gọi đệ quy của bạn trên danh sách l sẽ có chính xác các đối số giống như cuộc gọi ban đầu của bạn, gây ra đệ quy vô hạn.

Để khắc phục điều này, hãy thử tách đầu vào thành ba danh sách - một trong các giá trị nhỏ hơn, một giá trị bằng nhau và một trong các giá trị lớn hơn. Mã này được hiển thị ở đây:

function sort(data){ 
    if (data.length < 2){ 
    return data; 
    } else { 
    var l = []; 
    var r = []; 
    var e = []; 
    var i = 0; 
    var pivot = (data.length/2) | 0; 

    for(i = 0; i < data.length; i++) { 
     if (data[i] > data[pivot]) { 
     r.push(data[i]); 
     } else if (data[i] < data[pivot]) { 
     l.push(data[i]); 
     } else { 
     e.push(data[i]); 
     } 
    } 
    return sort(l).concat(e, sort(r)); 
    } 
} 

Phiên bản mới này một cách rõ ràng nhóm các yếu tố bình đẳng vào danh sách riêng của họ, vì vậy họ không đệ quy được sắp xếp theo một trong hai cuộc gọi đệ quy. Nó cũng xử lý các phần tử trùng lặp một cách duyên dáng.

Hy vọng điều này sẽ hữu ích!

+1

+1. Một chút cải tiến: 'sắp xếp (l) .concat (e, sắp xếp (r));' – Bergi

+1

@ Bergi- Cảm ơn! Tôi không phải là một lập trình viên JS, và tôi không biết rằng bạn có thể làm điều đó. – templatetypedef

+6

gg Randall. Hãy lấy một số thống kê về các cuộc gọi truy cập API đối với thẻ 'sort'? :) –

0

JavaScript chuyển đối tượng theo tham chiếu (mảng cũng là đối tượng). Nếu bạn muốn chuyển chúng theo giá trị, bạn cần sử dụng chức năng ghép nối như được giải thích here.

Lưu ý rằng thao tác này sẽ tạo nhiều bản sao dữ liệu của bạn. Bạn có thể muốn sử dụng hàm sort() gốc.

+1

Tôi không nghĩ đó là vấn đề ở đây. Việc đệ quy vô hạn không phải là do tham chiếu pass-by-by, mà do thực tế là mã gốc không xử lý đúng một trong các trường hợp cần xử lý. – templatetypedef

+0

câu hỏi của bạn không đề cập đến bất kỳ điều gì về đệ quy vô hạn, thay vì các biến không thay đổi ... – nus

1

Nếu bạn chọn giá trị lớn nhất của mảng làm phần tử trục, thì tất cả các giá trị của data sẽ kết thúc trong mảng l và không có trong r. Do đó sẽ làm cho đệ quy không bao giờ dừng lại (và giữ l, rpivot với cùng giá trị). Trừ khi đây là một bài tập về não, sử dụng data.sort() nên làm một công việc tốt hơn. ;)