Obsah

Cykly

smyčka

cyklus while Cykly slouží k opakovanému provádění příkazů. V Javě máme tři cykly: while, do a for. Cyklus while začíná klíčovým slovem while, za kterým následuje v závorkách podmínka a dále tělo cyklu. Tělem cyklu je buď příkaz nebo blok. Cyklus se provádí takto: vyhodnotí se podmínka a je-li splněna, provede se tělo cyklu. Poté se znovu vyhodnotí podmínka a je-li splněna, opět se provede tělo cyklu, atd. Pokud podmínka není splněna, pokračuje se příkazy za cyklem.

  Scanner sc = new Scanner( System.in );
  int x = sc.nextInt();
  while( x > 0 ) {  // dokud je x větší než nula, prováděj...
     System.out.println( x );
     x /= 2;
  } 
Jestliže na začátku není podmínka splněna, tělo cyklu se neprovede ani jednou. Cyklus while je tedy cyklus s počtem opakování 0 nebo více.

cyklus do Cyklus do začíná klíčovým slovem do, za kterým je tělo cyklu, klíčové slovo while a podmínka. Provádí se takto: nejprve se provede tělo cyklu, pak se vyhodnotí podmínka a je-li splněna, znovu se provede tělo cyklu, vyhodnotí se podmínka, atd. Není-li podmínka splněna, pokračuje se za cyklem.

  int x = sc.nextInt();
  do {
     System.out.println( x );
     x /= 2;
  } while( x > 0 ); 
Tělo cyklu se provede vždy alespoň jednou. Počet opakování je tedy 1 nebo více.

cyklus for Cyklus for má tento tvar: for( inicializace; podmínka; aktualizace ) tělo cyklu. Provádí se takto: nejprve se provede inicializace, pak se vyhodnotí podmínka a je-li splněna, provede se tělo cyklu. Poté se provede aktualizace, znovu se vyhodnotí podmínka a je-li splněna, opět se provede tělo cyklu, atd. Inicializace se tedy provede pouze jednou na začátku. Pokud na začátku není podmínka splněna, tělo cyklu se neprovede ani jednou.

  int i;
  for( i = 1; i <= 10; i++ ) {
     System.out.println( i );
  } 
Inicializace může obsahovat deklaraci proměnné. Tato deklarace je platná pouze v daném cyklu (tj. v hlavičce a těle cyklu). Říkáme, že proměnná je v tomto cyklu lokální.
  for( int i = 1; i <= 10; i++ ) {
     System.out.println( i * i );
  } 

Nekonečný cyklus: viz cyklus nekonečný

Libovolná z částí inicializace, podmínka a aktualizace může chybět. Chybí-li podmínka, jde o nekonečný cyklus (podmínka je stále splněna). Pokud není uvedena inicializace nebo aktualizace, neprovede se v daný okamžik žádný příkaz.

  int n = sc.nextInt();
  for( ; n > 0; n-- ) {
     System.out.println( n );
  } 
U všech třech cyklů je tělem cyklu příkaz nebo blok. Pro lepší čitelnost se často zapisuje blok i v případě, že tělo cyklu obsahuje pouze jeden příkaz. V těle cyklu můžeme používat příkazy break a continue. Příkaz break okamžitě ukončí provádění cyklu. Pokračovat se bude příkazy za cyklem.
  int s = 100;
  while( s > 0 ) {
     int n = sc.nextInt();
     if( n == 0 ) {
        break;
     }
     s -= n;
     System.out.println( s );
  }
  // tady se bude pokračovat po provedení break 
Příkaz continue ukončí provádění těla cyklu a přejde na vyhodnocení podmínky cyklu.
  int s = 0;
  do {
     int n = sc.nextInt();
     if( n == 0 ) {
        continue;
     }
     s += n;
     System.out.println( s );
     // sem přejde continue
  } while( s < 100 ); 
Věnujme se teď načtení posloupnosti čísel. Neznáme-li předem počet prvků, máme dvě možnosti: buď tento počet zadáme jako první hodnotu, nebo stanovíme, jakou hodnotou bude vstupní posloupnost končit. Oba přístupy si ukážeme na úloze nalezení součtu vstupní posloupnosti. Nejprve uvedeme řešení se zadaným počtem prvků:
  int n = sc.nextInt(), s = 0;
  for( ; n > 0; n-- ) {
     s += sc.nextInt();
  }
  System.out.println( s ); 
Dále si ukážeme řešení s koncovou hodnotou. Pro ukončení vstupní posloupnosti použijeme nulu. Podmínku cyklu while lze napsat tak, že načteme hodnotu, přiřadíme ji do proměnné pomocí operátoru = a návratovou hodnotu operátoru porovnáme s nulou.
  int x, s = 0;
  while( ( x = sc.nextInt() ) != 0 ) {
     s += x;
  }
  System.out.println( s ); 
