Algorytmy i Struktury Danych. (c) Marcin Sydow. Sortowanie Selection Sort Insertion Sort Merge Sort. Sortowanie 1. Listy dowiązaniowe.

Podobne dokumenty
Algorytmy i Struktury Danych. (c) Marcin Sydow. Introduction. QuickSort. Sortowanie 2. Limit. CountSort. RadixSort. Summary

Zadanie 1 Przygotuj algorytm programu - sortowanie przez wstawianie.

Sortowanie przez scalanie

Analiza algorytmów zadania podstawowe

Programowanie w VB Proste algorytmy sortowania

Definicja. Ciąg wejściowy: Funkcja uporządkowująca: Sortowanie polega na: a 1, a 2,, a n-1, a n. f(a 1 ) f(a 2 ) f(a n )

Algorytmy i Struktury Danych, 2. ćwiczenia

Algorytmy i Struktury Danych.

Podstawowe struktury danych

Strategia "dziel i zwyciężaj"

Wstęp do programowania

Algorytmy i złożoność obliczeniowa. Wojciech Horzelski

Złożoność obliczeniowa algorytmu ilość zasobów komputera jakiej potrzebuje dany algorytm. Pojęcie to

Algorytmy i Struktury Danych.

Dynamiczne struktury danych

INFORMATYKA SORTOWANIE DANYCH.

Algorytmy i struktury danych

Złożoność Obliczeniowa Algorytmów

Wykład 3. Metoda dziel i zwyciężaj

Wprowadzenie do złożoności obliczeniowej

Podstawowe algorytmy i ich implementacje w C. Wykład 9

Rekurencja. Dla rozwiązania danego problemu, algorytm wywołuje sam siebie przy rozwiązywaniu podobnych podproblemów. Przykład: silnia: n! = n(n-1)!

Sortowanie - wybrane algorytmy

Wykład 2. Poprawność algorytmów

Podstawy Informatyki. Sprawność algorytmów

Kolokwium ze wstępu do informatyki, I rok Mat. (Ściśle tajne przed godz. 10 : grudnia 2005.)

Wstęp do programowania

Analiza algorytmów zadania podstawowe

Algorytm selekcji Hoare a. Łukasz Miemus

Algorytmy i struktury danych. Wykład 4 Tablice nieporządkowane i uporządkowane

Sortowanie w czasie liniowym

Wstęp do programowania

Zaawansowane algorytmy i struktury danych

Wstęp do Programowania potok funkcyjny

Wstęp do programowania

Złożoność algorytmów. Wstęp do Informatyki

znalezienia elementu w zbiorze, gdy w nim jest; dołączenia nowego elementu w odpowiednie miejsce, aby zbiór pozostał nadal uporządkowany.

wstęp do informatyki i programowania część testowa (25 pyt. / 60 min.)

Wykład 5. Sortowanie w czasie liniowologarytmicznym

Efektywna metoda sortowania sortowanie przez scalanie

Programowanie proceduralne INP001210WL rok akademicki 2017/18 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Algorytmy i Struktury Danych. Co dziś? Drzewo decyzyjne. Wykład IV Sortowania cd. Elementarne struktury danych

5. Podstawowe algorytmy i ich cechy.

Zasady analizy algorytmów

Jeśli czas działania algorytmu zależy nie tylko od rozmiaru danych wejściowych i przyjmuje różne wartości dla różnych danych o tym samym rozmiarze,

ALGORYTMY I STRUKTURY DANYCH

Algorytmy równoległe: ocena efektywności prostych algorytmów dla systemów wielokomputerowych

Algorytmy sortujące 1

Informatyka 1. Złożoność obliczeniowa

Programowanie Równoległe i Rozproszone. Algorytm Kung a. Algorytm Kung a. Programowanie Równoległe i Rozproszone Wykład 8. Przygotował: Lucjan Stapp

TEORETYCZNE PODSTAWY INFORMATYKI

Sortowanie danych. Jolanta Bachan. Podstawy programowania

Algorytmy równoległe: ocena efektywności prostych algorytmów dla systemów wielokomputerowych

Wstęp do programowania INP001213Wcl rok akademicki 2017/18 semestr zimowy. Wykład 13. Karol Tarnowski A-1 p.

liniowa - elementy następują jeden za drugim. Graficznie możemy przedstawić to tak:

Wstęp do programowania INP001213Wcl rok akademicki 2018/19 semestr zimowy. Wykład 13. Karol Tarnowski A-1 p.

