Zbiór do posortowania mieści się w pamięci

Slides:



Advertisements
Podobne prezentacje
Sortowanie przez scalanie
Advertisements

Algorytmy sortowania i porządkowania
Algorytmy sortowania i przeszukiwania
C++ wykład 2 ( ) Klasy i obiekty.
Egzamin.
Język C/C++ Funkcje.
INSTRUKCJA NABORU ELEKTRONICZNEGO
Algorytmy – c.d. złożoność algorytmów struktury danych
Algorytmy – c.d. struktury danych złożoność algorytmów
Schemat blokowy M START KONIEC
Język ANSI C Funkcje Wykład: Programowanie komputerów
INDEKSY I SORTOWANIE ZEWNĘTRZNE
Programowanie I Rekurencja.
Algorytm Dijkstry (przykład)
Funkcje c.d. Strukturalność. Algorytmy. Ćwiczenia przed kolokwium.
PROGRAMOWANIE STRUKTURALNE
ALGORYTMY I STRUKTURY DANYCH
Elementarne struktury danych Piotr Prokopowicz
Sortowanie Zajęcia 13.
ZŁOŻONOŚĆ OBLICZENIOWA
ALGORYTMY GEOMETRYCZNE.
FIZYKA dla studentów POLIGRAFII Układy i procesy termodynamiczne
Wykład 1: Wskaźniki Podstawy programowania Programowanie w C
Temat nr 10: System przerwań
Podstawy programowania PP – LAB5 Wojciech Pieprzyca.
Algorytmy i struktury danych
Menu Tabela program Microsoft Word
Algorytmy i struktury danych
Podstawy programowania
Algorytmy i Struktury Danych Sortowanie
Prowadzący: Dr inż. Jerzy Szczygieł
Przegląd podstawowych algorytmów
Zbiory biblioteczne W bibliotekach gromadzone są różnorodne zbiory, między innymi: książki, filmy na kasetach VHS oraz DVD, różne programy multimedialne,
Łódź, 3 października 2013 r. Katedra Analizy Nieliniowej, WMiI UŁ Podstawy Programowania Złożona składnia języka C++
Podstawy programowania
Pliki Pojęcie i rodzaje plików Definicja typu plikowego Operacje wykonywane na plikach elementowych.
sortowanie na bazie – wykorzystanie sortowania ze zliczaniem
Word Tabela.
Automatyka i Robotyka Systemy czasu rzeczywistego Wykład 4.
Materiały pochodzą z Platformy Edukacyjnej Portalu
Prezentują:.
Złożone typy danych Listy Tworzenie elastycznych baz danych
Podstawy programowania w języku C i C++
Projekt AS KOMPETENCJI jest współfinansowany przez Unię Europejską w ramach środków Europejskiego Funduszu Społecznego Program Operacyjny Kapitał Ludzki.
Inicjalizacja i sprzątanie
Przeglądanie zasobów komputera - uruchamianie programów
Tablice w Turbo Pascalu.
Opracowała: Edyta Guznowska – nauczyciel-bibliotekarz
SYSTEMY EKSPERTOWE I SZTUCZNA INTELIGENCJA
Podstawy Techniki Cyfrowej
Algorytmika.
Algorytmy i Struktury Danych
Treści multimedialne - kodowanie, przetwarzanie, prezentacja Odtwarzanie treści multimedialnych Andrzej Majkowski 1 informatyka +
Treści multimedialne - kodowanie, przetwarzanie, prezentacja Odtwarzanie treści multimedialnych Andrzej Majkowski informatyka +
Treści multimedialne - kodowanie, przetwarzanie, prezentacja Odtwarzanie treści multimedialnych Andrzej Majkowski 1 informatyka +
Procesor, pamięć, przerwania, WE/WY, …
Treści multimedialne - kodowanie, przetwarzanie, prezentacja Odtwarzanie treści multimedialnych Andrzej Majkowski 1 informatyka +
Programowanie proceduralne Podstawy Programowania dla geoinformatyków Wykład 3 Rafał Witkowski, 2015.
Tablice Zajęcia 8. Definicja Tablica (z ang. array) jest zmienną złożoną, która składa się z ciągu elementów tego samego typu. W pamięci komputera tablica.
Wstęp do programowania Wykład 4
INFORMATYKA SORTOWANIE DANYCH
ALGORYTMY I STRUKTURY DANYCH
1.problem próbkowania (sampling problem) dobór charakterystycznych punktów powierzchni w celu uzyskania najlepszego efektu przy minimalizacji ilości danych.
Przypomnienie wiadomości – kilka zadań
Listy.
Kolejka priorytetowa.
Operacje na ciągach znaków
Działania pamięciowe na ułamkach dziesiętnych
ALGORYTMY I STRUKTURY DANYCH
Zapis prezentacji:

