Bağlantılı bir listede neden hızlı sıralama kullanmıyoruz?


16

Hızlı sıralama algoritması aşağıdaki adımlara ayrılabilir

  1. Pivotu tanımlayın.

  2. Bağlantılı listeyi pivot temelinde bölümlere ayırın.

  3. Bağlantılı listeyi özyinelemeli olarak 2 parçaya bölün.

Şimdi, her zaman pivot olarak son elemanı seçersem, pivot elemanını (1. adım) tanımlamak zaman alır.O(n)

Pivot elemanını tanımladıktan sonra, doğru bölme noktasını (2. adım) tanımlamak için verilerini depolayabilir ve diğer tüm elemanlarla karşılaştırabiliriz. Her karşılaştırma , pivot verilerini sakladığımızda zaman alacak ve her takas zaman alacaktır . Dolayısıyla toplamda n element için O ( n ) zamanı gerekir .O(1)O(1)O(n)n

Yani nüks ilişkisi:

hangi O ( n, log n ) sıralama bağlı bir liste ile birleştirme ile aynı olan.T(n)=2T(n/2)+nO(nlogn)

Peki neden bağlantılı listeler için hızlı sıralama yerine birleştirme sıralama tercih edilir?


İlk yerine pivot olarak son elemanı seçmeye gerek yok
TheCppZoo

Yanıtlar:


19

Quicksort'taki bellek erişim modeli rastgele, aynı zamanda kullanıma hazır uygulama yerinde, bu nedenle hücreler sıralı sonuç elde etmek için birçok takas kullanıyor.
Aynı zamanda birleştirme sıralaması da harici, sıralı sonuç döndürmek için ek dizi gerektirir. Dizide ek alan yükü anlamına gelir, bağlantılı listenin olması durumunda değeri çıkarmak ve düğümleri birleştirmeye başlamak mümkündür. Erişim doğada daha ardışıktır.

Bu nedenle, hızlı sıralama bağlantılı liste için doğal bir seçim değilken birleştirme sıralaması büyük avantaj sağlar.

Landau notasyonu kabul edilebilir (az ya da çok, çünkü Quicksort hala ), ancak sabit çok daha yüksektir.O(n2)

Ortalama durumda, her iki algoritma da bu nedenle asimtotik durum aynıdır, ancak tercih kesinlikle gizli sabitten kaynaklanır ve bazen kararlılık söz konusudur (hızlı sıralama doğal olarak kararsızdır, mergsort istikrarlıdır).O(nlogn)


Ama ortalama zaman karmaşıklığı aynı değil mi? Bağlantılı liste için hızlı sıralama ve birleştirme sıralama özelliğini kullanma.
Zephyr

10
@ Zephyr, karmaşıklık gösteriminin sabit faktörleri düşürdüğünü hatırlamanız gerekir. Evet, bağlantılı bir listede hızlı sıralama ve bağlantılı bir listede birleştirme, aynı karmaşıklık sınıfındadır, ancak görmediğiniz sabitler birleştirme işlemini eşit olarak daha hızlı hale getirir.
Mark

@Zephyr Temel olarak teorik ve ampirik sonuçların farkıdır. Ampirik olarak hızlı sıralama daha hızlıdır.
ferit

1
O(n2)

3
O(logn)

5

O(n)O(n2)

O(1)

264O(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;

Bu, linux çekirdeğinin bağlantılı listelerini sıralamak için kullandığı algoritmadır. previousSon birleştirme işlemi hariç tümü sırasında işaretçiyi yok saymak gibi bazı ekstra optimizasyonlara rağmen .


-2

Sonuçlara sıralama birleştirme, bölme sıralama, ağaç tür yazmak ve karşılaştırabilirsiniz
bazı ekstra alan sağlar eğer sıralama yazma ağacına oldukça kolaydır
tür bağlantılı listenin her düğüm bir nevi tek başına listesini bağlantılı olsa bile iki işaretçiler olmalıdır ağacın İçin
bağlantılı listesinde takas yerine ekleme ve silme tercih
Hoare bölüm sadece iki kez bağlantılı liste için yapılabilir

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.

Bu kod bazı iyileştirmeler gerektiriyor
Öncelikle ekstra depolama alanını özyineleme ihtiyaçları ile sınırlamalıyız,
daha sonra özyinelemeyi yinelemeyle değiştirmeye çalışmalıyız
Eğer algoritmayı daha da geliştirmek istiyorsak, kendi kendini dengeleyen ağaç


Ayrıntılı katkınız için teşekkürler, ancak bu bir kodlama sitesi değil. 200 satır kod, bağlantılı listeler için hızlı sıralama yerine birleştirme sıralamasının neden tercih edildiğini açıklamak için hiçbir şey yapmaz.
David Richerby

Bölümünde Sıralama pivot ilk veya son öğeyle sınırlıdır (kuyruk düğümüne işaretçiyi tutarsak son) aksi takdirde pivot seçimi yavaş Hoare bölümü yalnızca iki kez bağlantılı listeler için mümkündür Sabit faktörü yoksayarsak ağaç çabuk sıralama ile aynı özdeşliğe sahiptir, ancak ağaç türünde en kötü durumdan kaçınmak daha kolaydır Birleştirme sıralaması için yorumda birkaç karakter vardır
Mariusz

-2

Quicksort
Belki quicksort için adımlar göstereceğim

Liste birden fazla düğüm içeriyorsa

  1. Pivot seçimi
  2. Üç alt listeye bölme listesi
    ilk alt liste pivot anahtarından daha az anahtar
    içeren düğümler içerir ikinci alt liste pivot anahtarına eşit anahtarlı
    düğümler içerir üçüncü alt liste pivot anahtarından daha büyük anahtarlı düğümler içerir
  3. Pivot düğüme eşit olmayan düğümler içeren alt listeler için yinelemeli çağrılar
  4. Sıralanan alt listeleri sıralı bir listede birleştirin

Reklam 1. Pivotu
hızlı seçmek istiyorsak seçim sınırlıdır
Baş düğümü veya kuyruk düğümü seçebiliriz
Pivotumuza
hızlı bir şekilde erişilebilir olmasını istiyorsak listemiz düğüme poiner almak zorunda kalır, aksi takdirde düğümü aramamız gerekir

2. Reklam
Bu adım için kuyruk işlemlerini kullanabiliriz
İlk bağlantıyı orijinal bağlantılı listeden kaldırırız.Anahtarını
pivot anahtarıyla karşılaştırır ve düğümü doğru alt
listeye doğru sıralar Alt listeler mevcut düğümlerden oluşturulur ve
yeni düğümler için bellek ayırmaya gerek yoktur

Kuyruk düğümüne işaretçi yararlı olacaktır çünkü kuyruk işlemleri
ve birleştirme bu işaretçinin varlığıyla daha hızlı çalışır


Korkarım bunun soruyu nasıl cevapladığını göremedim.
John L.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.