Porównanie Heap Sort, Counting Sort, Shell Sort, Bubble Sort. Porównanie sortowao: HS, CS, Shs, BS

Struktury danych i złożoność obliczeniowa Wykład 2. Prof. dr hab. inż. Jan Magott

Zaawansowane algorytmy i struktury danych

Wykład 1_2 Algorytmy sortowania tablic Sortowanie bąbelkowe

Sortowanie przez wstawianie Insertion Sort

Algorytmy i struktury danych

Matematyczne Podstawy Informatyki

Algorytmy i struktury danych. Wykład 6 Tablice rozproszone cz. 2

Sortowanie. Kolejki priorytetowe i algorytm Heapsort Dynamiczny problem sortowania:

Uwaga: Funkcja zamień(a[j],a[j+s]) zamienia miejscami wartości A[j] oraz A[j+s].

WYŻSZA SZKOŁA INFORMATYKI STOSOWANEJ I ZARZĄDZANIA

Podstawy programowania. Przykłady algorytmów Cz. 2 Sortowanie

Sortowanie. LABORKA Piotr Ciskowski

Przykładowe sprawozdanie. Jan Pustelnik

Drzewa poszukiwań binarnych

OSTASZEWSKI Paweł (55566) PAWLICKI Piotr (55567) Algorytmy i Struktury Danych PIŁA

Algorytmy i struktury danych. wykład 5

Algorytmy i struktury danych Sortowanie IS/IO, WIMiIP

Złożoność obliczeniowa zadania, zestaw 2

Wykład 4. Sortowanie

Algorytmy sortujące i wyszukujące

Wstęp do Informatyki zadania ze złożoności obliczeniowej z rozwiązaniami

Algorytmy równoległe. Rafał Walkowiak Politechnika Poznańska Studia inżynierskie Informatyka 2010

Algorytmy i. Wykład 5: Drzewa. Dr inż. Paweł Kasprowski

Wstęp do programowania. Listy. Piotr Chrząstowski-Wachtel

Podstawy programowania. Wykład 7 Tablice wielowymiarowe, SOA, AOS, itp. Krzysztof Banaś Podstawy programowania 1

Drzewa BST i AVL. Drzewa poszukiwań binarnych (BST)

Porównanie czasów działania algorytmów sortowania przez wstawianie i scalanie

Podstawy Programowania 1 Sortowanie tablic jednowymiarowych. Plan. Sortowanie. Sortowanie Rodzaje sortowania. Notatki. Notatki. Notatki.

Laboratorium nr 7 Sortowanie

Sortowanie przez wstawianie

PODSTAWY INFORMATYKI wykład 5.

Struktury Danych i Złożoność Obliczeniowa

Technologie informacyjne Wykład VII-IX

Podstawy algorytmiki i programowania - wykład 6 Sortowanie- algorytmy

Algorytmy i złożoności. Wykład 3. Listy jednokierunkowe

Wstęp do programowania. Dziel i rządź. Piotr Chrząstowski-Wachtel

Podstawy Programowania. Złożoność obliczeniowa

Klasa 2 INFORMATYKA. dla szkół ponadgimnazjalnych zakres rozszerzony. Założone osiągnięcia ucznia wymagania edukacyjne na. poszczególne oceny

prowadzący dr ADRIAN HORZYK /~horzyk tel.: Konsultacje paw. D-13/325

Wstęp do programowania INP001213Wcl rok akademicki 2017/18 semestr zimowy. Wykład 9. Karol Tarnowski A-1 p.

Teoretyczne podstawy informatyki

3. Podaj elementy składowe jakie powinna uwzględniać definicja informatyki.

Algorytmy i struktury danych Matematyka III sem.

Transkrypt:

1

Tematy wykładu: problem sortowania sortowanie przez wybór (SelectionSort) sortowanie przez wstawianie (InsertionSort) sortowanie przez złaczanie (MergeSort) struktura danych list dowiązaniowych

Input: S - ciąg elementów, które mogą być uporządkowane za pomocą pewnej relacji porządku liniowego R (np. liczby naturalne); len - długość ciągu S (liczba naturalna) Output: S - ciąg składający się z tych samych elementów co S, uporządkowany niemalejąco (tzn. 0<i<len S[i 1] R S[i]) W tym kursie, dla uproszczenia dyskusji, rozważamy jako elementy sortowane liczby naturalne, ale nie ma to wpływu (poza CountSort) na większość omawianych algorytmów.

