Quick sort, spojové struktury

Podobne dokumenty
TGH01 - Algoritmizace

Reprezentace dat. BI-PA1 Programování a Algoritmizace I. Ladislav Vagner

TGH01 - Algoritmizace

Komplexní analýza. Martin Bohata. Katedra matematiky FEL ČVUT v Praze Martin Bohata Komplexní analýza Mocninné řady 1 / 18

Aproximace funkcí 1,00 0,841 1,10 0,864 1,20 0,885. Body proložíme lomenou čarou.

Numerické metody 8. května FJFI ČVUT v Praze

Edita Pelantová, katedra matematiky / 16

Kristýna Kuncová. Matematika B2 18/19

(1) Derivace. Kristýna Kuncová. Matematika B2 17/18. Kristýna Kuncová (1) Derivace 1 / 35

Funkce zadané implicitně. 4. března 2019

Martin Pergel. 26. února Martin Pergel

Logika V. RNDr. Kateřina Trlifajová PhD. Katedra teoretické informatiky Fakulta informačních technologíı BI-MLO, ZS 2011/12

Úvodní informace. 18. února 2019

5. a 12. prosince 2018

Linea rnı (ne)za vislost

Matematika (KMI/PMATE)

Elementární funkce. Edita Pelantová. únor FJFI, ČVUT v Praze. katedra matematiky, FJFI, ČVUT v Praze

Necht je funkce f spojitá v intervalu a, b a má derivaci v (a, b). Pak existuje bod ξ (a, b) tak, že f(b) f(a) b a. Geometricky

Kapitola 4: Soustavy diferenciálních rovnic 1. řádu

Inverzní Z-transformace

Powyższe reguły to tylko jedna z wersji gry. Istnieje wiele innych wariantów, można też ustalać własne zasady. Miłej zabawy!

Matematika 2, vzorová písemka 1

Co nám prozradí derivace? 21. listopadu 2018

Geometrická nelinearita: úvod

wykład III uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C - zarządzanie pamięcią, struktury,

MATEMATIKA 3. Katedra matematiky a didaktiky matematiky Technická univerzita v Liberci

Struktury czyli rekordy w C/C++

Kristýna Kuncová. Matematika B2

Numerické metody minimalizace

1 Soustava lineárních rovnic

B0B99PRPA Procedurální programování

Internet a zdroje. (Zdroje na Internetu) Mgr. Petr Jakubec. Katedra fyzikální chemie Univerzita Palackého v Olomouci Tř. 17.

ZÁPADOČESKÁ UNIVERZITA V PLZNI FAKULTA PEDAGOGICKÁ Katedra matematiky. Dudek Martin. obor Matematická studia

Wykład 15. Literatura. Kompilatory. Elementarne różnice. Preprocesor. Słowa kluczowe

Vlastnosti. Příprava. Czech - 2 -

PARADIGMATA PROGRAMOVÁNÍ 1B

Temat: Dynamiczne przydzielanie i zwalnianie pamięci. Struktura listy operacje wstawiania, wyszukiwania oraz usuwania danych.

Wstęp do programowania 1

NÁVOD K POUŽITÍ KEZELÉSI KÉZIKÖNYV INSTRUKCJA OBSŁUGI NÁVOD NA POUŽÍVANIE. Česky. Magyar. Polski. Slovensky

Obsah Atributová tabulka Atributové dotazy. GIS1-2. cvičení. ČVUT v Praze, Fakulta stavební, katedra mapování a kartografie

Automatové modely. Stefan Ratschan. Fakulta informačních technologíı. Evropský sociální fond Praha & EU: Investujeme do vaší budoucnosti

TVL LED NÁVOD K POUŽITÍ NÁVOD NA POUŽITIE

Typy złożone. Struktury, pola bitowe i unie. Programowanie Proceduralne 1

WYKŁAD 10. Zmienne o złożonej budowie Statyczne i dynamiczne struktury danych: lista, kolejka, stos, drzewo. Programy: c5_1.c, c5_2, c5_3, c5_4, c5_5

Tablice, funkcje - wprowadzenie

TVL UMP2 NÁVOD K POUŽITÍ NÁVOD NA POUŽITIE

