Tại sao chúng ta không sử dụng sắp xếp nhanh trong danh sách được liên kết?


16

Thuật toán sắp xếp nhanh có thể được chia thành các bước sau

  1. Xác định trục.

  2. Phân vùng danh sách liên kết dựa trên trục.

  3. Chia danh sách liên kết đệ quy thành 2 phần.

Bây giờ, nếu tôi luôn chọn phần tử cuối cùng làm trục, thì việc xác định phần tử trục (bước 1) sẽ mất thời gian Ôi(n) .

Sau khi xác định phần tử trục, chúng ta có thể lưu trữ dữ liệu của nó và so sánh nó với tất cả các phần tử khác để xác định điểm phân vùng chính xác (bước thứ 2). Mỗi so sánh sẽ mất khi chúng tôi lưu trữ dữ liệu trục và mỗi lần hoán đổi mất thời gian. Vì vậy, tổng cộng phải mất thời gian cho phần tử.O ( 1 ) O ( n ) nÔi(1)Ôi(1)Ôi(n)n

Vì vậy, mối quan hệ tái phát là:

T(n)= =2T(n/2)+n là giống như trong sắp xếp hợp nhất với một danh sách được liên kết.Ôi(nđăng nhậpn)

Vậy tại sao sắp xếp hợp nhất lại được ưu tiên hơn sắp xếp nhanh cho các danh sách được liên kết?


Không cần phải chọn phần tử cuối cùng làm trục thay vì phần tử đầu tiên
TheCppZoo

Câu trả lời:


19

Mẫu truy cập bộ nhớ trong Quicksort là ngẫu nhiên, cũng là triển khai bên ngoài hộp, vì vậy nó sử dụng nhiều giao dịch hoán đổi nếu các ô để đạt được kết quả theo thứ tự.
Đồng thời sắp xếp hợp nhất là bên ngoài, nó yêu cầu mảng bổ sung để trả về kết quả đã ra lệnh. Trong mảng, nó có nghĩa là chi phí không gian bổ sung, trong trường hợp nếu danh sách được liên kết, có thể kéo giá trị ra và bắt đầu hợp nhất các nút. Việc truy cập là tuần tự hơn trong tự nhiên.

Bởi vì điều này, quicksort không phải là sự lựa chọn tự nhiên cho danh sách được liên kết trong khi sắp xếp hợp nhất có lợi thế lớn.

Ký hiệu Landau có thể (ít nhiều, bởi vì Quicksort vẫn là ) đồng ý, nhưng hằng số cao hơn nhiều.Ôi(n2)

Trong trường hợp trung bình, cả hai thuật toán đều ở nên trường hợp tiệm cận là như nhau, nhưng ưu tiên hoàn toàn là do hằng số ẩn và đôi khi sự ổn định là vấn đề (quicksort vốn không ổn định, sáp nhập ổn định).Ôi(nđăng nhậpn)


Nhưng độ phức tạp thời gian trung bình là như nhau phải không? Sử dụng sắp xếp nhanh chóng cũng như sắp xếp hợp nhất cho danh sách liên kết.
Zephyr

10
@Zephyr, bạn cần nhớ rằng ký hiệu phức tạp giảm các yếu tố không đổi. Có, quicksort trong danh sách được liên kết và sáp nhập trong danh sách được liên kết là cùng một lớp phức tạp, nhưng những hằng số mà bạn không thấy làm cho sự hợp nhất nhanh hơn.
Đánh dấu

@Zephyr Về cơ bản đó là sự khác biệt của kết quả lý thuyết và thực nghiệm. Theo kinh nghiệm, quicksort nhanh hơn.
men

1
Ôi(n2)

3
Ôi(đăng nhậpn)

5

Ôi(n)Ôi(n2)

Ôi(1)

264Ôi(1)

head = list.head;
head_array = array of 64 nulls

while head is not null
    current = head;
    head = head.next;
    current.next = null;
    for(i from 0 to 64)
        if head_array[i] is null
            head_array[i] = current;
            break from for loop;
        end if
        current = merge_lists(current, array[i]);
        head_array[i] = null;
     end for