Waga problemu sortowania jest jednym z najważniejszych podstawowych zadań dotyczących praktycznego przetwarzania danych. Tematyka sortowania była bardzo intensywnie badana od połowy 20. wieku i większość używanych obecnie algorytmów powstała wiele dekad temu. jest używane w bardzo wielu kontekstach, np.: przyspieszenie wyszukiwania przyspieszenie operacji na danych, np. operacji na bazach danych, etc. wizualizacja danych obliczanie pewnych ważnych statystyk I wiele innych

przez wybór () Pomysł sortowania przez wybór jest bardzo prosty. W sortowanym ciągu znajdujemy minimum, zamieniamy je miejscami z pierwszym elementem ciągu i kontynuujemy to samo na ciągu zaczynającym się od drugiego indeksu, dopóki bieżący ciąg ma więcej niż 1 element. selectionsort(s, len){ i = 0 while(i < len){ mini = indexofmin(s, i, len) swap(s, i, mini) i++ } } gdzie: indexofmin(s, i, len) - jest pomocniczą funkcją zwracającą indeks minimum wśród elementów S[j], gdzie i j < len swap(s, i, mini) - zamiana miejscami elementów S[i] i S[mini] Jaki jest niezmiennik pętli (zewnętrznej)?

przez wybór () Pomysł sortowania przez wybór jest bardzo prosty. W sortowanym ciągu znajdujemy minimum, zamieniamy je miejscami z pierwszym elementem ciągu i kontynuujemy to samo na ciągu zaczynającym się od drugiego indeksu, dopóki bieżący ciąg ma więcej niż 1 element. selectionsort(s, len){ i = 0 while(i < len){ mini = indexofmin(s, i, len) swap(s, i, mini) i++ } } gdzie: indexofmin(s, i, len) - jest pomocniczą funkcją zwracającą indeks minimum wśród elementów S[j], gdzie i j < len swap(s, i, mini) - zamiana miejscami elementów S[i] i S[mini] Jaki jest niezmiennik pętli (zewnętrznej)? (pierwsze i elementów ciągu jest posortowane)

- Analiza Operacja dominująca: porównanie 2 elementów w tablicy Rozmiar danycyh: długość ciągu (len) W pętli zewnętrznej wykonane będzie len 1 iteracji, w i-tej iteracji szukamy minimum w ciągu o długości (len-i) elementów (i odpowiednio tyle jest porównań) W (len) = len 1 i=1 i = len(len 1) 2 = Θ((len) 2 ) Algorytm ten ma więc kwadratową pesymistyczną złożoność czasową. Zauważmy, że przeciętna złożoność czasowa tego algorytmu A(len) jest taka sama jak pesymistyczna, gdyż algorytm SelectionSort dla danej długości ciągu zawsze (niezależnie od zawartości ciągu) wykonuje taką samą liczbę porównań - nawet dla ciągu wejściowego, który już jest posortowany

przez wstawianie () Począwszy od drugiej pozycji w sortowanym ciągu, w iteracji next przepychamy bieżący (o indeksie next) element wstecz, aż znajdziemy (używając porównań) dla niego właściwą pozycję, tak, żeby ciąg pierwszych next + 1 elementów był posortowany. Następnie zwiększamy bieżącą pozycję (next) o 1 aż do ostatniego elementu ciągu. insertionsort(arr, len){ for(next = 1; next < len; next++){ curr = next; temp = arr[next]; while((curr > 0) && (temp < arr[curr - 1])){ } } arr[curr] = arr[curr - 1]; curr--; } arr[curr] = temp; Jaki jest niezmiennik pętli zewnętrznej?

przez wstawianie () Począwszy od drugiej pozycji w sortowanym ciągu, w iteracji next przepychamy bieżący (o indeksie next) element wstecz, aż znajdziemy (używając porównań) dla niego właściwą pozycję, tak, żeby ciąg pierwszych next + 1 elementów był posortowany. Następnie zwiększamy bieżącą pozycję (next) o 1 aż do ostatniego elementu ciągu. insertionsort(arr, len){ for(next = 1; next < len; next++){ curr = next; temp = arr[next]; while((curr > 0) && (temp < arr[curr - 1])){ } } arr[curr] = arr[curr - 1]; curr--; } arr[curr] = temp; Jaki jest niezmiennik pętli zewnętrznej? Analogiczny do SelectionSort.

- Analiza (operacja dominująca i rozmiar danych (oznaczmy dla wygody przez n) takie same jak w poprzednim algorytmie) Jaki jest najgorszy przypadek? (najwięcej porównań)?