Cykly lze libovolně vnořovat. Např. tisk obdélníka o velikosti a x b ze znaků '@' zajistíme pomocí dvou vnořených cyklů for:
  int a = sc.nextInt(), b = sc.nextInt();
  for( ; a > 0; a-- ) {
     for( int i = 0; i < b; i++ ) {
        System.out.print( '@' );
     }
     System.out.println();
  } 
Vnitřní cyklus vytiskne b znaků '@' na jednu řádku. Po jeho skončení přejdeme na nový řádek metodou println(). Vnější cyklus zajistí, že se vytiskne a řádek.

V části inicializace můžeme deklarovat i více proměnných. Všechny však musí být stejného typu. Chceme-li v části aktualizace zapsat více výrazů, oddělujeme je čárkou.

  int n = sc.nextInt();
  System.out.print( n + 1 );
  for( int i = 1, j = n; i < j; i++, j-- ) {
     System.out.printf( "=%d+%d", i, j );
  }
  System.out.println(); 
Zde v cyklu for deklarujeme dvě proměnné. Proměnná i bude nabývat hodnot 1, 2, ..., proměnná j hodnot n, n−1, ... Zvyšování hodnoty i zajišťuje příkaz i++, snižování hodnoty j příkaz j−− v části aktualizace. Cyklus se bude provádět tak dlouho, dokud je i menší než j. Pro hodnotu 6 se tedy vytiskne: 7=1+6=2+5=3+4.

Úloha 1

Doplňte podmínku u cyklu while tak, aby se vypsaly všechny nezáporné mocniny 3 menší než zadaná hodnota.

Úloha 2

Doplňte podmínku cyklu do tak, aby pro n > 1 končil výpis hodnotou 1.

Úloha 3

Pro celé kladné číslo n je faktoriál n (značíme n!) definován jako součin hodnot od 1 do n, tj. n! = n * (n−1) * … * 1.
Doplňte chybějící části tak, aby po skončeni cyklu byla v proměnné f hodnota n!

Úloha 4

Doplňte chybějící části.

Úloha 5

Určete, co se vytiskne, pokud na vstupu zadáme hodnotu 10.

Úloha 6

Určete, co se vytiskne, pokud na vstupu zadáme hodnotu 20.

Úloha 7

Napište ve správném pořadí.

Úloha 8

Doplňte věty.

Otázky a odpovědi

Student: Mistře, mám pocit, že každý cyklus while se dá přepsat pomocí cyklu for. Např.
  while( x > 0 ) {
     System.out.println( x );
     x /= 2;
  } 
můžeme vyjádřit také takto:
  for( ; x > 0; x /= 2 ) {
     System.out.println( x );
  } 
Není tedy cyklus while nadbytečný?
Java guru: Ano, každý cyklus while lze nahradit cyklem for a i každý cyklus for lze přepsat pomocí cyklu while. Jediný rozdíl mezi těmito cykly je v tom, že cyklus for umožňuje deklarovat lokální proměnné (tj. proměnné, které jsou platné pouze v daném cyklu). Např.
  for( int i = 0; i < 10; i++ ) {
     System.out.println( i );
  } // touto závorkou končí platnost deklarace i
  // tady už i nemůžeme použít 
Takže cyklus while se opravdu může zdát nadbytečný. To, že můžeš jednu věc vyjádřit více způsoby však není nic neobvyklého. Totéž platí např. pro zvětšení hodnoty proměnné x o jedničku:
  x = x + 1;
  x += 1;
  x++;  // zkušený programátor zvolí tuto možnost 
Většinou dáváme přednost čitelnějším a úspornějším zápisům.
Student: Jaký cyklus mám tedy používat, mistře?
Java guru: Používej všechny tři cykly. Je-li potřeba provést tělo cyklu vždy alespoň jednou, použij cyklus do. Jinak si můžeš vybrat mezi cyklem while a for. Volba je často věc osobního stylu a je možné, že tvůj kolega si ve stejné situaci zvolí něco jiného. Jsou však také situace, kdy je jeden cyklus mírně lepší volbou. Např. pokud víme předem, kolikrát se bude cyklus opakovat, je lepší cyklus for, protože kód je pak čitelnější. Cyklus while se hodí pro zápis cyklu „dokud platí podmínka, prováděj příkaz.“

Cyklus nekonečný: viz nekonečný cyklus

Student: Mistře, co je to nekonečný cyklus?
Java guru: Nekonečný cyklus je cyklus, jehož podmínka je vždy splněna.
  while( true ) {
     //...
  } 
U cyklu for stačí vynechat podmínku.
  for( ; ; ) {
     //...
  } 
Ukončení takového cyklu provádíme příkazem break v těle cyklu.