end while

current = null;
for(i from 0 to 64)
    if head_array[i] is not null
        if current is not null
            current = merge_lists(current, head_array[i]);
        else
            current = head_array[i];
        end if
     end if
 end for

 list.head = current;

Đây là thuật toán mà kernel linux sử dụng để sắp xếp các danh sách được liên kết của nó. Mặc dù với một số tối ưu hóa bổ sung như bỏ qua previouscon trỏ trong tất cả nhưng hoạt động hợp nhất cuối cùng.


-2

Bạn có thể viết merge sort, phân vùng sắp xếp, cây sắp xếp và so sánh kết quả
Nó là khá dễ dàng để cây ghi loại nếu bạn cho phép thêm một số không gian
Đối với cây loại mỗi nút của danh sách liên kết phải có hai con trỏ thậm chí nếu chúng ta loại đơn lẻ liên kết danh sách
Trong danh sách liên kết tôi thích chèn và xóa thay vì hoán đổi
phân vùng Hoare chỉ có thể được thực hiện cho danh sách liên kết đôi

program untitled;


type TData = longint;
     PNode = ^TNode;
     TNode = record
                data:TData;
                prev:PNode;
                next:PNode;
             end;

procedure ListInit(var head:PNode);
begin
  head := NIL;
end;

function ListIsEmpty(head:PNode):boolean;
begin
  ListIsEmpty := head = NIL;
end;

function ListSearch(var head:PNode;k:TData):PNode;
var x:PNode;
begin
  x := head;
  while (x <> NIL)and(x^.data <> k)do
     x := x^.next;
  ListSearch := x;
end;

procedure ListInsert(var head:PNode;k:TData);
var x:PNode;
begin
  new(x);
  x^.data := k;
  x^.next := head;
  if head <> NIL then
     head^.prev := x;
   head := x;
   x^.prev := NIL;
end;

procedure ListDelete(var head:PNode;k:TData);
var x:PNode;
begin
   x := ListSearch(head,k);
   if x <> NIL then
   begin
     if x^.prev <> NIL then
        x^.prev^.next := x^.next
      else 
        head := x^.next;
     if x^.next <> NIL then
        x^.next^.prev := x^.prev;
     dispose(x);
   end;
end;

procedure ListPrint(head:PNode);
var x:PNode;
    counter:longint;
begin
  x := head;
  counter := 0;
  while x <> NIL do
  begin
    write(x^.data,' -> ');
    x := x^.next;
    counter := counter + 1;
  end;
  writeln('NIL');
  writeln('Liczba elementow listy : ',counter);
end;

procedure BSTinsert(x:PNode;var t:PNode);
begin
  if t = NIL then
    t := x
  else
    if t^.data = x^.data then
            BSTinsert(x,t^.prev)
        else if t^.data < x^.data then
            BSTinsert(x,t^.next)
        else
            BSTinsert(x,t^.prev);
end;

procedure BSTtoDLL(t:PNode;var L:PNode);
begin
   if t <> NIL then
   begin
     BSTtoDLL(t^.next,L);
     ListInsert(L,t^.data);
     BSTtoDLL(t^.prev,L);
   end;
end;

procedure BSTdispose(t:PNode);
begin
   if t <> NIL then
   begin
    BSTdispose(t^.prev);
    BSTdispose(t^.next);
    dispose(t);
   end; 
end;

procedure BSTsort(var L:PNode);
var T,S:PNode;
    x,xs:PNode;
begin
  T := NIL;
  S := NIL;
  x := L;
  while x <> NIL do
  begin
    xs := x^.next;
    x^.prev := NIL;
    x^.next := NIL;
    BSTinsert(x,t);
    x := xs;
  end;
  BSTtoDLL(T,S);
  BSTdispose(T);
  L := S;
end;

var i : byte;
    head:PNode;
    k:TData;