- Analiza (operacja dominująca i rozmiar danych (oznaczmy dla wygody przez n) takie same jak w poprzednim algorytmie) Jaki jest najgorszy przypadek? (najwięcej porównań)? Kiedy dane są odwrotnie posortowane. Wtedy złożoność jest następująca: W (n) = n(n 1) 2 = 1 2 n2 + Θ(n) = Θ(n 2 ) Zauważmy też, że jeśli dane wejściowe już są posortowane, algorytm działa bardzo szybko i wymaga tylko n-1 porównań. Zatem ten algorytm jest bardziej inteligentny niż poprzedni, gdyż dostosowuje ilość pracy do stopnia posortowania danych i w najgorszym przypadku (dane odwrotnie posortowane) wykonuje tyle pracy co dla każdego przypadku.

Analiza przeciętnej złożoności czasowej Przypomnienie: do analizy przeciętnej złożoności czasowej należy założyć pewien model losowości danych wejściowych. Załóżmy prosty naturalny model losowości: dane są liczbami naturalnymi od 1 do n i każda permutacja jest jednakowo prawdopodobna. Wtedy, w itej iteracji zewnętrznej pętli algorytm wykona następującą przeciętną liczbę porównań: 1 i i j=1 j = 1 (i+1)i i 2 = i+1 2 W ten sposób, we wszystkich iteracjach otrzymamy łącznie: A(n) = n 1 i=1 i+1 2 = 1 2 n k=2 k = 1 4 n2 + Θ(n) = Θ(n 2 )

Analiza, c.d. Jak wynika z analizy, w przeciętnym przypadku algorytm ten jest 2 razy szybszy od algorytmu sortowania przez wybór, ale wciąż ma kwadratową złożoność czasową (czyli np. 3-krotny wzrost rozmiaru danych spowoduje ok. 9-krotny wzrost czasu działania niezależnie od implementacji i sprzętu). Kwadratowa złożoność czasowa jest zbyt wysoka w przypadku dużych danych (rozważmy np. sortowanie miliarda liczb - ile porównań należałoby wykonać? Ile by to trwało nawet na szybkiej maszynie? Zauważmy, że miliard 8-bajtowych liczb to zaledwie 8GB danych w RAM)

Analiza, c.d. Jak wynika z analizy, w przeciętnym przypadku algorytm ten jest 2 razy szybszy od algorytmu sortowania przez wybór, ale wciąż ma kwadratową złożoność czasową (czyli np. 3-krotny wzrost rozmiaru danych spowoduje ok. 9-krotny wzrost czasu działania niezależnie od implementacji i sprzętu). Kwadratowa złożoność czasowa jest zbyt wysoka w przypadku dużych danych (rozważmy np. sortowanie miliarda liczb - ile porównań należałoby wykonać? Ile by to trwało nawet na szybkiej maszynie? Zauważmy, że miliard 8-bajtowych liczb to zaledwie 8GB danych w RAM) Czy jest możliwe zaprojektowanie algorytmu sortującego istotnie szybciej niż z kwadratową złożonością?

przez złączanie () Jest to zastosowanie podejścia Dziel i rządź do sortowania. Rozważmy następujący pomysł na sortowanie: 1 podziel ciąg na 2 połowy 2 posortuj każdą połówkę oddzielnie 3 połącz posortowane połówki w całość Zauważmy, że połączenie 2 posortowanych ciągów w jeden posortowany wymaga stosunkowo niewiele (liniowo wiele) porównań (dlaczego?) więc powyższy schemat ma szanse na bycie szybkim sposobem sortowania. Ponadto, w punkcie 2, każda z połówek może być posortowana też zgodnie z całym schematem (rekursja), dopóki połówki mają długość większość niż 1. Zatem, dostajemy gotowy rekurencyjny algorytm sortowania (przez złączanie).

przez złączanie () - schemat mergesort(s, len){ if(len <= 1) return S[0:len] m = len/2 return merge(mergesort(s[0:m], m), m mergesort(s[m:len], len-m), len-m) } używamy tu nieco nietypowej notacji (bardziej podobnej np. do Pythona), żeby zwięźle wyrazić algorytm. oznaczenie S[a:b] oznacza tu podciąg składający się z elementów S[i] takich, że a i < b funkcja merge(a1, len1, a2, len2) złącza dwa posortowane podciągi a1 i a2 (o długościach len1 i len2, odpowiednio) i zwraca połączony i posortowany ciąg

