Pole, Řetězce 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 7., 9. a 10. listopadu 2017
Přehled Pole (deklarace, použití). Pole příklady. Řetězce. Multidimenzionální pole (matice). M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 2/43
Pole motivace Problém: uložit změřené teploty pro každý den týdne, spočítat průměrnou teplotu (v týdnu), zobrazit průměr, zobrazit rozdíl mezi naměřenou a průměrnou teplotou pro každý den týdne. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 3/43
Pole motivace int main ( void ) { int t1,t2,t3,t4,t5,t6,t7,avg; printf ( "Napis zmerene teploty (7 x):\n" ); scanf ( "%d%d%d%d%d%d%d", &t1,&t2,&t3,&t4,&t5,&t6,&t7 ); avg = (t1 + t2 + t3 + t4 + t5 + t6 + t7) / 7; printf ( "Prumerna teplota: %d\n", avg ); printf ( "Nedelni diference: %d\n", t1 - avg ); printf ( "Pondelni diference: %d\n", t2 - avg );... printf ( "Sobotni diference: %d\n", t7 - avg ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 4/43
Pole motivace Naivní řešení je nešikovné: program je rozvláčný, některé příkazy se opakují (pouze s malými modifikacemi), program není škálovatelný (průměr za měsíc, za rok). Problém může být elegantněji vyřešen pomocí pole (array). Pole je strukturovaný datový typ skládající se nějakých prvků (buněk), které jsou všechny stejného typu. Prvek pole je identifikován svým indexem (celočíselnou hodnotou). V jazyce C jsou indexy čísla 0, 1,..., array size - 1. Velikost pole (array size) je dána jeho deklarací. Za běhu nemůže být změněna (pro statická pole). M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 5/43
Pole motivace Pole bude použito pro uložení hodnot teploty: int temp[7] Vstupní hodnoty budou čteny ve for cyklu: for ( i = 0; i < 7; i ++ ) scanf ( "%d", &temp[i] ); Průměr bude opět počítán cyklem: avg = 0; for ( i = 0; i < 7; i ++ ) avg += temp[i]; avg /=7; A závěrečný report: for ( i = 0; i < 7; i ++ ) printf ( "diference: %d\n", temp[i] - avg ); M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 6/43
Pole Pole p obsahující n prvků typu T se deklaruje: T p[n] T n p je libovolný datový typ, je kladná celočíselná konstanta a je jméno proměnné (identifikátor). Je-li pole globální proměnná (mající rozsah platnosti v celém souboru), pak je počáteční obsah všech prvků pole definován - samé nulové bajty. Je-li pole lokální proměnná (deklarovaná v bloku funkce), pak je počáteční obsah pole nedefinován. Prvky pole jsou přístupné pomocí indexu: p[i] M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 7/43
Pole meze Indexování pole: p[i] je-li i nezáporná hodnota a i je menší než počet prvků pole (dimenze pole) p, pak p[i] je proměnná typu T, když i není v rozsahu indexu pole, tak p[i] znamená nějaké místo v paměti. Čtení nebo zápis na takové místo paměti může mít fatální následky (abnormální konec programu, přepis dat, ztrátu dat,... ), indexy pole nejsou testovány za běhu programu. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 8/43
Pole meze int a; int b[4]; int c; a b c b[0] b[1] b[2] b[3] b[0] = 10 b[4] = 20 Indexování mimo meze není za běhu programu testováno: chování programu je nedefinované, chování se může lišit podle kompilátoru a operačního systému, indexování mimo meze (out-of-bounds) se obtížně ladí. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 9/43
Pole sekvence #include <stdio.h> #define DAYS_MAX 100 int main ( void ) { int temp[days_max], n, avg=0, i; printf ( "Napis pocet dni (1.. %d):\n", DAYS_MAX ); scanf ( "%d", &n ); printf ( "Napis teploty (%d x):\n", n ); for ( i = 0; i < n; i ++ ) scanf ( "%d", &temp[i] ); for ( i = 0; i < n; i ++ ) avg += temp[i]; avg /= n; printf ( "Prumerna teplota: %d\n", avg ); printf ( "diference:\n" ); for ( i = 0; i < n; i ++ ) printf ( "%d ", temp[i] - avg ); printf( "\n" ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 10/43
Pole sekvence Co když uživatel napíše počet dní větší než DAYS MAX? int readint ( int min, int max ) { int x; scanf ( "%d", &x ); while ( x < min x > max ) { printf ( "Spatne, prosim napsat znovu:"); scanf ( "%d",&x ); return x;... printf ( "Napis pocet dni (1.. %d):\n", DAYS_MAX ); n = readint ( 1, DAYS_MAX ); printf("napis teploty (%d x):\n", n );... M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 11/43
Pole sekvence Obrácení vstupu (verze s polem). #include <stdio.h> #define ARRAY_MAX 100 int main ( void ) { int arr[array_max], x, i = 0; printf ( "Napis sekvenci, maximum %d cisel, " "zakoncenou nulou\n", ARRAY_MAX ); do { scanf ( "%d", &x ); arr[i++] = x; while ( x!= 0 && i < ARRAY_MAX ); for ( i = i - 1; i >= 0; i -- ) printf ( "%d ", arr[i] ); printf ( "\n" ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 12/43
Pole jako tabulka V předchozích příkladech byly do poĺı uloženy sekvence. Pole mohou být použity i pro tabulky dvojice (index, hodnota). Toto mapování přiřadí hodnotě indexu příslušný prvek pole. Jednoduchý příklad Přečíst sekvenci přirozených čísel z intervalu od 1 do 100, včetně mezí, a sestavit tabulku četnosti hodnot sekvence. Tabulka bude obsahovat 100 prvků typu int. Hodnota frq[x] bude reprezentovat počet výskytů čísla x+1 v sekvenci. Tabulku deklarujeme jako globální pole, tedy její prvky budou na počátku nulové. (Globální pole ale není ideální řešení.) Použijeme dvě funkce na manipulaci s polem: readnumbers() čte prvky ze standardního vstupu a plní frekvenční tabulku, printtable() vypisuje obsah tabulky četnosti. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 13/43
Pole jako tabulka int frq[100]; void readnumbers ( void ) { int x; printf ( "Napis cisla, zakonceni nulou\n" ); scanf ( "%d", &x ); while ( x!= 0 ) { if ( x >= 1 && x <= 100 ) frq[x-1] ++; scanf ( "%d", &x ); void printtable ( void ) { int i; for ( i = 1; i <= 100; i ++ ) if ( frq[i-1] ) printf ( "%2d vyskyt %d krat\n",i, frq[i-1] ); M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 14/43
Pole jako tabulka Modifikace tabulka četnosti pro rozsah od MIN do MAX #define MIN 1 #define MAX 100 int frq[max-min+1]; void readnumbers ( void ) { int x; printf ( "Napis cisla zakoncena nulou\n"); scanf ( "%d", &x ); while ( x!=0 ) { if ( x >= MIN && x <= MAX) frq[x-min] ++; scanf ( "%d", &x ); void printtable ( void ) { int i; for ( i = MIN; i <= MAX; i ++ ) if ( frq[i-min] ) printf ( "%2d vyskyt %d krat\n",i, frq[i-min] ); M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 15/43
Pole jako parametr funkce Problém program čte dva vektory a počítá jejich skalární součin. Dimenze vektorů jsou dány konstantou MAX. Vektory jsou čteny funkcí readvector(). void readvector (int v[], int n ) { int i; printf ( "Napis %d konponent vektoru:\n", n); for ( i = 0; i < n; i ++ ) scanf ( "%d", &v[i] ); M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 16/43
Pole jako parametr funkce Skalární součin počítá funkce dotproduct(): int dotproduct ( int x[], int y[], int n ) { int i, s = 0; for ( i = 0; i < n; i ++ ) s += x[i] * y[i]; return s; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 17/43
Pole jako parametr funkce #define MAX 100 int readint( int min, int max ) {... void readvector ( int v[], int n ) {... int dotproduct( int x[], int y[], int n ) {... int main ( void ) { int x[max], y[max], n; printf ( "Pocet komponent vektoru (1.. %d):\n", MAX ); n = readint( 1, MAX ); printf ( "vektor x\n" ); readvector ( x, n ); printf ( "vektor y\n" ); readvector (y, n ); printf ( "Skalarni soucin: %d\n", dotproduct(x, y, n)); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 18/43
Pole jako parametr funkce shrnutí Funkce deklaruje pole s prvky typu T jako parametr ve dvou variantách: T arr[] T * arr Obě možnosti jsou jak z pohledu syntaxe, tak implementace, ekvivalentní. Parametr arr slouží pro přístup k prvku pole obvyklým způsobem: arr[i] Skutečným parametrem je pole, jehož prvky musí být typu T, libovolné velikosti. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 19/43
Pole jako parametr funkce shrnutí Funkce nezná velikost předaného pole. Parametr arr nemá tuto informaci. Hodnota parametru předaná funkci je pouze adresa pole v paměti (ukazatel na počátek pole). Pozor: sizeof ( arr ) vrací délku ukazatele, nikoli velikost pole (tj. skutečný počet prvků pole)! Pokud funkce potřebuje znát skutečný počet prvků pole, je třeba předat další parametr, třeba int nrelem. Jaký je rozdíl mezi polem parametrem funkce a výstupním parametrem? M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 20/43
Řetězce Řetězcový literál je sekvence znaků uzavřená do uvozovek: "Toto je retezec" "jeste jiny retezec\n" "Rekl \"Ahoj!\"\n" "" Reprezentace řetězců v paměti: pole znaků, prvek pole má datový typ char, řetězec je zakončen nulovým znakem (nulový bajt znak \0 ). Řetězcové proměnné: pole znaků, char astring[10] je proměnná, která může obsahovat řetězec dlouhý až 9 znaků (jeden znak je třeba pro zakončení nulovým znakem). M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 21/43
Řetězce Operace s řetězci funkce ve standardní knihovně. Hlavičkový soubor: #include <string.h> Některé důležité funkce: strcpy kopírování řetězce (nebezpečné), strcat připojení řetězce za řetězec (nebezpečné), strcmp porovnání dvou řetězců, strlen délka řetězce, strncpy kopírování řetězce (bezpečná varianta), strncat připojení řetězce za řetězec (bezpečná varianta). Společný problém nebezpečné varianty netestují, zda se výsledný řetězec vejde do cílového pole. Je-li řetězec příliš dlouhý, přepíše se pamět! M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 22/43
int main(void) { char w1[max_len], w2[max_len], gt[max_len]; printf ( "Napis prvni slovo:\n" ); scanf ( "%s", w1 ); printf ( "Napis druhe slovo:\n" ); scanf ( "%s", w2 ); /* scanf %s konverze čte slovo ze vstupu, bílé znaky (mezery, tabulátory, nové řádky) jsou oddělovače */ M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 23/43 Řetězce příklad Přečíst dvě slova. Vypsat jejich délku. Najít a vypsat lexikograficky větší slovo. #include <stdio.h> #include <string.h> #define MAX_LEN 100
Řetězce příklad printf ( "%s, delka je %d znaku\n", w1, strlen(w1)); printf ( "%s, delka je %d znaku\n", w2, strlen(w2)); if ( strcmp ( w1, w2 ) > 0 ) strcpy ( gt, w1 ); else strcpy ( gt, w2 ); printf("vetsi slovo %s\n", gt ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 24/43
Řetězce příklad Program může havarovat, když na vstupu bude slovo delší než 99 znaků. Tato technika se nazývá přeplnění bufferu ( buffer overflow ). Je to obecná metoda, jak se nabourat do vzdáleného systému. K zamezení této zranitelnosti je vhodné vždy omezit max. délku vstupního řetězce:... scanf ( "%99s", w1 ); /* 99 znaků max. */... Dále je dobrou technikou vždy omezit délku i při kopírovacích operacích (zde nelze zneužít k nabourání se do vzdáleného sytému, ale je to dobré obecné opatření pro bezpečnost programu):... strncpy ( gt, w1, sizeof ( gt ) ); /* strncpy místo strcpy */ M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 25/43
Řetězce příklad Slovo pozpátku: #include <stdio.h> #include <string.h> #define MAX_LEN 100 void reverse ( char w[] ); int main ( void ) { char w[max_len]; printf ("Napis slovo:\n"); scanf ( "%99s", w ); reverse ( w ); printf ( "Pozpatku: %s\n", w ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 26/43
Řetězce příklad void reverse ( char w[] ) { int len = strlen ( w ), last = len-1, half = len/2, i; char tmp; for (i=0; i<half; i++) { tmp = w[i]; w[i] = w[last-i]; w[last-i] = tmp; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 27/43
Multidimenzionální pole Pole je multidimenzionální, když pro přístup k prvku jsou třeba dva nebo více indexů. Multidimenzionální pole je v C implementováno jako pole, jehož elementy jsou pole (která mají o dimenzi méně). Dvoudimenzionální pole může reprezentovat třeba matici: double mat[4][3]; matice má prvky typu double, matice má 4 řádky a 3 sloupce, matice je organizována jako pole 4 prvků, kde každým prvkem je opět pole 3 prvků, každý je hodnotou typu double. Pro přístup k prvku matice musí být použity 2 indexy: sum = 0; for ( i = 0; i < 4; i ++ ) for ( j = 0; j < 3; j ++ ) sum += mat[i][j]; /* součet všech prvků */ M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 28/43
Multidimenzionální pole příklad Vstup programu: dvě matice, obě m x n prvků. Výstup programu: součet matic. Poznámka: velikost matic musí být pevně daná (statická alokace), tudíž velikost matic je omezena na ROWS MAX x COLS MAX prvků, kde ROWS MAX a COLS MAX jsou symbolické konstanty. Program bude umět zpracovávat i menší matice, část vyhrazeného prostoru se nevyužije. Pokud bychom chtěli pracovat s maticemi libovolné velikosti, museli bychom pole alokovat dynamicky. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 29/43
Multidimenzionální pole příklad #include <stdio.h> #define ROWS_MAX 10 #define COLS_MAX 10 int readint (int min, int max ) {... /* čte číslo ze vstupu, testuje rozsah min..max */ void readmatrix ( int mat[][cols_max], int m, int n ) {... void matrixsum (int x[][cols_max], int y[][cols_max], int z[][cols_max], int m, int n ) {... void printmatrix ( int mat[][cols_max], int m, int n) {... int main (void ) {... M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 30/43
Multidimenzionální pole příklad int main (void ) { int x[rows_max][cols_max], y[rows_max][cols_max], z[rows_max][cols_max], m, n; printf ( "Napis pocet radku (max. %d):\n", ROWS_MAX ); m = readint ( 1, ROWS_MAX ); printf ( "Napis pocet sloupcu (max. %d):\n", COLS_MAX ); n = readint ( 1, COLS_MAX ); printf ( "Prvni matice:\n" ); readmatrix (x, m, n ); printf ( "Druha matice:\n" ); readmatrix ( y, m, n); matrixsum (x, y, z, m, n); printf ( "Vysledek:\n" ); printmatrix (z, m, n ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 31/43
Multidimenzionální pole příklad void readmatrix ( int mat[][cols_max], int m, int n ) { int r, c; printf ( "Napis %d x %d celych cisel\n", m, n ); for ( r = 0; r < m; r ++ ) for ( c = 0; c < n; c ++ ) scanf ( "%d", &mat[r][c] ); void printmatrix ( int mat[][cols_max], int m, int n ) { int r, c; for ( r = 0; r < m; r ++ ) { for ( c = 0; c < n; c ++ ) printf ( "%5d ", mat[r][c] ); printf ( "\n" ); M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 32/43
Multidimenzionální pole příklad void matrixsum (int x[][cols_max], int y[][cols_max], int z[][cols_max], int m, int n) { int r, c; for ( r = 0; r < m; r ++ ) for (c = 0; c < n; c ++ ) z[r][c] = x[r][c] + y[r][c]; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 33/43
Minimální a maximální prvek pole Najít nejmenší a největší prvek při použití co nejmenšího možného počtu porovnání. #include <stdio.h> void dump ( int arr[], int lng ) { int i; for ( i = 0; i < lng; i++ ) printf ( "[%2d]=%5d\n", i, arr[i] ); int main ( void ) { int min, max; int a[] = {1, 4, 5, 78, -100, 45, 28, 34, 5; /* počet prvků pole a: sizeof ( a ) / sizeof ( a[0] ) */ dump ( a, sizeof ( a ) / sizeof ( a[0] ) ); minmax ( a, sizeof ( a )/ sizeof ( a[0] ), &min, &max ); printf ( "Max: %d,\nmin %d\n", max, min ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 34/43
Minimální a maximální prvek pole void minmax1 ( int arr[], int len, int *min, int *max ) { int i; *min = *max = arr[0]; for (i = 1; i < len; i ++ ) { if ( arr[i] > *max ) *max = arr[i]; if ( arr[i] < *min ) *min = arr[i]; Kolik porovnání je v nejlepším případě? Kolik porovnání je v nejhorším případě? Co když len == 0? M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 35/43
Minimální a maximální prvek pole void minmax2 ( int arr[], int len, int *min, int *max ) { int i; *min = *max = arr[0]; for ( i = 1; i < len; i ++ ) { if ( arr[i] > *max ) *max = arr[i]; else if ( arr[i] < *min ) *min = arr[i]; Kolik porovnání je v nejlepším případě? Kolik porovnání je v nejhorším případě? {1,2,10,20,50,100 {10,3,0,-7,-200 M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 36/43
Minimální a maximální prvek pole void minmax3 ( int arr[], int len, int *min, int *max ) { int i; if ( arr[0] > arr[1] ) { *max = arr[0]; *min = arr[1]; else { *max = arr[1]; *min = arr[0]; for ( i = 2 - len % 2; i < len - 1; i += 2 ) if ( arr[i] > arr[i + 1] ) { if ( arr[i] > *max ) *max = arr[i]; if ( arr[i + 1] < *min ) *min = arr[i + 1]; else { if ( arr[i + 1] > *max ) *max = arr[i + 1]; if ( arr[i] < *min ) *min = arr[i]; Kolik porovnání je v nejlepším případě? Kolik porovnání je v nejhorším případě? Co když je len je liché? A co když len == 1? M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 37/43
Eratosthénovo síto Problém: nalézt prvočísla menší než zadané n. Naivní řešení: zkusit pro každé číslo, zda je či není prvočíslo. Eratosthénes z Kyrény (276-194 př.n.l.): vylepšený algoritmus, který eliminuje složená čísla. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 38/43
Eratosthénovo síto Problém: nalézt prvočísla menší než zadané n. Naivní řešení: zkusit pro každé číslo, zda je či není prvočíslo. Eratosthénes z Kyrény (276-194 př.n.l.): vylepšený algoritmus, který eliminuje složená čísla. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 prime 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 38/43
Eratosthénovo síto Problém: nalézt prvočísla menší než zadané n. Naivní řešení: zkusit pro každé číslo, zda je či není prvočíslo. Eratosthénes z Kyrény (276-194 př.n.l.): vylepšený algoritmus, který eliminuje složená čísla. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 prime 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 38/43
Eratosthénovo síto Problém: nalézt prvočísla menší než zadané n. Naivní řešení: zkusit pro každé číslo, zda je či není prvočíslo. Eratosthénes z Kyrény (276-194 př.n.l.): vylepšený algoritmus, který eliminuje složená čísla. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 prime 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 38/43
Eratosthénovo síto Problém: nalézt prvočísla menší než zadané n. Naivní řešení: zkusit pro každé číslo, zda je či není prvočíslo. Eratosthénes z Kyrény (276-194 př.n.l.): vylepšený algoritmus, který eliminuje složená čísla. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 prime 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 38/43
Eratosthénovo síto Problém: nalézt prvočísla menší než zadané n. Naivní řešení: zkusit pro každé číslo, zda je či není prvočíslo. Eratosthénes z Kyrény (276-194 př.n.l.): vylepšený algoritmus, který eliminuje složená čísla. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 prime 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 38/43
Eratosthénovo síto Problém: nalézt prvočísla menší než zadané n. Naivní řešení: zkusit pro každé číslo, zda je či není prvočíslo. Eratosthénes z Kyrény (276-194 př.n.l.): vylepšený algoritmus, který eliminuje složená čísla. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 prime 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 38/43
Eratosthénovo síto algoritmus 1 Na voskovou destičku napiš čísla 1 až n. 2 Vypal číslo 1 horkou jehlou. 3 Začni od x = 2, toto je prvočíslo. 4 Vypal horkou jehlou všechny násobky x. 5 Ukonči se, pokud již neexistuje větší číslo. 6 Nalezni další větší nevypálené číslo x, toto číslo je prvočíslo. Pokračuj bodem 4. Který první násobek x budeme v bodě 4 vypalovat? M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 39/43
Eratosthénovo síto algoritmus 1 Na voskovou destičku napiš čísla 1 až n. 2 Vypal číslo 1 horkou jehlou. 3 Začni od x = 2, toto je prvočíslo. 4 Vypal horkou jehlou všechny násobky x. 5 Ukonči se, pokud již neexistuje větší číslo. 6 Nalezni další větší nevypálené číslo x, toto číslo je prvočíslo. Pokračuj bodem 4. Který první násobek x budeme v bodě 4 vypalovat? 2x M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 39/43
Eratosthénovo síto algoritmus 1 Na voskovou destičku napiš čísla 1 až n. 2 Vypal číslo 1 horkou jehlou. 3 Začni od x = 2, toto je prvočíslo. 4 Vypal horkou jehlou všechny násobky x. 5 Ukonči se, pokud již neexistuje větší číslo. 6 Nalezni další větší nevypálené číslo x, toto číslo je prvočíslo. Pokračuj bodem 4. Který první násobek x budeme v bodě 4 vypalovat? 2x 3x M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 39/43
Eratosthénovo síto algoritmus 1 Na voskovou destičku napiš čísla 1 až n. 2 Vypal číslo 1 horkou jehlou. 3 Začni od x = 2, toto je prvočíslo. 4 Vypal horkou jehlou všechny násobky x. 5 Ukonči se, pokud již neexistuje větší číslo. 6 Nalezni další větší nevypálené číslo x, toto číslo je prvočíslo. Pokračuj bodem 4. Který první násobek x budeme v bodě 4 vypalovat? 2x 3x x 2 Pro jaké x budeme naposledy vypalovat nějaké číslo? M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 39/43
Eratosthénovo síto algoritmus 1 Na voskovou destičku napiš čísla 1 až n. 2 Vypal číslo 1 horkou jehlou. 3 Začni od x = 2, toto je prvočíslo. 4 Vypal horkou jehlou všechny násobky x. 5 Ukonči se, pokud již neexistuje větší číslo. 6 Nalezni další větší nevypálené číslo x, toto číslo je prvočíslo. Pokračuj bodem 4. Který první násobek x budeme v bodě 4 vypalovat? 2x 3x x 2 Pro jaké x budeme naposledy vypalovat nějaké číslo? n 2 M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 39/43
Eratosthénovo síto algoritmus 1 Na voskovou destičku napiš čísla 1 až n. 2 Vypal číslo 1 horkou jehlou. 3 Začni od x = 2, toto je prvočíslo. 4 Vypal horkou jehlou všechny násobky x. 5 Ukonči se, pokud již neexistuje větší číslo. 6 Nalezni další větší nevypálené číslo x, toto číslo je prvočíslo. Pokračuj bodem 4. Který první násobek x budeme v bodě 4 vypalovat? 2x 3x x 2 Pro jaké x budeme naposledy vypalovat nějaké číslo? n 2 n 3 M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 39/43
Eratosthénovo síto algoritmus 1 Na voskovou destičku napiš čísla 1 až n. 2 Vypal číslo 1 horkou jehlou. 3 Začni od x = 2, toto je prvočíslo. 4 Vypal horkou jehlou všechny násobky x. 5 Ukonči se, pokud již neexistuje větší číslo. 6 Nalezni další větší nevypálené číslo x, toto číslo je prvočíslo. Pokračuj bodem 4. Který první násobek x budeme v bodě 4 vypalovat? 2x 3x x 2 Pro jaké x budeme naposledy vypalovat nějaké číslo? n n 2 n 3 Časová složitost: T (n) O(n log(log(n))), kde n je horní mez. Časová složitost: T (b) O(2 b log(b)), kde b je počet bitů na vstupu (b = log 2 (n) ). M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 39/43
Eratosthénovo síto implementace #include <stdio.h> #include <stdlib.h> #include <math.h> #define MAX 1000000 void sieve ( char set[], int max ); void print ( char set[], int max ); int count ( char set[], int max ); int main ( void ) { char set [MAX]; sieve ( set, MAX ); printf( "Prvocisla od 2 do %d:\n", MAX ); print ( set, MAX ); printf( "Celkem %d prvocisel\n", count ( set, MAX ) ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 40/43
Eratosthénovo síto implementace void sieve ( char set[], int max ) { int i, p = 2, pmax = (int) sqrt ( max ); /* všechna čísla jsou kandidáti */ for (i = 0; i < max; i ++ ) set[i] = 1; set[0] = set[1] = 0; /* 0 a 1 nejsou prvočísla */ do { for ( i = p*p; i < max; i += p ) set[i] = 0; /* škrtání násobků */ /* Hledáme další prvočíslo */ do { p++; while (!set[p] ); while ( p <= pmax ); M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 41/43
Eratosthénovo síto implementace void sieve ( char set[], int max ) { int i, p = 2, pmax = (int) sqrt ( max ); /* všechna čísla jsou kandidáti */ for (i = 0; i < max; i ++ ) set[i] = 1; set[0] = set[1] = 0; /* 0 a 1 nejsou prvočísla */ do { for ( i = p*p; i < max; i += p ) set[i] = 0; /* škrtání násobků */ /* Hledáme další prvočíslo */ do { p++; while (!set[p] ); while ( p <= pmax ); Je hledání dalšího prvočísla vždy bezpečné? M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 41/43
Eratosthénovo síto implementace int count ( char set[], int max) { int i, res = 0; for (i = 2; i < max; i++ ) res += set[i]!= 0; return res; void print ( char set[], int max) { int i, res = 0; for (i = 2; i < max; i++ ) if ( set[i] ) printf ( " %d", i ); printf ( "\n" ); M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 42/43
Otázky a odpovědi Otázky... M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Pole, BI-PA1 43/43