Funkcja (podprogram) void

Wskaźniki w C. Anna Gogolińska

podle přednášky doc. Eduarda Fuchse 16. prosince 2010

Programowanie Proceduralne

Wskaźniki. Programowanie Proceduralne 1

Wykład X. Programowanie. dr inż. Janusz Słupik. Gliwice, Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2016 Janusz Słupik

IJC Jazyk C. Petr Peringer peringer AT fit.vutbr.cz. (Verze: ) Božetěchova 2, Brno. Úvod ISO C libc C99 11 Debug C++ Link Opt...

ULS4805FE. Návod k použití Návod na použitie Instrukcja obsługi Instruction Manual Használatı utasítás. Licensed by Hyundai Corporation, Korea

B0B99PRPA Procedurální programování. Stanislav Vítek

ggplot2 Efektní vizualizace dat v prostředí jazyka R Martin Golasowski 8. prosince 2016

B0B99PRPA Procedurální programování

Petr Křemen FEL ČVUT. Petr Křemen (FEL ČVUT) Vysvětlování modelovacích chyb 133 / 156

HL24285SMART. Návod k použití Návod na použitie Instrukcja obsługi Használatı utasítás. Licensed by Hyundai Corporation, Korea

DFT. verze:

PA152,Implementace databázových systémů 2 / 25

Charakteristika jazyka C

Vybrané kapitoly z matematiky

Register and win!

Petr Hasil. c Petr Hasil (MUNI) Nekonečné řady MA III (M3100) 1 / 187

Uzupełnienie dot. przekazywania argumentów

Programowanie I C / C++ laboratorium 02 Składnia pętli, typy zmiennych, operatory

Pliki. Informacje ogólne. Obsługa plików w języku C

Podstawy programowania w języku C++

Návod k použití BUBNOVÁ SUŠIČKA

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Rovnice proudění Slapový model

(2) Funkce. Kristýna Kuncová. Matematika B2. Kristýna Kuncová (2) Funkce 1 / 25

Zwój Prawoskrętny. Vinutí Pravé

// Liczy srednie w wierszach i kolumnach tablicy "dwuwymiarowej" // Elementy tablicy są generowane losowo #include <stdio.h> #include <stdlib.

Obsah Před zahájením instalace a používání si prosím pečlivě přečtěte návod k použití.

Lineární algebra - iterační metody

Wykład VI. Programowanie. dr inż. Janusz Słupik. Gliwice, Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2014 Janusz Słupik

návod k použití instrukcja obsługi

MATEMATIKA 3 NUMERICKÉ METODY. Katedra matematiky a didaktiky matematiky Technická univerzita v Liberci

Západočeská univerzita v Plzni Fakulta aplikovaných věd. Katedra matematiky. Semestrální práce - matematika a byznys

Struktury. Przykład W8_1

DXDB 215 NÁVOD K POUŽITÍ NÁVOD NA POUŽITIE INSTRUKCJA OBSŁUGI USER MANUAL

Laplaceova transformace

Příručka k rychlé instalaci: NWD2105. Základní informace. 1. Instalace softwaru

Co to jest sterta? Sterta (ang. heap) to obszar pamięci udostępniany przez system operacyjny wszystkim działającym programom (procesom).

Cauchyova úloha pro obyčejnou diferenciální rovnici

Obsah. Zobrazení na osmistěn. 1 Zobrazení sféry po částech - obecné vlastnosti 2 Zobrazení na pravidelný konvexní mnohostěn

nowe operatory &. (kropka) * operator rzutowy ->, (przecinek) sizeof

Tablice w argumentach funkcji. Tablicy nie są przekazywane po wartości Tablicy są przekazywane przez referencje lub po wskaźniku

Podstawy programowania w języku C++

funkcje rekurencyjne Wykład 12. Podstawy programowania (język C) Funkcje rekurencyjne (1) Funkcje rekurencyjne (2)

Języki i metodyka programowania. Wskaźniki i tablice.

Wskaźniki. Przemysław Gawroński D-10, p marca Wykład 2. (Wykład 2) Wskaźniki 8 marca / 17

kontaktní modely (Winklerův, Pasternakův)