Szczegóły funkcji merge input: a1, a2 - posortowane ciągi liczb o długościach len1 i len2, odpowiednio output: zwraca posortowany ciąg powstały z elementów ciągów a1 i a2 merge(a1, len1, a2, len2){ i = j = k = 0; result[len1 + len2] // (alokacja pamięci) while((i < len1) && (j < len2)) if(a1[i] < a2[j]) result[k++] = a1[i++]; else result[k++] = a2[j++]; while(i < len1) result[k++] = a1[i++]; while(j < len2) result[k++] = a2[j++]; return result; }

Analiza funcji merge merge(a1, len1, a2, len2) dominująca operacja: porównanie 2 elementów lub indeksów rozmiar danych: łączna długość obu ciągów: n = len1 + len2 złożoność czasowa: W(n) = A(n) = 1 Przy zastosowaniu wyszukiwania binarnego liczba porównań w merge wynosi O(log(n)), ale i tak potrzeba O(n) operacji przypisania wartości przy przesuwaniu

Analiza funcji merge merge(a1, len1, a2, len2) dominująca operacja: porównanie 2 elementów lub indeksów rozmiar danych: łączna długość obu ciągów: n = len1 + len2 złożoność czasowa: W(n) = A(n) = Θ(n) 1 niestety, złożoność pamięciowa jest wysoka, gdyż alokujemy tablicę na połączone ciągi: S(n) = 1 Przy zastosowaniu wyszukiwania binarnego liczba porównań w merge wynosi O(log(n)), ale i tak potrzeba O(n) operacji przypisania wartości przy przesuwaniu

Analiza funcji merge merge(a1, len1, a2, len2) dominująca operacja: porównanie 2 elementów lub indeksów rozmiar danych: łączna długość obu ciągów: n = len1 + len2 złożoność czasowa: W(n) = A(n) = Θ(n) 1 niestety, złożoność pamięciowa jest wysoka, gdyż alokujemy tablicę na połączone ciągi: S(n) = Θ(n) (można tego uniknąć jeśli dane są w formie tzw. list dowiązaniowych a nie tablic) 1 Przy zastosowaniu wyszukiwania binarnego liczba porównań w merge wynosi O(log(n)), ale i tak potrzeba O(n) operacji przypisania wartości przy przesuwaniu

Analiza algorytmu mergesort Aby obliczyć złożoność algorytmu mergesort wystarczy obliczyć łączną złożoność wszystkich wywołań funkcji merge. Na każdym poziomie rekursji funkcja merge(s1, len1, s2, len2) jest wywoływana na ciągach o łącznej długości len (najpierw na 2 potem na 4, etc.) Ponieważ ciąg dzielony jest na 2 połowy, więc głębokość (liczba poziomów) rekursji wynosi Θ(log 2 (len)) (podobnie jak byłoby w rekurencyjnej wersji algorytmu binarysearch).

Analiza złożonośći czasowej algorytmu mergesort mergesort(s, len) operacja dominująca: porównanie 2 elementów lub indeksów rozmiar danych: długość ciągu wejściowego (len) Zatem, mamy Θ(log 2 (len)) poziomów rekursji i na każdym poziomie wszystkie wywołania funkcji merge mają łączną złożoność Θ(len). Podsumowując, otrzymujemy: W (len) = A(len) = Θ(len log(len)) - czyli złożoność jest liniowo-logarytmiczna (lepsza od kwadratowej!)

Krótkie podsumowanie omówionych 3 algorytmów sortowanie przez wybór i przez wstawianie: proste algorytmy mające kwadratową złożoność czasową (Θ(n 2 )) natomiast sortowanie przez złączanie (mergesort) jest istotnie szybsze: liniowo-logarytmiczne (Θ(nlog 2 (n))), chociaż (w wersji, gdy ciągi przechowywane są w tablicach) niestety zużywa dużo (liniowo wiele) pamięci na kopiowane tablice oraz Θ(log 2 (n)) na rekursję.

Złożoność kwadratowa a liniowo-logarytmiczna Zauważmy, że różnica pomiędzy złożonością kwadratową i liniowo-logarytmiczną jest praktycznie istotna i dla dużych danych może być bardzo znacząca. rozważmy np. 100 milionów logów serwera WWW do posortowania (np. po adresie IP) załóżmy, że można porównać miliard par logów na sekundę.

Złożoność kwadratowa a liniowo-logarytmiczna Zauważmy, że różnica pomiędzy złożonością kwadratową i liniowo-logarytmiczną jest praktycznie istotna i dla dużych danych może być bardzo znacząca. rozważmy np. 100 milionów logów serwera WWW do posortowania (np. po adresie IP) załóżmy, że można porównać miliard par logów na sekundę. Ile czasu zabierze to algorytmowi insertionsort?

Złożoność kwadratowa a liniowo-logarytmiczna Zauważmy, że różnica pomiędzy złożonością kwadratową i liniowo-logarytmiczną jest praktycznie istotna i dla dużych danych może być bardzo znacząca. rozważmy np. 100 milionów logów serwera WWW do posortowania (np. po adresie IP) załóżmy, że można porównać miliard par logów na sekundę. Ile czasu zabierze to algorytmowi insertionsort? (10 8 ) 2 p/10 9 s = 10 7 s (115 dni) A ile w przypadku algortymu mergesort? (załóżmy stałą multiplikatywną 1)

Złożoność kwadratowa a liniowo-logarytmiczna Zauważmy, że różnica pomiędzy złożonością kwadratową i liniowo-logarytmiczną jest praktycznie istotna i dla dużych danych może być bardzo znacząca. rozważmy np. 100 milionów logów serwera WWW do posortowania (np. po adresie IP) załóżmy, że można porównać miliard par logów na sekundę. Ile czasu zabierze to algorytmowi insertionsort? (10 8 ) 2 p/10 9 s = 10 7 s (115 dni) A ile w przypadku algortymu mergesort? (załóżmy stałą multiplikatywną 1) 2.65 10 9 p/10 9 s (2.65 sekundy) :)