BEGIN
  ListInit(head);
  repeat
     writeln('0. Wyjscie');
     writeln('1. Wstaw element na poczatek listy');
     writeln('2. Usun element listy');
     writeln('3. Posortuj elementy drzewem binarnym');
     writeln('4. Wypisz elementy  listy');
     readln(i);
     case i of
     0:
     begin
       while not ListIsEmpty(head) do
            ListDelete(head,head^.data);
     end;
     1:
     begin
       writeln('Podaj element jaki chcesz wstawic');
       readln(k);
       ListInsert(head,k);
     end;
     2:
     begin
       writeln('Podaj element jaki chcesz usunac');
       readln(k);
       ListDelete(head,k);
     end;
     3:
     begin
       BSTsort(head);
     end;
     4:
     begin
        ListPrint(head);    
     end
     else
        writeln('Brak operacji podaj inny numer');
     end;
  until i = 0;  
END.

Mã này cần một số cải tiến
Trước tiên, chúng ta nên hạn chế lưu trữ bổ sung cho nhu cầu đệ quy
sau đó chúng ta nên cố gắng thay thế đệ quy bằng phép lặp
Nếu muốn cải thiện thuật toán hơn nữa, chúng ta nên sử dụng cây tự cân bằng


Cảm ơn sự đóng góp chi tiết của bạn nhưng đây không phải là một trang web mã hóa. 200 dòng mã không làm gì để giải thích tại sao sắp xếp hợp nhất được ưu tiên hơn sắp xếp nhanh cho các danh sách được liên kết.
David Richerby

Trong phân vùng Sắp xếp chọn trục được giới hạn ở phần tử đầu tiên hoặc cuối cùng (cuối cùng nếu chúng ta giữ con trỏ đến nút đuôi) nếu không chọn trục là chậm Phân vùng Hoare chỉ có thể cho các danh sách được liên kết gấp đôi Hoán đổi nên được thay thế bằng cách chèn và xóa Sắp xếp cây với không cân bằng cây có cùng độ tương tự như quicksort nếu chúng ta bỏ qua yếu tố không đổi nhưng sẽ dễ tránh trường hợp xấu nhất trong sắp xếp cây Để sắp xếp hợp nhất có một vài ký tự trong bình luận
Mariusz

-2

Quicksort
Có lẽ tôi sẽ chỉ ra các bước cho quicksort

Nếu danh sách chứa nhiều hơn một nút

  1. Lựa chọn Pivot
  2. Danh sách phân vùng thành ba danh sách phụ Danh sách phụ
    thứ nhất chứa các nút có khóa nhỏ hơn
    danh sách phụ danh sách phụ khóa thứ hai chứa các nút có khóa bằng
    danh sách phụ danh sách khóa thứ ba chứa các nút có khóa lớn hơn khóa trục
  3. Các cuộc gọi đệ quy cho danh sách con chứa các nút không bằng nút trục
  4. Ghép các danh sách con được sắp xếp vào một danh sách được sắp xếp

Quảng cáo 1.
Nếu chúng tôi muốn chọn trục nhanh, sự lựa chọn bị hạn chế
Chúng tôi có thể chọn nút đầu hoặc nút đuôi
Danh sách của chúng tôi phải có poiner cho nút nếu chúng tôi muốn trục của chúng tôi
có thể truy cập nhanh nếu không chúng tôi phải tìm kiếm nút

Quảng cáo 2.
Chúng tôi có thể sử dụng các thao tác xếp hàng cho bước này
Fist chúng tôi loại bỏ nút từ danh sách được liên kết ban đầu
so sánh khóa của nó với khóa trục và nút enqueue với danh sách phụ chính xác
được tạo từ các nút hiện có và không cần
phân bổ bộ nhớ cho các nút mới

Con trỏ tới nút đuôi sẽ hữu ích vì các hoạt động hàng đợi
và nối được chạy nhanh hơn với sự hiện diện của con trỏ này


Tôi sợ rằng tôi không thể thấy làm thế nào điều này trả lời câu hỏi.
Apass.Jack
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.