Pojem množiny nedefinujeme, pouze připomínáme, že množina je. Nejprve shrneme pojmy a fakta, které znáte ze střední školy.

Paradoxy geometrické pravděpodobnosti

Návod k použití Instrukcja obsługi Návod na používanie

Programowanie proceduralne INP001210WL rok akademicki 2015/16 semestr letni. Wykład 6. Karol Tarnowski A-1 p.

Shrnutí. Vladimír Brablec

Transkrypt:

Quick sort, spojové struktury BI-PA1 Programování a Algoritmizace 1 Miroslav Baĺık, Ladislav Vagner a Josef Vogel Katedra teoretické informatiky a Katedra softwarového inženýrství Fakulta informačních technologíı České vysoké učení technické v Praze xvagner@fit.cvut.cz, vogeljos@fit.cvut.cz 12., 21. a 22. prosince 2017

Přehled Datový typ struct (struktura, záznam) připomenutí. Algoritmus quick sort. Knihovní implementace quick sort, ukazatel na funkci. Spojové seznamy. Obousměrné spojové seznamy. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 2/39

Struktury opakování Deklarace struktury: struct jméno_struktury { položky seznam_proměnných; jméno struktury je jméno datového typu struct (nepovinné), seznam proměnných je seznam deklarovaných proměnných, proměnné odděleny čárkami (nepovinné), položky jsou jakéhokoli datového typu, s výjimkou struktury samé (rekurzivní deklarace struktury je zakázána), avšak položkou může být ukazatel na strukturu samou (struct jméno struktury * jmeno polozky). Deklarace proměnné: struct jméno_struktury seznam_proměnných; /* ok */ jméno_struktury seznam_proměnných; /* chybně v C */ M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 3/39

Struktury opakování Zkráceně může být datový typ struktura také deklarován: typedef struct jméno_struktury { položky jméno_typu; /* deklarace proměnných: */ jméno_typu seznam_proměnných; /* také ok: */ struct jméno_struktury jiný_seznam_proměnných; jméno typu je zkratka pro struct jméno struktury, jméno struktury je nepovinné ve výše uvedené deklaraci, jméno typu není povinné, ale použití typedef je podezřelé, když jméno typu není použito. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 4/39

Struktury příklad typedef struct TComplex { double real, imag; TCOMPLEX; TCOMPLEX a, *pa; struct TComplex b; Položky struktury jsou přístupné použitím dvou operátorů: tečka. se použije k přístupu k položce struktury, šipka -> se použije pro přístup k položce přes ukazatel na proměnnou typu struktura. a.real = 10; a.imag = a.real + 5; pa = &b; pa->real = 230; pa->imag = pa->real + a.imag; a = *pa; /* ok, kopie obsahu */ (*pa).real = (&a)->imag; /* ok, ale neobvyklé */ M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 5/39

Algoritmus Quick sort Merge sort má časovou složitost O(n log n). To je asymptoticky optimální, avšak má dvě nevýhody: skrytá multiplikativní konstanta není malá, algoritmus potřebuje další pamět ový prostor pole řazených prvků ještě jednou. Algoritmus Quick sort nemá tato omezení: skrytá multiplikativní konstanta je velmi malá, algoritmus nepotřebuje žádný další prostor, na druhé straně, v nejhorším případě je časová složitost O(n 2 ). Vstupní data musí mít speciální pořadí, aby se dosáhl nejhorší případ. Průměrná složitost je O(n log n). Empiricky je Quick sort nejrychlejší volbou. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 6/39

Algoritmus Quick princip Vybere se pivot. Ideálně má pivot hodnotu mediánu prvků pole. Algoritmus rozděĺı pole na dvě části a prohodí prvky tak, aby: dolní část obsahovala prvky menší než pivot, horní část obsahovala prvky větší nebo rovné pivotu. Obě části se řadí rekurzivně. Výběr pivota je rozhodující výběr je dobrý, když obě části jsou stejně velké. Při takové volbě je algoritmus nejrychlejší. Při špatném výběru je velikost pole zmenšena pouze o jeden prvek a algoritmus degraduje na kvadratickou složitost. Optimální hodnota pivota je medián, ale ten není znám, dokud pole neni seřazeno. Dobré implementace proto používají třeba medián z náhodně vybraných tří prvků pole. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 7/39

Algoritmus Quick sort příklad 5 11 14 7 9 4 20 1 Pivot: 7 5 1 4 7 9 14 20 11 Pivot: 5 Pivot: 14 4 1 5 7 9 11 20 14 Pivot: 4 Pivot: 11 Pivot: 20 1 4 5 7 9 11 14 20 Pivot: 7 1 4 5 7 9 11 14 20 M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 8/39

Knihovní funkce pro Quick sort Standardní knihovna C obsahuje implementaci algoritmu Quick sort. Prototyp funkce je obsažen v stdlib.h. Implementace je generická prvky pole, které jsou algoritmem řazeny, mohou být libovolného typu. Funkce qsort je kompletní implementací algoritmu Quick sort, až na vlastní porovnání: prvky pole musí být porovnány a zaměněny mezi sebou, záměna se provede bajt po bajtu, porovnání je různorodé, závisí na typu prvků pole a řadicím kritériu. Funkci, která porovnává dva prvky pole mezi sebou, dodává aplikační programátor v podobě ukazatele na funkci. Kdykoliv potřebuje algoritmus Quick sort porovnat nějaké prvky, zavolá tuto uživatelskou funkci. Volání probíhá prostřednictvím předaného ukazatele. Porovnávací funkci jsou dodány ukazatele na oba porovnávané prvky pole. Návratová hodnota je kladná, nulová nebo záporná pro hodnoty první větší než druhý, resp. rovné nebo menší. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 9/39

Knihovní funkce pro Quick sort #include <stdlib.h> int main( void ) { int a[9] = {1,5,9,3,6,4,89,23,11; int i; qsort( (void*)a, 9, sizeof(a[0]), intcompare ); /* intcompare je porovnávací funkce */ for(i = 0; i < 9 ; i ++ ) printf ( "%3d ",a[i] ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 10/39

Knihovní funkce pro Quick sort int intcompare ( const void *a, const void *b ) { int * aa, *bb; aa = (int*) a; bb = (int*) b; /* a b jsou ukazatele na porovnávané prvky pole, typ ukazatele - void * - musí být přetypován na typ ukazatele podle skutečného prvku pole, (zde int - ukazatele aa a bb) */ if ( *aa < *bb ) return -1; if ( *bb < *aa ) return 1; return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 11/39

Knihovní funkce pro Quick sort int intcompare ( const void *a, const void *b ) { int * aa, *bb; aa = (int*) a; bb = (int*) b; return *aa - *bb; /* kratší, často správné, ale není 100% OK */ M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 12/39

Knihovní funkce pro Quick sort int intcompare ( const void *a, const void *b ) { int * aa, *bb; aa = (int*) a; bb = (int*) b; return *aa - *bb; /* kratší, často správné, ale není 100% OK */ int intcompare ( const void *a, const void *b ) { return *(int*)a - *(int*)b; /* ještě kratší, ale opět není 100% OK */ M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 12/39

Knihovní funkce pro Quick sort /* Proč parametry const void *? Ty skutečně v naší implementaci ukazují na celá čísla */ int intcompare ( const int *a, const int *b ) { return *a - *b; /* pěkné - jednodušeji už nelze, ale stále není 100% OK */ /* Ale knihovní funkce qsort předpokládá jiné rozhraní funkce. Ok, přesvědčme kompilátor, že ten mišmaš funkčních ukazatelů je naše přání */... qsort( (void*)a, 9, sizeof(a[0]), ( int(*)(const void *, const void *) ) intcompare ); /* ukazatel na funkci je přetypován, aby se shodovaly očekávané typy */... M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 13/39

Quick sort porovnávací funkce, pro zvídavé Můžeme si dovolit přetypovat ukazatele na funkci dle libosti? M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 14/39

Quick sort porovnávací funkce, pro zvídavé Můžeme si dovolit přetypovat ukazatele na funkci dle libosti? Ne. Kompilátor naše přetypování sice akceptuje, ale při neuváženém přetypování je pravděpodobný pád programu. Proč tedy zde přetypování funguje? M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 14/39

Quick sort porovnávací funkce, pro zvídavé Můžeme si dovolit přetypovat ukazatele na funkci dle libosti? Ne. Kompilátor naše přetypování sice akceptuje, ale při neuváženém přetypování je pravděpodobný pád programu. Proč tedy zde přetypování funguje? Protože to není libovolné přetypování: funkce qsort připraví pro porovnávací funkci dva parametry typu ukazatel (odkazují na porovnávané prvky). Skutečně volaná funkce má také dva parametry typu ukazatel, liší se typy ukazatelů na prvky, ale jejich pamět ová reprezentace za běhu je stejná (4/8 B v paměti), funkce qsort zavolá funkci odkazovanou předaným ukazatelem na funkci, námi dodaný ukazatel odkazuje na platnou funkci, očekává se návratová hodnota typu int, námi dodaná funkce vrací typ int. Co tedy toto přetypování ukazatele na funkci fakticky udělá? M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 14/39

Quick sort porovnávací funkce, pro zvídavé Můžeme si dovolit přetypovat ukazatele na funkci dle libosti? Ne. Kompilátor naše přetypování sice akceptuje, ale při neuváženém přetypování je pravděpodobný pád programu. Proč tedy zde přetypování funguje? Protože to není libovolné přetypování: funkce qsort připraví pro porovnávací funkci dva parametry typu ukazatel (odkazují na porovnávané prvky). Skutečně volaná funkce má také dva parametry typu ukazatel, liší se typy ukazatelů na prvky, ale jejich pamět ová reprezentace za běhu je stejná (4/8 B v paměti), funkce qsort zavolá funkci odkazovanou předaným ukazatelem na funkci, námi dodaný ukazatel odkazuje na platnou funkci, očekává se návratová hodnota typu int, námi dodaná funkce vrací typ int. Co tedy toto přetypování ukazatele na funkci fakticky udělá? Nic. Ve výsledném programu se toto přetypování neprojeví žádným výkonným kódem. Přetypování pouze potlačí chybu/varování kompilátoru. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 14/39

Quick sort porovnávací funkce, pro zvídavé Opravdu lze v porovnávací funkci odečítat místo porovnání? M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 15/39

Quick sort porovnávací funkce, pro zvídavé Opravdu lze v porovnávací funkci odečítat místo porovnání? Obecně nelze. Pokud dochází k přetékání, výsledné pole nebude správně seřazené. Zkuste si pro pole celých čísel s hodnotami pobĺıž horního a dolního limitu typu int. Lze trik s odečítáním použít pro desetinná čísla? M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 15/39

Quick sort porovnávací funkce, pro zvídavé Opravdu lze v porovnávací funkci odečítat místo porovnání? Obecně nelze. Pokud dochází k přetékání, výsledné pole nebude správně seřazené. Zkuste si pro pole celých čísel s hodnotami pobĺıž horního a dolního limitu typu int. Lze trik s odečítáním použít pro desetinná čísla? Nelze. Pokud je výsledkem odečítání číslo v intervalu (-1,+1), bude v návratovém typu převedeno na hodnotu 0 int, tedy taková desetinná čísla budou pro porovnání shodná. Lze trik s odečítáním použít pro typy char / short int? M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 15/39

Quick sort porovnávací funkce, pro zvídavé Opravdu lze v porovnávací funkci odečítat místo porovnání? Obecně nelze. Pokud dochází k přetékání, výsledné pole nebude správně seřazené. Zkuste si pro pole celých čísel s hodnotami pobĺıž horního a dolního limitu typu int. Lze trik s odečítáním použít pro desetinná čísla? Nelze. Pokud je výsledkem odečítání číslo v intervalu (-1,+1), bude v návratovém typu převedeno na hodnotu 0 int, tedy taková desetinná čísla budou pro porovnání shodná. Lze trik s odečítáním použít pro typy char / short int? Obecně nelze, ale téměř jistě to bude vždy správně fungovat. Podle normy jazyka se před odečtením char / short int musí rozšířít na celé číslo (integer promotion) a v datovém typu int se provede vlastní operace. Pokud je rozsah char / short int menší než rozsah typu int, nemůže dojít k přetečení. I tak je ale lepší se triku vyhnout. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 15/39

Quick sort porovnávací funkce, pro zvídavé int intcmpwrong ( const int * a, const int * b ) { return *a - *b; int dblcmpwrong ( const double * a, const double * b ) { return *a - *b; int a[]={ 1000000000, -1000000000, 2000000000, -2000000000 ; qsort ( a, sizeof ( a ) / sizeof ( a[0] ), sizeof ( a[0] ), (int(*)(const void *, const void *)) intcmpwrong ); /* 2000000000-2000000000 -1000000000 1000000000 */ double b [] = { 1.2, 1.3, 1.8, 1.5, 1.7, 1.1, 1.4 ; qsort ( b, sizeof ( b ) / sizeof ( b[0] ), sizeof ( b[0] ), (int(*)(const void *, const void *)) dblcmpwrong ); /* 1.2 1.3 1.8 1.5 1.7 1.1 1.4 */ M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 16/39

Quick sort porovnávací funkce, pro zvídavé Proč se tedy trik s odečítáním ukazuje? M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 17/39

Quick sort porovnávací funkce, pro zvídavé Proč se tedy trik s odečítáním ukazuje? Kód lze často najít v existujícím software a literatuře. Vše funguje, dokud nedojde k přetečení. Tím je trik zákeřný většinou funguje, ale není 100% správný. Vyhněte se mu. Jak tedy správně? M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 17/39

Quick sort porovnávací funkce, pro zvídavé Proč se tedy trik s odečítáním ukazuje? Kód lze často najít v existujícím software a literatuře. Vše funguje, dokud nedojde k přetečení. Tím je trik zákeřný většinou funguje, ale není 100% správný. Vyhněte se mu. Jak tedy správně? int intcompare ( const int *a, const int *b ) { return ( *b < *a ) - ( *a < *b ); /* OK! */ int dblcompare ( const double *a, const double *b ) { return ( *b < *a ) - ( *a < *b ); /* OK! */ int shortcompare ( const short *a, const short *b ) { return ( *b < *a ) - ( *a < *b ); /* OK! */ M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 17/39

Seřazení studentů knihovní funkcí qsort () Seřazení pole studentů podle průměrného prospěchu: #include <stdlib.h> typedef struct TStudent { char name[name_max], surname [NAME_MAX]; double avg; TSTUDENT; int studentcompare ( TSTUDENT *a, TSTUDENT *b ) { return (b->avg < a->avg) - (a->avg < b->avg); void sortstudents (TSTUDENT a[], int n ) { qsort ( (void*)a, n, sizeof(a[0]), (int(*) (const void *, const void *)) studentcompare ); M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 18/39

Seřazení studentů knihovní funkcí qsort () Seřazení pole studentů podle průměrného prospěchu: #include <stdlib.h> typedef struct TStudent { char name[name_max], surname [NAME_MAX]; double avg; TSTUDENT; int studentcompare ( TSTUDENT *a, TSTUDENT *b ) { return (b->avg < a->avg) - (a->avg < b->avg); void sortstudents (TSTUDENT a[], int n ) { qsort ( (void*)a, n, sizeof(a[0]), (int(*) (const void *, const void *)) studentcompare ); Pořadí studentů se stejným průměrem není po seřazení definováno, může být stejné i obrácené než bylo v původním poli (Quick sort může pořadí zachovat, ale může i prvky prohodit). Takové řazení se nazývá nestabilní. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 18/39

Seřazení studentů knihovní funkcí qsort () Pokud bychom chtěli, aby dalším kritériem pro pořadí bylo navíc abecední pořadí příjmení a jména, museli bychom porovnání upravit třeba takto: #include <string.h> int studentcompare ( TSTUDENT *a, TSTUDENT *b ) { int res = (b->avg < a->avg) - (a->avg < b->avg); if (res) return res; if (( res = strncmp ( a->surname, b->surname, NAME_MAX ))) return res; return strncmp ( a->name, b->name, NAME_MAX ); M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 19/39

Spojové struktury seznam Problém: program čte celá čísla ze vstupu (až do EOF). Vstup je pak zobrazen v obráceném pořadí. Rekurzivní řešení (hloubka rekurze). Uložení do pole (musí být dána velikost pole). Uložení do zřetězeného seznamu: struktura je dynamicky alokována pro každé vstupující číslo, struktura obsahuje hodnotu čísla a ukazatel na strukturu obsahující předchozí číslo ze sekvence (následující v řetězu). struktura obsahující první číslo (poslední v řetězu) má prázdný ukazatel (hodnota NULL). Input sequence: 56, 8, 5 Head Dynamically allocated structures 5 8 56 M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 20/39

Spojový seznam typedef struct TElement { int val; struct TElement *next; TELEMENT; TELEMENT * createelement ( int val, TELEMENT * next ) { TELEMENT * n; n = (TELEMENT *)malloc ( sizeof (*n) ); n->val = val; n->next = next; return n; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 21/39

Spojový seznam Problém obrácení vstupní sekvence: začátek s prázdným seznamem, čtení čísla ze vstupu, přidání čísla přidání do seznamu dopředu (na první pozici), opakuje se až do konce vstupu, zobrazí se hodnoty ze seznamu (seznam je už obrácený). M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 22/39

Spojový seznam int main ( void ) { TELEMENT * st = NULL, *p; int x; printf ( "Napis sekvenci cisel:\n" ); while ( scanf ( "%d", &x ) == 1 ) st = createelement ( x, st ); printf ( "Obracene:\n" ); p = st; while ( p ) { printf ( "%d ", p->val ); p = p->next; printf ( "\n" ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 23/39

Spojový seznam Potřebujeme další ukazatel (p) pro čtení hodnot?... printf ( "Obracene:\n" ); while (st) { printf ( "%d ", st->val ); st = st->next; /* jejda */... Když je hlava seznamu ztracena (ukazatel st je změněn), neexistuje žádný způsob, jak najít hlavu seznamu. Seznam je ztracen. Čtení spojového seznamu tedy vždy využívá pomocný ukazatel na prvek seznamu. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 24/39

Spojový seznam Jak uvolnit pamět alokovanou spojovým seznamem? Špatné řešení:... while ( st ) { free ( st ); st = st->next; /* může selhat - přistupuje k již uvolněné paměti */ Správné řešení:... while ( st ) { TELEMENT * p = st->next; /* ukazatel je zachován */ free ( st ); st = p; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 25/39

Spojový seznam Jiný problém: Čtení sekvence celých čísel, jejich uložení do zřetězeného seznamu. Sekvence bude zakončena EOF. Duplikované hodnoty se neukládají. Hodnoty budou uloženy v obráceném pořadí. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 26/39

Spojový seznam void printlist ( TELEMENT *st ) { while ( st ) { printf ( "%d ", st->val ); st = st->next; /* ok - modifikujeme jen lokální proměnnou */ printf ( "\n" ); int isinlist (TELEMENT * st, int x) { while ( st && st->val!= x ) st = st->next; return st!= NULL; void freelist ( TELEMENT * st ) { while ( st ) { TELEMENT * p = st->next; free ( st ); st = p; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 27/39

Spojový seznam int main ( void ) { TELEMENT *st = NULL, *p; int x; printf ( "Napis sekvenci:\n" ); while ( scanf ( "%d", &x ) == 1 ) if (! isinlist ( st, x ) ) st = createelement (x, st); printf ( "Obracene, duplicity odstraneny:\n"); printlist ( st ); freelist ( st ); st = NULL; /* trochu paranoidní */ return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 28/39

Spojový seznam Vytvořili jsme nový seznam a nový prvek jsme zařadili na začátek seznamu. Proto seznam obsahuje hodnoty v obráceném pořadí. Modifikujme program tak, abychom prvky přidávali na jeho konec (pořadí zachováno): Když je seznam prázdný, tak prvek nahradí hodnotu NULL, je-li neprázdný, musíme najít poslední prvek a zde připojit prvek s novou hodnotou. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 29/39

Spojový seznam TELEMENT * appendend ( TELEMENT *st, int x ) { TELEMENT * tmp; /* prázdný seznam */ if (! st ) return createelement ( x, NULL ); /* neprázdný - najít poslední prvek */ for ( tmp = st; tmp->next; tmp = tmp->next ) { tmp->next = createelement ( x, NULL ); return st;... while ( scanf ( "%d", &x ) == 1 ) if (! isinlist ( st, x ) ) st = appendend (st, x); M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 30/39

Spojový seznam Vložení prvého prvku potřebuje konstantní čas O(1). Připojení dalšího prvku vyžaduje nalezení konce seznamu O(n), kde n je délka seznamu. Když vynecháme hledání duplicit (které má lineární složitost O(n)), můžeme algoritmus optimalizovat na konstantní složitost O(1). K tomu použijeme další ukazatel, který ukazuje na poslední prvek seznamu: ukazatel bude na počátku nastaven na NULL pro prázdný seznam, ukazatel bude aktualizován při při každém přidání prvku na konec seznamu. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 31/39

Spojový seznam int main ( void ) { TELEMENT *st = NULL, *en = NULL, *p; int x; printf ( "Napis sekvenci:\n" ); while ( scanf ( "%d", &x ) == 1 ) { p = createelement ( x, NULL ); if ( en == NULL ) st = p; /* prázdný seznam */ else en->next = p; en = p; /* aktualizace ukazatele na poslední prvek */... M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 32/39

Spojový seznam zarážka Zarážka je jeden prvek navíc na konci spojového senzamu. Neobsahuje užitečná data, pouze zjednodušuje některé operace: např. lze vypustit if v cyklu. Tím se program trochu urychĺı (nikoli však z hlediska asymptotické složitosti) a také zcela zmizí problém prvého vložení do seznamu. Operace připojení, vkládání a mazání musí zachovat zarážku na konci seznamu. Čtecí operace musí zarážku přeskočit. Prázdný seznam je reprezentován jediným prvkem zarážkou. st Linked list with sentinel Input sequence: 5, 8 5 8?? en M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 33/39

Spojový seznam zarážka int main ( void ) { TELEMENT *st, *en; int x; /* inicializace seznamu se zarážkou */ st = en = malloc ( sizeof(*en) ); printf ( "Napis sekvenci cisel:\n" ); while ( scanf ( "%d", &x ) == 1 ) en = appendend ( x, en ); printlist ( st, en ); freelist ( st, en ); TELEMENT * appendend ( int x, TELEMENT * en ) { TELEMENT *p = en; en = malloc ( sizeof(*en) ); p->val = x; p->next = en; return en; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 34/39

Spojový seznam zarážka void printlist ( TELEMENT * st, TELEMENT * en ) { while ( st!= en ) { printf ( "%d ", st->val ); st = st->next; printf ( "\n" ); void freelist ( TELEMENT * st, TELEMENT * en) { while ( st!= en ) { TELEMENT * p = st->next; free ( st ); st = p; free ( en ); M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 35/39

Spojový seznam Údržba seřazeného spojového seznamu vyžaduje vkládání prvků kamkoli v seznamu (na začátek, na konec, dovnitř) Tato operace vyžaduje čas O(n). Neexistuje žádný jednoduchý trik, jak tento algoritmus urychlit. Při vložení prvku budeme vždy modifikovat dva ukazatele. Když udržujeme ukazatel na poslední prvek, musíme modifikovat ještě tento ukazatel, je-li nový prvek je poslední v seznamu. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 36/39

Spojový seznam int main ( void ) { TELEMENT *st = NULL, *en = NULL, *tmp, *prev; int x; printf ( "Napis sekvenci:\n" ); while ( scanf ( "%d", &x ) == 1 ) { prev = NULL; for ( tmp = st; tmp && tmp->val <= x; tmp = tmp->next ) prev = tmp; if ( prev == NULL ) { /* první v seznamu */ st = createelement ( x, st ); if (! en ) en = st; else { /* dovnitř nebo na konec */ prev->next = createelement ( x, prev->next ); if ( prev == en ) en = en->next;... M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 37/39

Spojové struktury Spojové seznamy jsou jednoduché spojové struktury. Spoje propojují prvky spojové struktury. Spoje vytvářejí relaci předchůdce následník. Spojové seznamy jsou lineární struktury každý prvek má nejvíce jednoho následníka. Single linked list Cyclic single linked list Double linked list M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 38/39

Otázky a odpovědi Otázky... M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Spojové struktury, BI-PA1 39/39