Negatywną cechą przedstawionej wersji algorytmu mergesort było to, że wywołania funkcji merge musza zużywać łącznie dużo pamięci na tablice pomocnicze przechowujące wyniki (posortowane ciągi wynikowe). Można tego uniknąć jeśli ciągi przechowywane są za pomocą innej struktury danych: List dowiązaniowych składają się z węzłów i dowiązań (w programowaniu: wskaźników) które łączą węzły. Każdy węzeł jest pewnym kontenerem i przechowuje jeden element (np. element ciągu). Powiązane stanowią ciąg. np.: początek -> (2)-> (3)-> (5)-> (8)-> null

Jest wiele wariantów list dowiązaniowych np.: jednokierunkowe (każdy węzeł zawiera wskaźnik do następnego węzła, dodatkowy węzeł pokazuje na początek listy, ostatni węzeł pokazuje na null. W takiej liście można poruszać się tylko do przodu) dwukierunkowe (każdy węzeł zawiera wskaźniki do następnika i poprzednika w liście, możemy mieć dwa oddzielne wskaźniki na początek i koniec. Struktura zużywa 2 razy więcej pamięci na wskaźniki, ale można poruszać się po niej zarówno do przodu jak i do tyłu) cykliczne (jedno lub dwukierunkowe): ostatni węzeł powiązany jest (cyklicznie) z pierwszym W przypadku implementacji algorytmu mergesort wystarczają listy jednokierkunkowe, gdyż funkcja merge przechodzi każdą listę tylko w jednym kierunku.

Listy kontra tablice tablice: zalety: bardzo szybki dostęp bezpośredni do dowolnego elementu, minimalne zużycie pamięci wady: wstawienie dowolnego elementu w środek ma liniowy złożoność czasową (przesuwanie innych elementów) listy dowiązaniowe: zalety: wstawienie/usunięcie dowolnie długiej podlisty ma stałą złożoność czasową, niezależnie od długości podlisty (wystarczy przestawić stałą liczbę dowiązań) wady: wolny dostęp do elementów (liniowy) zależący od miejsca w liście, dodatkowa pamięć na dowiązania (wskaźniki)

w mergesort Jeśli ciąg wejściowy do posortowania przechowywany jest w formie listy dowiązaniowej, można zaimplementować algorytm mergesort tak, że ma taką samą złożoność czasową (liniowo-logarytmiczną) natomiast nie zużywa wogóle dodatkowej pamięci wewnątrz funkcji merge (gdyż funkcja merge jedynie przestawia dowiązania aby połączyć ciągi), jedynie zużywa pamięć na obsługę rekursji (ramki stosu wywołań funkcji).

Problemy/pytania: istota problemu sortowania i zastosowania selectionsort (pomysł, działanie, kod, analiza) (j.w.) (j.w.) listy kontra tablice (wady i zalety) napisz funkcję merge używając list a nie tablic

Dziękuję za uwagę!