Zbiór do posortowania mieści się w pamięci Ogólnie o sortowaniu Rodzaje sortowania (wg pamięci) Wewnętrzne Zbiór do posortowania mieści się w pamięci Zewnętrzne Zbiór do posortowania mieści się w pamięci zewnętrznej, np. na dyskach (wykorzystuje się tylko stałą – małą – ilość pamięci wewnętrznej.

Ogólnie o sortowaniu Rodzaje sortowania (wg operacji) Adaptacyjne Wykonuje się różne sekwencje operacji dla różnych układów danych Nieadaptacyjne Sekwencja wykonywanych operacji nie zależy od kolejności danych.

Wymaga dodatkowej pamięci na pełną kopię sortowanych danych Ogólnie o sortowaniu Parametry wydajnościowe sortowania: czas działania algorytmu ilość dodatkowej pamięci zużywanej przez algorytm Wykorzystuje tyle miejsca, ile potrzeba na zapisanie sortowanych danych + mały stos lub tablica Wymaga dodatkowej pamięci na pełną kopię sortowanych danych Używa reprezentacji w postaci listy połączonej albo innego sposobu pośredniego dostępu do danych, czyli wymaga dodatkowej pamięci na n wskaźników lub indeksów

Ogólnie o sortowaniu Definicja. Sortowanie jest stabilne, jeśli zachowuje względną kolejność elementów o jednakowych kluczach. Przykład. Lista studentów uporządkowana alfabetycznie według nazwisk. Jeśli chcemy ją posortować wg ocen, to studenci mający taką samą ocenę nadal będą w liście ułożeni alfabetycznie.

Ogólnie o sortowaniu Za operację dominującą będziemy przyjmować porównanie elementów w ciągu. Za złożoność pamięciową S(n) będziemy przyjmować ilość dodatkowej pamięci (oprócz n miejsc pamięci dla elementów w ciągu), potrzebnej do wykonania algorytmu. Zakładamy też, że elementy do posortowania są liczbami całkowitymi umieszczonymi w tablicy – dla ułatwienia.

Sortowanie przez selekcję Idea: Wyznaczamy najmniejszy element w ciągu (tablicy) i zamieniamy go miejscami z elementem pierwszym, następnie z pozostałego ciągu wybieramy element najmniejszy i ustawiamy go na drugie miejsce tablicy (zmieniamy), itd. Realizacja w C++ //realizacja funkcji zamiana //przestawiajacej dwa elementy //dowolnego typu void zamiana(int &A, int &B) { int t=A; A=B; B=t; } void selekcja (int a[],int l, int r) { for (int i=l; i<r; i++) int min=i; for (int j=i+1; j<=r; j++) if (a[j]<a[min]) min=j; zamiana(a[i],a[min]); } Typ może być dowolny

Sortowanie przez selekcję Przykład: S E L K C J A 7 porównań 6 porównań 5 porównań 4 porównania 3 porównania 2 porównania 1 porównanie

Sortowanie przez selekcję Analiza: Załóżmy, że l=0 i r=n-1. W linii pierwszej przykładu mamy n-1 porównań a[j]<a[min], potem w kolejnych liniach: n-2, n-3, ….a na końcu tylko 1 porównanie. Zatem: Tmax(n) P-stwo, że w każdym z porównań znajdziemy element najmniejszy jest jednakowe Stąd:

Sortowanie przez selekcję Policzmy teraz pesymistyczną wrażliwość tego algorytmu. Przypomnijmy, że Ponieważ w procedurze zawsze jest wykonywany ten sam ciąg operacji, niezależnie od danych wejściowych, to Δ(n)=0. Obliczmy na koniec miarę wrażliwości oczekiwanej algorytmu. w procedurze zawsze jest wykonywany ten sam ciąg operacji, niezależnie od danych wejściowych Ponadto S(n)=O(1) Mówimy, że algorytm sortuje w miejscu

Sortowanie przez selekcję Zalety: Liczba zamian w najgorszym przypadku: n-1. Prostota implementacji. Zadowalająca szybkość dla małych wartości n. Nie wymaga dodatkowej pamięci. Wady: Nie jest stabilny. Ma dużą złożoność (rzędu kwadratowego), więc nie nadaje się do sortowania długich tablic. Jest mało wrażliwy na wstępne uporządkowanie. Algorytm można uczynić stabilnym, zwiększając współczynnik proporcjonalności złożoności.

Sortowanie przez wstawianie Idea: W i-tym kroku trzeba wstawić element tab[i] na właściwe miejsce w posortowanym fragmencie tab[0]…tab[i-1], wcześniej przesuwając wszystkie elementy większe od niego w tym fragmencie w prawo o 1; powstaje posortowany fragment tab[0]…tab[i+1]. Realizacja w C++ void InsertSort(int *tab) { for(int i=1; i<n;i++) int j=i; // 0..i-1 jest już posortowane int temp=tab[j]; while ((j>0) && (tab[j-1]>temp)) tab[j]=tab[j-1]; j--; } tab[j]=temp;

Sortowanie przez wstawianie 1 porównanie <=2 porównania <=3 porównania <= 4 porównania <=5 porównań ……. <=9 porównań GOTOWE

Sortowanie przez wstawianie Analiza: W linii pierwszej mamy 1 porównanie, potem maksymalnie 2, itd. , aż do maksymalnie n-1 porównań na końcu. Zatem możemy policzyć pesymistyczną złożoność : Ponieważ element tab[i] z równym prawdopodobieństwem może zająć każdą z i-tej pozycji w ciągu tab[0]<tab[1]<…<tab[i-1], to w i-tym kroku mamy pij=1/i, czyli Sumując teraz po wszystkich n-1 iteracjach, dostajemy:

Sortowanie przez wstawianie Policzmy teraz pesymistyczną wrażliwość tego algorytmu. Przypomnijmy, że Jest to zatem kres górny zbioru liczb, które powstają jako różnice ilości operacji dominujących. Zatem od liczby największej z możliwych należy odjąć najmniejszą z możliwych, żeby otrzymać taki kres górny. Ponieważ najmniejszą ilością porównań w każdym kroku n-1iteracji jest jedno porównanie, a największa ilość wyrażą się obliczoną właśnie Tmax(n)=n(n-1)/2 to = =n(n-1)/2-(n-1)=Θ(n2). Pesymistyczna wrażliwość złożoności czasowej jest zatem duża i możemy się spodziewać dużej zmienności złożoności obliczeniowej.

Sortowanie przez wstawianie Średnia wrażliwość (czyli miara wrażliwości oczekiwanej): w i-tym kroku mamy: Sumując po wszystkich n-1 iteracjach, dostajemy:

Sortowanie przez wstawianie Zalety: Stabilność. Średnio algorytm jest 2 razy szybszy niż algorytm sortowania przez selekcję. Optymalny dla ciągów prawie posortowanych. Nie wymaga dodatkowej pamięci.

Sortowanie przez wstawianie Udoskonalenia: Można przestać porównywać elementy, napotkawszy element, który jest nie większy niż wstawiany, bo podtablica z lewej strony jest posortowana – sortowanie adaptacyjne. W pierwszej pętli „for” wyznaczamy element najmniejszy i umieszczamy go na początku tablicy, następnie sortujemy pozostałe elementy. Standardowo sortuje się zamiany elementów, ale można zrobić przeniesienie większych elementów o jedną pozycję w prawo.

Sortowanie bąbelkowe Ma prosty zapis. Na czym polega to sortowanie? Przykład 7-elementowej tablicy. Element zacieniowany w pojedynczym przebiegu głównej pętli „ulatuje” do góry jako najlżejszy. Tablica jest przemiatana od dołu do góry (pętla i) i analizowane są dwa sąsiadujące ze sobą elementy (pętla j); jeśli nie są uporządkowane, to następuje ich zamiana.

Sortowanie bąbelkowe Implementacja w C++ Algorytm jest klasy O(n2) void bubble(int *tab) { for (int i=1;i<n;i++) for (int j=n-1;j>=i;j--) if (tab[j]<tab[j-1]) {//swap int tmp=tab[j-1]; tab[j-1]=tab[j]; tab[j]=tmp; } Algorytm jest klasy O(n2) Analiza: Dość często zdarzają się puste przebiegi(nie jest dokonywana żadna wymiana, bo elementy są posortowane). Algorytm jest bardzo wrażliwy na konfigurację danych: 4,2,6,18,20,39,40 – wymaga jednej zamiany 4,6,18,20,39,40,2 – wymaga szesściu zamian

Sortowanie bąbelkowe Ulepszenia: przyśpieszają, choć nie zmieniają klasy. Można zapamiętać indeks ostatniej zamiany (walka z pustymi przebiegami). Można przełączać kierunki przeglądania tablicy (walka z niekorzystnymi konfiguracjami danych). void ShakerSort(int *tab) { int left=1,right=n-1,k=n-1; do for(int j=right; j>=left; j--) if(tab[j-1]>tab[j]) swap(tab[j-1],tab[j]); k=j; } left=k+1; for(j=left; j<=right; j++) right=k-1; while (left<=right); void bubble(int *tab) { for (int i=1;i<n;i++) for (int j=n-1;j>=i;j--) if (tab[j]<tab[j-1]) {//swap int tmp=tab[j-1]; tab[j-1]=tab[j]; tab[j]=tmp; } Algorytm poprawiony – sortowania przez wstrząsanie.

Sortowanie szybkie (quicksort) Idea: Jest to również metoda „dziel i rządź”, ponieważ dzieli tablicę na dwie części, które potem sortuje niezależnie. Algorytm składa się z dwóch kroków: Krok 1: procedura rozdzielania elementów tablicy względem wartości pewnej komórki tablicy służącej za oś podziału; proces sortowania jest dokonywany przez tę właśnie procedurę. Krok 2: procedura służąca do właściwego sortowania, która nie robi w zasadzie nic oprócz wywoływania samej siebie; zapewnia poskładanie wyników cząstkowych i w konsekwencji posortowanie całej tablicy.

Sortowanie szybkie Sednem metody jest proces podziału, który zmienia kolejność elementów w tablicy tak, że spełnione są trzy warunki: element a[i] znajduje się dla pewnego i na właściwej pozycji w tablicy; Żaden z elementów a[l], …, a[i-1] nie jest większy niż a[i]; Żaden z elementów a[i+1], …, a[r] nie jest mniejszy niż a[i]. W kółku mamy element rozgraniczający, elementy mniejsze są na lewo, a większe na prawo.

Sortowanie szybkie Oś podziału

Sortowanie szybkie Implementacja funkcji partition w C++. (W nagłówku funkcji tab jest adresem pierwszego elementu tablicy A do posortowania, l i r określają odpowiednio początek i koniec podtablicy A, która będzie dzielona przez funkcję partition.) War. początkowy int partition (int *tab, int l, int r) { int i=l-1, j=r, v=*(tab+r), s; for(;;) { i++; while (*(tab+i)<v) i++; j--; while (v<=*(tab+j)) if(j==1) break; } if (j==i) break; s=*(tab+i); *(tab+i)=*(tab+j); *(tab+j)=s; *(tab+i)=*(tab+r); *(tab+r)=s; return i; //α: 1<=l<r. //γ: A[k]<v<=A[i] dla k:=1,2,…,i-1. //δ: A[k]<v<=A[i] dla k:=l,l+1,…i-1  A[j]<v<=A[m] dla m:=j+1,j+2,…, r-1 //μ: A[k]<v dla k:=l,l+1,…i v<=A[m] dla m:=j,j+1,…, r-1 //η: A[k]<v dla k:=l,l+1,…i-1 v<=A[m] dla m:=i,i+1,…, r-1 bo j=i //β: A[k]<A[i]<=A[m] dla k:=l,l+1,…i-1  m:=i+1,i+2,…,r zamiana War. końcowy

Sortowanie szybkie Przeprowadzimy dowód semantycznej poprawności tego algorytmu, stosując metodę niezmienników. Warunek γ ma miejsce, bo poprzedzająca go instrukcja „while” zakończy się dla i, przy którym v<=A[i], pozostałe nierówności są wynikiem działania tej pętli. Jeśli i=1, wtedy pozostałe nierówności nie wystąpią. Następny warunek δ jest uzupełnieniem γ o podobne jak w warunku γ nierówności A[j]<v<=A[m] dla m:=j+1,j+2,…,r-1, których uzasadnienie przeprowadzamy w oparciu o pętlę „while” ustalającą j. Jeżeli i<j, to dokonujemy zamiany elementu j-tego z i-tym, co pociąga za sobą zajście μ wobec δ i przejście do następnego przebiegu pętli „for”. Jeżeli j=i, to wychodzimy z pętli „for” nie dokonując zamiany j-tego elementu z i-tym, dlatego na wyjściu z pętli „for” ma miejsce warunek η będący warunkiem δ zapisanym dla j=i. Po dokonaniu zamiany elementu i-tego z r-tym analogicznie jak μ był konsekwencją δ, warunek końcowy β jest konsekwencją η.

Sortowanie szybkie Uzasadnienie, że γ, δ, η, μ, β są niezmiennikami algorytmu partition pozwala na stwierdzenie o indeksie i będącym wartością funkcji partition: A[i] jest na właściwym miejscu w tablicy uporządkowanej, elementy tablicy od A[l] do A[i-1] są mniejsze od A[i], elementy A[i+1] do A[r] są większe lub równe A[i]. Zatem algorytm partition jest częściowo poprawny. Dobra określoność algorytmu jest oczywista. Posiadanie własności stopu wynika z obserwacji, że obie pętle „while” zawierają liczniki i oraz j, pierwszy rosnący, ograniczony z góry przez r, drugi malejący ograniczony z dołu przez 1. Pętla „for” będzie skończona ponieważ dla tak określonych liczników zawsze zajdzie warunek i==j.

Sortowanie szybkie Realizacja w C++ Właściwe sortowanie void quicksort (int *tab, int l, int r) { if(r<=l) return; //1-instrukcja int i=partition(tab, l, r); //2-instrukcja quicksort(tab, l, i-1); //3-instrukcja quicksort(tab, i+1, r); //4-instrukcja } Właściwe sortowanie Dowód poprawności: Własność: Dla dowolnej liczności n=r-l sortowanej tablicy algorytm jest semantycznie poprawny. Dowód: Krok1. Algorytm jest semantycznie poprawny dla n=0. Istotnie, wtedy r=l, a zatem r<=l i z postaci 1-instrukcji wynika, że tablica jednoelementowa nie ulegnie zmianie, pozostanie tablicą uporządkowaną. Oznacza to semantyczną poprawność dla n=0.

Sortowanie szybkie Krok 2. Ma miejsce następujące twierdzenie: jeżeli algorytm jest semantycznie poprawny dla dowolnych n<=k, gdzie k jest dowolną ustaloną liczbą naturalną nieujemną, to jest semantycznie poprawny dla n=k+1. Istotnie. Zauważmy, że 1<=k+1, zatem dla n=r-l=k+1 spełniony jest warunek początkowy α algorytmu partition i program wykona poprawnie instrukcję 1 i 2. Ponieważ l<=i<=r, zatem i-1-l<=r-l-1<=k oraz r-(i+1)=r-i-1<=r-l-1<=k i na mocy założenia indukcyjnego wywołania algorytmu quicksort w instrukcji 3 i 4 tego algorytmu wykonają się poprawnie, a zatem wykona się poprawnie cały algorytm. Tablica będzie uporządkowana, ponieważ instrukcja 3 poprawnie uporządkuje elementy tablicy od od l-tego do i-1-szego, i-ty jest na właściwej pozycji wobec poprawności algorytmu podział , a instrukcja 4 uporządkuje poprawnie elementy tablicy od i+1-szego do r-tego, co kończy dowód twierdzenia w kroku 2. Wobec spełnienia obu kroków na mocy zasady indukcji matematycznej ma miejsce dowodzona własność.

Sortowanie szybkie – złożoność obliczeniowa Zależy od tego, czy podziały są zrównoważone, czy nie, a to z kolei zależy od tego, które elementy zostaną wybrane do dzielenia. Podziały zrównoważone Algorytm asymptotycznie ma taką złożoność jak sortowanie przez scalanie. Podziały niezrównoważone Algorytm może działać tak wolno jak sortowanie przez wstawianie.

Sortowanie szybkie – złożoność obliczeniowa Najgorszy przypadek podziałów: gdy procedura partition tworzy jeden obszar złożony z n-1 elementów, a drugi tylko z 1 elementu. Załóżmy, że takie niezrównoważone podziały będą wykonywane w każdym kroku algorytmu.

Sortowanie szybkie – złożoność obliczeniowa koszt podziału wykonanie dla tablicy jednoelementowej równanie rekurencyjne Rozwiązujemy rekurencję, iterując: Czy to jest pesymistyczna złożoność obliczeniowa?

Sortowanie szybkie – złożoność obliczeniowa Niech Tmax (n) będzie najgorszym czasem działania algorytmu quicksort dla danych wejściowych rozmiaru n. Mamy równanie rekurencyjne: gdzie parametr q przyjmuje wartości od 1 do n-1, ponieważ mamy dwa obszary, z których każdy ma co najmniej 1 element. Zgadujemy, że dla pewnej stałej c. Zatem Przy odpowiednim doborze dużej stałej c

Sortowanie szybkie – złożoność obliczeniowa Najlepszy przypadek podziałów: T(n)=2T(n/2)+Θ(n) Przypadek 2 tw. o rekurencji uniwersalnej daje rozwiązanie: T(n)= Θ(nlgn) Podział na połowę

Sortowanie szybkie – złożoność obliczeniowa Jeśli zbadamy różnicę między przypadkiem pesymistycznym a najlepszym, to dostaniemy pesymistyczną wrażliwość algorytmu: Δ(n)=Θ(n2-nlg2n)

Sortowanie szybkie – złożoność obliczeniowa Podziały zrównoważone – przypadek średni Przykład podziału w stosunku 9 do1 Przypadek średni jest bliski przypadkowi najlepszemu – udowodnimy!

Sortowanie szybkie – złożoność obliczeniowa Podziały zrównoważone – przypadek średni (oczekiwana złożoność) Załóżmy, że wystąpienie dowolnej permutacji n liczb całkowitych jako danych do sortowania jest jednakowo prawdopodobne, podział permutacji na dwie podtablice i-1 elementową i n-i elementową jest również jednakowo prawdopodobny dla dowolnego i=1,2,…,n. Wtedy średnia złożoność obliczeniowa Tsr(n) spełnia warunki: jednakowo prawdopodobne ∙n

Sortowanie szybkie –złożoność obliczeniowa odejmujemy stronami Stosujemy iteracje…. n+1-sza suma szeregu harmonicznego lub wykorzystanie szacowania sumy za pomocą całki

Sortowanie szybkie –złożoność obliczeniowa Funkcja harmoniczna: stała Eulera Z całki natomiast: Stąd widać, że

Sortowanie szybkie Zalety: Praktycznie działa w miejscu (używa tylko niewielkiego stosu pomocniczego). Do posortowania n elementów wymaga średnio czasu proporcjonalnego do nlog2n . Ma wyjątkowo skromną pętlę wewnętrzną. Wady: Jest niestabilny. Zabiera około n2 operacji w przypadku najgorszym. Jest wrażliwy (tzn. prosty niezauważony błąd w implementacji może powodować niewłaściwe działanie w przypadku niektórych danych). Średnia złożoność obliczeniowa jest niemal optymalna. Od kiedy w 1960 C.A.R.Hoare go opublikował, zaczęły się pojawiać jego ulepszone wersje – ale algorytm jest tak zrównoważony, że poprawienie programu w jednym aspekcie, pogarsza jego parametry w innym. Jest często stosowany w bibliotekach standardowych. Można go usprawnić ograniczając rekurencję do pewnego ustalonego n, a tablice o mniejszej długości sortujemy nierekurencyjnym algorytmem sortowania.