Podstawy Programowana 2 Algorytmy Arkadusz Chrobot Zakład Informatyk 28 maa 2019 1 / 60 Plan Podsumowane 2 / 60 Dzseszy wykład będze dotyczył dwóch algorytmów sortowana, które powązane są z wcześne poruszanym tematam: metodą dzel zwycęża, rekurencą oraz drzewam Perwszym z nch est algorytm, drugm algorytm sortowana z użycem kopca (ang ) 3 / 60 Zanm przedzemy do opsu wspomnanych algorytmów przedstawmy funkce nne elementy kodu źródłowego, które będą wspólne dla wszystkch zaprezentowanych na tym wykładze programów 4 / 60
Funkca plk nagłówkowe typ tablcowy 1 #nclude<stdoh> 2 #nclude<stdlbh> 3 #nclude<tmeh> 4 5 typedef nt nt_array_type[10]; 5 / 60 Plk nagłówkowe typ tablcowy Wynk dzałana prezentowanych programów będą przedstawane na ekrane komputera, a do tworzena danych weścowych zostane zastosowany generator lczb pseudolosowych, dlatego włączane są zaprezentowane na poprzednm sladze plk nagłówkowe Na potrzeby programów został równeż zdefnowany typ tablcowy określaący tablcę 10 elementów typu nt (wersz nr 5) 6 / 60 Funkca fll_array() 1 vod fll_array(nt_array_type array) 3 nt ; 4 srand(tme(0)); 5 for(=0;<szeof(nt_array_type)/szeof(array[0]);++) 6 array[] = -10+rand()%21; 7 } 7 / 60 Funkca fll_array() Zadanem zaprezentowane na poprzednm sladze funkc est wypełnene tablcy lczbam całkowtym wylosowanym z zakresu do 10 do 10 Tablca do wypełnena est przekazywana przez parametr est typu nt_array_type, który został zdefnowany na początku programu Dzęk temu możemy określć lczbę e elementów, użytą do określena zakończena pętl for stosuąc wyrażene dzelące rozmar typu tablcowego przez rozmar perwszego elementu tablcy tego typu (wersz nr 5) 8 / 60
Funkca prnt_array() 1 vod prnt_array(nt_array_type array) 3 nt ; 4 for(=0;<szeof(nt_array_type)/szeof(*array);++) 5 prntf("%d ",array[]); 6 prntf("\n"); 7 } 9 / 60 Funkca prnt_array() Funkca prnt_array() wypsue zawartość przekazane e przez parametr array tablcy na ekran przenos kursor do następnego wersza na ekrane Od nnych funkc wykonuących podobną czynność w programach zaprezentowanych na wcześneszych wykładach różn ą klka szczegółów Perwszym est to, że typ parametru est wcześne zdefnowany w programe za pomocą typedef, drugm est to, że po zakończenu pętl for do przenesena kursora do następnego wersza ekranu est używana funkca prntf(), a argumentem e wywołana est cąg znaków składaący sę ze znaku nowego wersza (wersz nr 6) Ostatnm szczegółem est wyrażene użyte do określena zakończena pętl for Jest ono podobne do tego, które est użyte w funkc fll_array(), ednak dostęp do perwszego elementu tablcy odbywa sę za pomocą wskaźnka, a ne notac z nawasam kwadratowym (wersz nr 4) 10 / 60 Funkca swap() 1 vod swap(nt *frst, nt *second) 3 nt temporary = *frst; 4 *frst = *second; 5 *second = temporary; 6 } 11 / 60 Funkca swap() Kod źródłowy funkc swap() był opsywany na wykładach welokrotne, węc teraz tylko przypomnamy, że służy ona do zamany wartośc mędzy dwema zmennym W przypadku programów z dzseszego wykładu będą to elementy tablcy 12 / 60
Algorytm został opracowany przez brytyskego nformatyka CAR Hoare a est ednym z naszybszych algorytmów sortowana w przypadku typowych zastosowań Wprawdze w przypadku pesymstycznym ego złożoność oblczenowa wynos Θ(n 2 ), gdze n est lczbą elementów tablcy, ale w przypadku średnm optymstycznym est ona równa Θ(n log 2 (n)), przy czym stałe ukryte w te notac są małe sortue tablcę w mescu, ale ego złożoność przestrzenna wynos O(n) Wynka to z faktu, że algorytm ten est rekurencyny est mplementowany z użycem rekurs, stąd zużywa pamęć na stose Można go zamplementować w sposób teracyny, ale est to dosyć złożona czynność, a efektywność wers teracyne ne est wększa od efektywnośc wers rekurencyne Sortowane wykonywane przez est sortowanem nestablnym 13 / 60 Metoda dzel zwycęża w Ida algorytmu może być zaprezentowana z użycem metody dzel zywcęża : Dzel: Tablca A[p r] est dzelona (wartośc e elementów są zamenane mescam) na dwa nepuste obszary A[p q] A[q + 1 r] take, że wartość każdego elementu z A[p q] ne est wększa od wartośc dowolnego elementu z A[q+1 r] Indeks q est wyznaczany przez podprogram dzelący Zwycęża: Dwa obszary A[p q] A[q + 1 r] są sortowane za pomocą rekurencynych wywołań algorytmu Połącz: Poneważ obszary są sortowane w mescu, to ne trzeba podemować żadnych dodatkowych dzałań, aby e połączyć: cała tablca A[p r] est uż posortowana 14 / 60 Funkca qucksort() 1 vod qucksort(nt_array_type array, nt low, nt hgh) 3 f(low<hgh) { 4 nt partton_ndex = partton(array,low,hgh); 5 qucksort(array, low, partton_ndex); 6 qucksort(array, partton_ndex+1, hgh); 7 } 8 } 15 / 60 Funkca qucksort() Funkca qucksort() dopowada krokow Zwycęża w zaprezentowane wcześne analze algorytmu z użycem metody dzel zwycęża Ne zwraca ona żadne wartośc, ale posada trzy parametry Przez perwszy przekazywana est tablca do posortowana, a przez drug trzec parametr ndeksy wyznaczaące obszar te tablcy, który ma być uporządkowany Początkowo, np przy wywołanu qucksort() z pozomu funkc man(), obszar ten obemue całą tablcę Wewnątrz qucksort() naperw sprawdzane est, czy wartość ndeksu początkowego obszaru (low) est mnesza od wartośc ndeksu końcowego obszaru (hgh) eśl tak, to oznacza to, że est eszcze obszar tablcy, który trzeba będze uporządkować, w przecwnym przypadku funkca zakończy swoe dzałane Jeśl warunek z wersza nr 3 est spełnony, to uruchamana est funkca partton(), która porządkue zadany obszar tablcy wyznacza punkt podzału tego obszaru na dwa mnesze Następne funkca qucksort() est wywoływana dwukrotne, dla każdego z obszarów z osobna 16 / 60
Funkca qucksort() Perwszy obszar porządkowany przez rekurencyne wywołane qucksort() obemue elementy tablcy, których ndeksy zawarte są mędzy ndeksem początkowym (low) ndeksem podzału (partton_ndex) Oba ndeksy są włączone do tego zakresu Drug obszar obemue elementy tablcy o ndeksach w zakrese od ndeksu podzału (ale bez nego) do ndeksu końcowego (hgh), włączne Funkca partton() est w programe zdefnowana przed qucksort(), ale ze względu na czytelność prezentac zostane opsana po ne 17 / 60 Funkca partton() 1 nt partton(nt_array_type array, nt low, nt hgh) 3 nt pvot = array[low]; 4 nt = low-1, = hgh+1; 5 6 whle(<) { 7 whle(array[--]>pvot) 8 ; 9 whle(array[++]<pvot) 10 ; 11 f(<) 12 swap(&array[],&array[]); 13 } 14 return ; 15 } 18 / 60 Funkca partton() Funkca partton() odpowada krokow Podzel z analzy algorytmu metodą dzel zwycęża Posada ona trzy parametry o takm samym znaczenu, ak parametry funkc qucksort(), a zwraca lczbę, która est ndeksem wyznaczaącym punkt podzału beżąco porządkowanego obszaru tablcy na dwa mnesze W trzecm werszu funkc est deklarowana ncowana zmenna o nazwe pvot, która zawera tzw wartość osuącą, czyl tą, według które będze porządkowany dany obszar tablcy Jako ta wartość przymowana est wartość perwszego elementu tablcy należącego do beżąco porządkowanego obszaru (wersz nr 3) W werszu nr 4 deklarowane ncowane są zmenne, które będą używane do ndeksowana porządkowanego obszaru od ego początku (zmenna ) od końca (zmenna ) Proszę zwrócć uwagę, że początkowo oba te ndeksy określaą elementy znaduące sę poza porządkowanym obszarem 19 / 60 Funkca partton() Zewnętrzna pętla whle (wersz nr 6) est wykonywana tak długo, ak długo wartość ndeksu est mnesza od wartośc ndeksu, nnym słowy tak długo aż te ndeksy sę ne pokryą lub ne mną Wewnątrz te pętl wykonywane są dwe kolene pętle whle Perwsza (wersze nr 7 8) przeszukue zadany obszar od końca ku początkow szukaąc elementu, którego wartość będze mnesza lub równa wartośc osuące Druga (wersze nr 9 10) przeszukue ten sam obszar w odwrotnym kerunku szukaąc elementu, którego wartość będze wększa lub równa wartośc osuące Proszę zwrócć uwagę na konstrukcę tych pętl Cała czynność przeszukwana odbywa sę w warunku pętl Zastosowano w nch predekrementacę prenkrementacę ndeksów, aby unknąć sęgana do elementów tablcy znaduących sę poza porządkowanym obszarem, a w nektórych przypadkach poza tablcą 20 / 60
Funkca partton() Po zakończenu obu pętl wewnętrznych w nstrukc warunkowe (wersz nr 11) funkca sprawdza, czy wartość ndeksu est mnesza od wartośc ndeksu Jeśl tak, to należy zamenć koleność wartośc elementów, które one określaą, bo ne est ona prawdłowa Jeśl ne, to zewnętrzna pętla whle sę zakończy, a ndeks będze określał punkt podzału dla porządkowanego obszaru tablcy, dlatego ego wartość est zwracana w werszu nr 14 Następny slad zawera drzewo lustruące dzałane funkc qucksort() dla neposortowane tablcy lczb naturalnych, o sedmu elementach W górne częśc drzewa zaznaczono, który fragment est wykonywany w funkc patton(), a który w qucksort() W dolne ne zastosowano tego rozwązana, aby ne zmneszać czytelnośc drzewa 21 / 60 8 4 3 10 1 5 9 5 4 3 10 1 8 9 partton 5 4 3 1 10 8 9 qucksort 5 4 3 1 1 4 3 5 partton 10 8 9 9 8 10 partton qucksort qucksort 1 4 3 5 9 8 8 9 10 1 4 3 3 4 8 9 3 4 22 / 60 Funkca man() 1 nt man(vod) 3 nt_array_type array; 4 fll_array(array); 5 prnt_array(array); 6 qucksort(array,0, 7 szeof(nt_array_type)/szeof(*array)-1); 8 prnt_array(array); 9 return 0; 10 } 23 / 60 Funkca man() W funkc man() została zdefnowana tablca typu nt_array_type (wersz nr 3), która następne est wypełnana przy pomocy funkc fll_array() lczbam całkowtym, wypsywana na ekrane przy pomocy prnt_array() sortowana z użycem funkc qucksort() Poneważ ako argumenty te funkc muszą być podane, oprócz tablcy, e ndeksy, to ako drug argument do te funkc przekazywana est wartość 0 (ndeks perwszego elementu) Jako trzec argument est przekazywana welkość tablcy wylczona dzęk takemu samemu wyrażenu, ak w funkc prnt_array(), pomneszona o eden Posortowana tablca est wypsywana na ekrane funkca man() kończy swoe dzałane zwracaąc wartość 0 24 / 60
Inne werse Istnee klka wers algorytmu, które w różny sposób są mplementowane Kolene slady zaweraą kody źródłowe nne popularne mplementac funkc qucksort() partton() Ne est ona tak efektywna, ak ta przedstawona wcześne, ale nektórzy nformatycy uważaą ą za bardze czytelną łatweszą do stworzena, a zatem daącą mne okaz do popełnena błędów 25 / 60 Funkca qucksort() wersa druga 1 vod qucksort(nt_array_type array, nt low, nt hgh) 3 f(low<hgh) { 4 nt partton_ndex = partton(array,low,hgh); 5 qucksort(array, low, partton_ndex-1); 6 qucksort(array, partton_ndex+1, hgh); 7 } 8 } 26 / 60 Funkca qucksort() wersa druga W przypadku funkc qucksort() zaprezentowane na poprzednm sladze est tylko eden szczegół, który różn ą od e poprzednczk zaprezentowane wcześne Obszar, który est porządkowany przez e perwsze wywołane rekurencyne ne zawera elementu tablcy określanego ndeksem partton_ndex (wersz nr 5) 27 / 60 Funkca partton() wersa druga 1 nt partton(nt_array_type array, nt low, nt hgh) 3 nt pvot = array[low], mddle = low, ; 4 5 for(=low+1; <=hgh; ++) 6 f(array[]<pvot) { 7 mddle++; 8 swap(&array[mddle],&array[]); 9 } 10 swap(&array[low],&array[mddle]); 11 return mddle; 12 } 28 / 60
Funkca partton() wersa druga W te mplementac funkc partton() użyta est tylko edna pętla est to pętla for Podobne ak poprzedno naperw deklarowanych est klka zmennych lokalnych Zmenna pvot ma take samo znaczene, ak w poprzedne wers Zmenna mddle to ndeks elementu, który pownen meć ostateczne element w porządkowanym obszarze, który będze zawerał wartość osuącą Zmenna est ndeksem pętl Idea te mplementac funkc partton() est następuąca: należy tak przestawć wartośc w elementach porządkowanego obszaru, aby wartośc mnesze od osuące znalazły sę po e lewe strone, a wększe po e prawe Skoro przymuemy za wartość osuącą wartość perwszego elementu tego obszaru, to należy naperw założyć, że wszystke pozostałe ego elementy maą wartość wększą lub równą osuące Jeśl tak ne est, to należy ch wartośc zamenć mescam Wykonywane est to w pozostałe częśc funkc 29 / 60 Funkca partton() wersa druga Proszę zwrócć uwagę na pętlę for Iterue ona po wszystkch elementach porządkowanego obszaru, poza perwszym Zatem ndeks est ncowany wartoścą o eden wększą od wartośc parametru low, a pętla kończona est dopero wtedy, gdy ego wartość przekroczy wartość parametru hgh W pętl, w nstrukc warunkowe (wersz nr 6) sprawdzane est, czy beżący element obszaru tablcy ma wartość mneszą od wartośc osuące Jeśl tak est, to zwększana est wartość ndeksu mddle wartość elementu przez nego określanego est zamenana mescam z wartoścą elementu określanego przez ndeks Po zakończenu pętl należy tylko wartość osuącą przemeścć we właścwe mesce obszaru, tzn z perwszego ego elementu do elementu określanego przez ndeks mddle Dokonywane est to w 10 werszu funkc Po ego wykonanu zwracana est wartość ndeksu mddle, która stanow punkt podzału obszaru 30 / 60 Funkca qsort() Algorytm est na tyle efektywny, że twórcy ęzyka C postanowl umeścć w standardowe bblotece funkcę qsort(), która go mplementue Je prototyp znadue sę w plku nagłówkowym stdlbh Funkca ta ne zwraca żadne wartośc, ale posada cztery parametry Przez perwszy, który est wskaźnkem typu vod * przekazywana est tablca do posortowana, przez drug przekazywana est lczba elementów te tablcy, a przez trzec rozmar poedynczego elementu Czwarty parametr to wskaźnk na funkcę porównuącą wartośc elementów tablcy, która pownna meć następuący prototyp: nt compare(const vod *, const vod *); Przez parametry do te funkc przekazywane są wskaźnk na porównywane elementy tablcy Jeśl wartość perwszego est mnesza od drugego, to funkca pownna zwrócć lczbę uemną, eśl wększa to dodatną, a eśl są równe, to 0 Tak sposób konstrukc qsort() pozwala e sortować tablce elementów dowolnego typu 31 / 60 Funkca qsort() Kolene slady zaweraą defncę funkc porównuące dla elementów tablcy typu nt oraz lustruą sposób wywołana qsort() dla te tablcy 32 / 60
Funkca compare_nt() 1 nt compare_nt(const vod *frst, const vod *second) 3 return *(nt *)frst - *(nt *)second; 4 } 33 / 60 Funkca compare_nt() Defnca te funkc est krótka Opsywana funkca ma dwa parametry wskaźnkowe o nazwach frst second Je treść stanow w zasadze eden wersz, w którym oba wskaźnk są naperw rzutowane na typ wskaźnkowy nt *, a następne wykonywana est ch dereferenca odemowane są od sebe wskazywane przez ne wartośc Jeśl wynk będze uemny, to perwsza est mnesza od druge, dodatn - zachodz mędzy nm odwrotna relaca, a zero oznacza, że są one sobe równe Ten wynk est zwracany funkca kończy swe dzałane 34 / 60 Funkca man() 1 nt man(vod) 3 nt_array_type array; 4 fll_array(array); 5 prnt_array(array); 6 qsort((vod*)array, 7 szeof(nt_array_type)/szeof(array[0]), 8 szeof(array[0]),compare_nt); 9 prnt_array(array); 10 return 0; 11 } 35 / 60 Funkca man() Wersze nr 6, 7 8 zaweraą nstrukcę wywołana qsort() Jako perwszy argument est przekazywany do ne wskaźnk na tablcę do uporządkowana Jest on rzutowany na typu vod * Następne przekazywana est lczba elementów te tablcy oblczona za pomocą wyrażena, które est użyte także w funkc fll_array() Jako trzec argument przekazywany est rozmar perwszego elementu te tablcy Może to być rozmar dowolnego elementu - wszystke są take same, ęzyk C gwarantue, że perwszy element tablcy zawsze będze stnał Jako ostatn argument wywołana przekazywany est wskaźnk (nazwa) funkc do porównywana wartośc elementów tablcy 36 / 60
Kopec Kopec, nazywany w polske lteraturze równeż stogem, est drzewem bnarnym, które ma kształt drzewa bnarnego pełnego lub zupełnego w którym zachodz własność kopca 1 Jeśl kopec est drzewem bnarnym zupełnym, to brak w węzłach ostatnego pozomu mogą występować tylko po ego prawe strone Kopec ne est naczęśce realzowany w postac dynamczne struktury danych, a odwzorowywany w tablcy, w ten sposób, że ako klucz węzła przymowany est ndeks elementu w tablcy, a ako wartość tego węzła wartość elementu Korzeń est zawsze odwzorowywany na perwszy element te tablcy Jeśl przymemy, że ta tablca est ndeksowana od 1 że ndex oznacza ndeks w tablcy węzła wewnętrznego kopca, to ndeks ego lewego potomka uzyskamy za pomocą wyrażena 2 ndex, prawego za pomocą 2 ndex + 1, a przodka za pomocą ndex/2, gdze / oznacza dzelene całkowte 1 W lteraturze angelske kopec est określany słowem heap, które z kole w polske termnolog nformatyczne oznacza stertę Aby ne powodować błędów nterpretac w nasze lteraturze wprowadzono odrębny termn 37 / 60 Kopec W ęzyku C tablce są ndeksowane od 0 Jeśl podstawmy za ndex choćby tę wartość, to przekonamy sę, że podane na poprzednm sladze wzory przestaną funkconować dla take tablcy Istneą dwa wyśca z te sytuac: można pomnąć perwszy element tablcy lub przekształcć odpowedno wzory My wyberzemy ten drug warant Zatem wyrażene do oblczana ndeksu przodka będze mało postać (ndex + 1)/2 Indeks lewego potomka wylczymy zaś korzystaąc ze wzoru: 2 ndex+1, a prawego z wyrażena: 2 ndex+2 Następny slad zawera lustracę kopca ego odwzorowana w tablcy ndeksowane od zera 38 / 60 Kopec 0 16 1 14 2 10 3 4 5 6 8 7 9 3 7 8 9 2 4 1 0 1 2 3 4 5 6 7 8 9 16 14 10 8 7 9 3 2 4 1 39 / 60 Kopec Przedstawony na poprzednm sladze kopec est kopcem maksmum (ang max-heap), tzn dla nego własność kopca est określona następuąco: A[parent()] A[], czyl wartość przodka dowolnego węzła est zawsze wększa lub równa wartośc tego węzła A oznacza tablcę Istneą także kopce mnmum (ang mnheap) Są to kopce, których własność est następuąca: A[parent()] A[] W dalsze częśc wykładu będzemy posługwać sę kopcem maksmum, który będzemy nazywać po prostu kopcem Relaca mędzy kopcem, a tablcą w które est on odwzorowany est określona nerównoścą rozmar kopca rozmar tablcy, gdze przez rozmar rozumemy lczbę elementów tablcy lub lczbę węzłów kopca Z te nerównośc wynka, że ne wszystke elementy tablcy muszą należeć do kopca 40 / 60
Kopce mogą być zastosowane do tworzena tzw koleek prorytetowych (ang prorty queue), ale nas będze nteresować na tym wykładze zastosowane ch w algorytme sortowana tablcy, który est spokrewnony z algorytmem sortowana przez wybór, a nazywa sę Ten algorytm, podobne ak realzue sortowane nestablne W porównanu do tego ostatnego est wolneszy, choć nadal należy do naszybszych algorytmów tego typu, za to ego złożoność oblczenowa wynos O(n log 2 (n)), dla wszystkch przypadków Może on być zrealzowany zarówno w postac rekurencyne (ta zostane przedstawona na wykładze), ak teracyne Na kolenych sladach przedstawone są kody źródłowe funkc oblczaących ndeksy prawego lewego potomka węzła (wylczane ndeksu przodka w tym algorytme ne est stosowane), a następne funkce, które przywracaą własność kopca, buduą kopec w końcu sortuą tablcę 41 / 60 Funkca get_left_chld_ndex() 1 statc nlne nt get_left_chld_ndex(nt ndex) 3 return (ndex << 1) + 1; 4 } 42 / 60 Funkca get_left_chld_ndex() Przedstawona na poprzednm sladze funkca wyznacza ndeks lewego potomka węzła kopca Aby przyspeszyć e dzane zamast operatora mnożena został zastosowany operator przesunęca btowego w lewo Możemy tak postąpć, bo drugm argumentem mnożena est 2 Dodatkowo est to funkca typu nlne, czyl est rozwana podobne ak makro, ale przez komplator (o le on na to pozwala), a ne preprocesor 43 / 60 Funkca get_rght_chld_ndex() 1 statc nlne nt get_rght_chld_ndex(nt ndex) 3 return (ndex << 1) + 2; 4 } 44 / 60
Funkca get_rght_chld_ndex() Funkca z poprzednego sladu wyznacza ndeks prawego potomka węzła Została ona napsana przy zastosowanu podobnych technk, ak e odpowednczka dla lewego węzła 45 / 60 Funkca heapfy() 1 vod heapfy(nt_array_type array, nt ndex, unsgned nt sze) 3 nt left = get_left_chld_ndex(ndex), 4 rght = get_rght_chld_ndex(ndex), 5 largest = ndex; 6 f(left<=sze) 7 f(array[left]>array[ndex]) 8 largest = left; 9 f(rght<=sze) 10 f(array[rght]>array[largest]) 11 largest = rght; 12 f(largest!=ndex) { 13 swap(&array[ndex],&array[largest]); 14 heapfy(array,largest,sze); 15 } 16 } 46 / 60 Funkca heapfy() Funkca heapfy() est podstawowym podprogramem w mplementac algorytmu Je zadanem est przywrócene własnośc kopca Ne zwraca ona żadnych wartośc, ale posada trzy parametry Przez perwszy est przekazywana do ne tablca z odwzorowanym kopcem, w którym est zaburzona wspomnana własność Przez drug parametr przekazywany est ndeks elementu, którego wartość potencalne zaburza tę własność Przez trzec parametr przekazywany est rozmar kopca Wewnątrz funkc naperw są wyznaczane zapamętywane w zmennych lokalnych left rght ndeksy lewego prawego potomka węzła, co do którego zachodz poderzene, że zaburza własność kopca (wersze nr 3 4), oraz w zmenne lokalne largest zapamętywana est wartość ndeksu tego węzła (wersz nr 5) Ta zmenna będze przechowywała ndeks tego węzła spośród wspomnane trók, który ma nawększą wartość Zatem w funkc wstępne przymuemy, że własność kopca ne est zaburzona 47 / 60 Funkca heapfy() Następne funkca sprawdza, czy lewy potomek węzła stnee, tzn czy ndeks zapamętany w left zwązany est z elementem, który meśc sę w kopcu (wersz nr 6) eśl tak est, to sprawdza, czy wartość tego potomka est wększa od wartośc przodka (wersz nr 7) Jeśl ten warunek okaże sę prawdzwy, to w zmenne largest est zapamętywany ego ndeks W werszu nr 8 w podobny sposób funkca sprawdza, czy stnee prawy potomek węzła Jeśl tak est, to funkca sprawdza, czy ego wartość est wększa od tego węzła, którego beżąco zmenna largest określa ako nawększy (o nawększe wartośc) Jest to na tym etape albo węzeł o ndekse ndex, albo ego lewy potomek Jeśl wartość prawego potomka est wększa od tego węzła, to ndeks tego potomka est zapamętywany w zmenne largest (wersz nr 11) Zatem po wykonanu wersza nr 11 we wspomnane zmenne znadue sę ndeks węzła o nawększe wartośc spośród trók: węzeł potencalne zaburzaący własność kopca, ego lewy prawy potomek 48 / 60
Funkca heapfy() W werszu nr 12 funkca sprawdza, czy wartość zmenne largest est różna od wartośc parametru ndex Jeśl tak by ne było, to oznaczałoby, że własność kopca ne była zakłócona funkca może zakończyć dzałane, ne wykonuąc żadnych dodatkowych czynnośc Jeśl ten warunek est ednak prawdzwy, to należy zamenć mescam wartośc w węzłach, których ndeksy określaą zmenne ndex largest (wersz nr 13) To może ednak spowodować przenesene zaburzena własnośc w dół kopca Teraz może ona ne zachodzć w poddrzewe, w którym węzeł o ndekse largest est korzenem Dlatego funkca heapfy() wywołue sę rekurencyne dla tego węzła (wersz nr 14) 49 / 60 Funkca buld_heap() 1 vod buld_heap(nt_array_type array) 3 nt ; 4 const nt number_of_elements = 5 szeof(nt_array_type)/szeof(*array); 6 for(=number_of_elements/2;>=0;--) 7 heapfy(array,,number_of_elements-1); 8 } 50 / 60 Funkca buld_heap() Funkca buld_heap() budue kopec w tablcy, która ma być posortowana Używa w tym celu opsane wcześne funkc heapfy() Ne zwraca ona żadne wartośc, a przez parametr przymue tablcę, w które utworzy kopec W werszach nr 4 5 zdefnowana est w te funkc stała, która określa lczbę elementów tablcy Kopec est budowany w pętl for Proszę zwrócć uwagę, że ta funkca terue po elementach tablcy rozpoczynaąc od środka tablcy przemeszczaąc sę ku elementow perwszemu Powstae pytane, dlaczego ne est porządkowana druga połowa tablcy Otóż funkca przymue, że rozmar kopca est równy rozmarow tablcy Zatem elementy należące do te połowy są lśćm kopca (lub, ak kto wol, tworzą ednoelementowe kopce) Stąd wywołuąc heapfy() dla elementów z perwsze połowy buld_heap() zapewna, że elementy w druge połowe też będą włączone do kopca - zadba o to heapfy() 51 / 60 Funkca heapsort() 1 vod heapsort(nt_array_type array) 3 nt last_ndex = szeof(nt_array_type)/szeof(*array)-1; 4 nt ; 5 6 buld_heap(array); 7 for(=last_ndex;>0;--){ 8 swap(&array[0],&array[]); 9 heapfy(array,0,--last_ndex); 10 } 11 } 52 / 60
Funkca heapsort() Funkca heapsort() dokonue właścwego sortowana tablcy Ne zwraca ona żadne wartośc, ale przez parametr przymue tablcę do posortowana Wewnątrz te funkc est zadeklarowana zancowana zmenna last_ndex, która zawera ndeks ostatnego elementu tablcy należącego do kopca wyznacza pośredno rozmar te struktury Funkca naperw budue kopec w tablcy poprzez wywołane buld_heap(), a następne w pętl for terue po całe tablcy, poczynaąc od elementu ostatnego (początkowo est to też ostatn element kopca) do elementu perwszego W czase tych terac zamena ona mescam wartość perwszego elementu z tym, który est określany przez lcznk pętl (zmenna ), a następne przywraca własność kopca poczynaąc od perwszego elementu tablcy Jake est uzasadnene dla tych czynnośc? Otóż, w kopcu nawększa wartość znadue sę w perwszym elemence tablcy, a w posortowane nemaleąco tablcy pownna sę ona znaleźć w ostatnm Należy zatem wartośc tych elementów zamenć mescam (wersz nr 8) Ta zamana może ednak zaburzyć własność kopca 53 / 60 Funkca heapsort() Aby ą przywrócć funkca heapsort() wywołue heapfy() dla perwszego elementu tablcy Tym razem ednak z kopca wyłączany est ostatn element tablcy, bo on est uż uporządkowany W każde kolene terac pętl for welkość kopca est zmneszana o eden zamenane są mescam wartośc w perwszym elemence tablcy (korzenu) elemence kopca o ndekse Po zakończenu te pętl cała tablca est uporządkowana 54 / 60 Funkca man() 1 nt man(vod) 3 nt_array_type array; 4 fll_array(array); 5 prnt_array(array); 6 heapsort(array); 7 prnt_array(array); 8 return 0; 9 } 55 / 60 Funkca man() Jedyna różnca w funkc man() mędzy przykładowym programam dla est taka, że zamast wywołana funkc qucksort() wywoływana est heapsort() (wersz nr 6) Jako argument e wywołana przekazywana est tablca do uporządkowana 56 / 60
Podsumowane Oba przedstawone algorytmy sortowana tablc należą do naszybszych w te kategor, ale w przypadku optymstycznym średnm przewagę wykazue Przypadkem pesymstycznym dla tego algorytmu, dla którego ego złożoność oblczenowa wynos Θ(n 2 ) est sortowane tablcy uż posortowane Wówczas algorytm dzel obszary tablcy na dwa, z których eden est ednoelementowy, a w drugm znaduą sę pozostałe elementy perwotnego obszaru Nalepsze dla tego algorytmu są podzały, w których nowe obszary otrzymuą po połowe elementów obszaru wyścowego Aby unknąć przypadku pesymstycznego stosowane są różne technk Można przez rozpoczęcem wykonana tego algorytmu zamenć mescam wartośc mędzy klkoma losowo wybranym elementam tablcy Ne ma wprawdze gwaranc, że to dzałane ne uporządkue tablcy, ale est duże prawdopodobeństwo, że zaburzy porządek wartośc, eśl tablca była uż uporządkowana Inny sposób polega na zamane tego algorytmu w algorytm probablstyczny, który wybera wartość osuącą (pseudo)losowo Żadna z tych technk ne dae ednak całkowte pewnośc, że przypadek pesymstyczny ne wystąp 57 / 60 Podsumowane Algorytm ma równeż tę przewagę nad algorytmem, że da sę wyelmnować z ego mplementac rekurencę, zatem ne będze ona tworzyła narzutu zwązanego z użycem pamęc na stose Złożoność przestrzenna tego algorytmu może zatem być stała 2 W praktyce algorytm wydae sę być częśce używany nż Jednak w nektórych zastosowanach bezpeczne est użyć tego drugego Przykładem mogą być usług zdalne, które używaą sortowana Jeśl użyty byłby w nch algorytm to mogłyby być one narażone na atak typu Denal of Servce (DoS) za pomocą żądań ch wykonana z odpowedno spreparowanym danym weścowym 2 Take mplementace algorytmu zostały opsane mn w ksążkach Perełk oprogramowana Jona Bentley a oraz Algorytmy struktury danych A V Aho, J E Hopcrofta J D Ullmana 58 / 60 Pytana? 59 / 60 konec Dzękuę Państwu za uwagę! 60 / 60