dlaczego sortowanie scalające jest preferowane niż szybkie sortowanie do sortowania połączonych list

Przeczytałem na forum:

Sortowanie scalające jest bardzo efektywne dla niezmienne struktury danych, takie jak połączone listy

I

Szybkie sortowanie jest zazwyczaj szybsze niż sortowanie scalające, gdy dane są przechowywane w pamięć. Jednak gdy zbiór danych jest ogromny i jest przechowywany na urządzeniach zewnętrznych takich jak dysk twardy, sortowanie scalające jest wyraźnym zwycięzcą pod względem prędkości. Informatyka minimalizuje kosztowne odczyty napęd zewnętrzny

I

Podczas pracy na listach połączonych, sortowanie scalające wymaga tylko niewielkiej stałej ilości dodatkowego magazynu

Czy ktoś może mi pomóc zrozumieć powyższy argument? dlaczego sortowanie merge jest preferowane do sortowania dużych połączonych list? a jak zminimalizować kosztowne odczyty na zewnętrznym dysku? zasadniczo chcę zrozumieć, dlaczego można wybrać sortowanie merge do sortowania dużej połączonej listy.

Author: maxpayne, 2011-03-07

3 answers

Szybkie sortowanie działa dobrze do sortowania w miejscu. W szczególności większość operacji może być zdefiniowana w kategoriach zamiany par elementów w tablicy. Aby to zrobić, zwykle "przechodzisz" przez tablicę za pomocą dwóch wskaźników (lub indeksów itp.) Jeden zaczyna się na początku tablicy, a drugi na końcu. Oba następnie działają w kierunku środka (i skończysz z konkretnym krokiem partycji, gdy się spotkają). To jest drogie z plikami, Ponieważ pliki są zorientowane przede wszystkim w kierunku czytania w jednym kierunku, od początku do końca. Zaczynanie od końca i szukanie do tyłu jest zwykle stosunkowo drogie.

Przynajmniej w najprostszym wcieleniu, sortowanie scalające jest prawie odwrotnie. Łatwy sposób implementacji wymaga tylko przeglądania danych w jednym kierunku, , ale polega na rozbiciu danych na dwa oddzielne kawałki, sortowaniu kawałków, a następnie łączeniu ich z powrotem.

Z linkowaną listą łatwo jest wziąć (na przykład) elementy naprzemienne w jednej połączonej liście i manipulować łączami, aby utworzyć dwie połączone listy z tych samych elementów zamiast. W przypadku tablicy, przestawianie elementów tak, aby przemienne elementy trafiały do oddzielnych tablic jest łatwe, jeśli chcesz utworzyć kopię tak dużą jak oryginalne dane, ale poza tym bardziej nietrywialną.

Podobnie Scalanie z tablicami jest łatwe, jeśli scalasz elementy z tablic źródłowych w nową tablicę z danymi w kolejności -- ale aby zrobić to w miejscu bez tworzenia zupełnie nowa kopia danych to zupełnie inna historia. W przypadku listy połączonej łączenie elementów z dwóch list źródłowych w jedną listę docelową jest banalne - ponownie, po prostu manipulujesz linkami, bez kopiowania elementów.

Jeśli chodzi o używanie Quicksort do tworzenia posortowanych przebiegów dla zewnętrznego sortowania scalonego, to działa, ale jest (zdecydowanie) nieoptymalne z reguły. Aby zoptymalizować sortowanie scalające, Zwykle chcesz zmaksymalizować długość każdego sortowanego "biegu" podczas jego produkcji. Jeśli po prostu czytasz w danych, które zmieszczą się w pamięci, Quicksort i zapisz, każde uruchomienie będzie ograniczone do (trochę mniej) wielkości dostępnej pamięci.

Z reguły możesz zrobić trochę więcej niż to. Zaczynasz od czytania w bloku danych, ale zamiast używać Quicksort na nim, budujesz stertę. Następnie, gdy zapisujesz każdy element ze sterty do posortowanego pliku "run", wczytujesz kolejny element z Twojego pliku wejściowego. Jeśli jest większy niż element, który właśnie napisałeś na dysku, wkładasz go do istniejącej sterty i powtarzasz.

Elementy, które są mniejsze (tzn. należą do elementów, które zostały już napisane), zachowujesz osobno i budujesz drugą stertę. Gdy (i tylko wtedy, gdy) pierwsza sterta jest pusta, a druga sterta przejęła całą pamięć, kończysz zapisywanie elementów do istniejącego pliku" Uruchom " i zaczynasz od nowego.

To, jak będzie to skuteczne, zależy od początkowej kolejności danych. W najgorszym przypadku (wejście posortowane w odwrotnej kolejności) nie robi nic dobrego. W najlepszym przypadku (Dane wejściowe już posortowane) pozwala na "sortowanie" danych w jednym przebiegu przez Dane wejściowe. W przeciętnym przypadku (Dane wejściowe w kolejności losowej) pozwala to na około dwukrotne zwiększenie długości każdego posortowanego biegu, co zazwyczaj poprawia prędkość o około 20-25% (choć procent ten różni się w zależności od tego, o ile większe są dane niż dostępna pamięć).

 48
Author: Jerry Coffin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-28 19:56:19

Quicksort zależy od możliwości indeksowania do tablicy lub podobnej struktury. Kiedy jest to możliwe, trudno jest pokonać Quicksort.

Ale nie można szybko indeksować bezpośrednio na połączonej liście. Oznacza to, że jeśli myList jest listą linkowaną, to myList[x], gdyby możliwe było napisanie takiej składni, wymagałoby to rozpoczynania od początku listy i podążania za pierwszymi linkami x. To musiałoby być zrobione dwa razy za każde porównanie, które quicksort robi, a to byłoby drogie prawdziwe szybko.

To samo na dysku: Quicksort musiałby szukać i czytać każdy element, który chce porównać.

Sortowanie scalające jest szybsze w takich sytuacjach, ponieważ odczytuje pozycje sekwencyjnie, co zwykle powoduje, że log2(N) przekazuje dane. Jest znacznie mniej We / Wy zaangażowanych, a znacznie mniej czasu spędzonego na śledzeniu linków na połączonej liście.

Quicksort jest szybki, gdy dane mieszczą się w pamięci i mogą być adresowane bezpośrednio. Mergesort jest szybszy, gdy dane nie mieszczą się w pamięci lub gdy jest drogie, aby dostać się do przedmiotu.

Zauważ, że sortowanie dużych plików zazwyczaj ładuje tyle, ile mogą z pliku do pamięci, Quicksort to i zapisać go do pliku tymczasowego, i powtarzać, aż przejdzie przez cały plik. W tym momencie istnieje pewna liczba bloków, z których każdy jest sortowany, a następnie program wykonuje N-way merge, aby wytworzyć posortowane wyjście.

 20
Author: Jim Mischel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-07 17:44:31

Quicksort przeniesie rekordy na środek listy. Aby przenieść element do indeksu X, musi on zaczynać się od 0 i powtarzać po jednym rekordzie na raz.

A mergesort dzieli listę na kilka małych list i porównuje tylko nagłówki list.

Konfiguracja dla sortowania scalonego jest zwykle kosztowna niż iterowana wymagana przez quicksort. Jednak gdy lista jest wystarczająco duża, lub odczyty są drogie (jak z dysku), czas potrzebny na quicksort do iteracji staje się głównym czynnikiem.

 3
Author: cadrell0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-02 14:01:24