1 Iteration Iteration innebär en upprepning, repetition av satser. Vi har nu sett hur en villkorssats kan välja att utföra ett satsblock beroende på om ett villkor är uppfyllt, selektion. För selektion formulerades ett villkor om ett satsblock skulle behandlas eller inte. För iterationen gäller att dess satsblock repeteras till dess att villkoret inte är längre är sant. Man till exempel beskriva läsandet av en bok schematiskt med iteration 1: Öppna boken 2: Om det finns sidor kvar att läsa: 2.1: Läs en sida Kontrollera villkor 2.2: Bläddra till nästa sida 3: Stäng bok 4: Lämna tillbaks boken till biblioteket Essensen i en iteration kan man se i exemplet består av tre beståndsdelar. 1. Iterationsvillkor ( 2: Finns det sidor kvar att läsa ) 2. Sats som påverkar iterationsvillkoret, tar iterationen närmare slutförandet. ( 2.2: Bläddra till nästa sida ) 3. Den sats som ska itereras. ( 2.1: Läs en sida ) Man skulle även kunna ta med den första satsen 1: Öppna boken, som möjliggör iterationen. Denna typ av sats som förbereder iterationen kallas för initieringssats. När man diskuterar iterationssatser i programkod kallar man dom ofta för "loopar". De iterationssatser som finns i kan delas in i två kategorier, nämligen Uppräkningar (eller nedräkningar) Villkorsloopar Exemplet ovan är ett typiskt exempel på en uppräknande loop. Man kan betrakta det som att man tar steg från sidan 1 till sidan 2 till sidan 3 osv. till den sista sidan i boken. Skillnaden mellan dessa två typer av loopar är i huvudsak satsen som påverkar iterationsvillkoret. I exemplet är det satsen att bläddra till nästa sida, dvs. ta ytterligare ett steg i boken, som påverkar iterationsvillkoret. 1.1 for-satsen En for-sats är en av de vanligaste satserna i programkod och är mycket viktigt att behärska. Syftet med for-satsen är att skapa uppräkningar. Formen för en for-sats är for ( initieringssats; iterationsvillkor; inkrementsatslista ) sats / satsblock Man kan i formen skönja flera likheter med if satsen. Den stora skillnaden ligger i initieringssatsen och inkrementlistan, och naturligtvis det faktum att for-satsen är iterativ. Kom ihåg att en lista är noll, ett eller flera element separerade med kommatecken. Vi kan nu visa på bokexemplet först schematiskt med en forsats:
for(öppna bok; om det finns sidor kvar att läsa; bläddra till nästa sida ) Läs en sida; Stäng bok; Lämna tillbaka boken till biblioteket; Detta är principen bakom varje forsats. Denna typ av kod kallas för pseudokod och används med fördel om man vill diskutera programkodslösningar. En java kompilator förstår naturligtvis inte pseudokod, använd penna och papper istället. Bokexemplet som ett komplett program Det går att skapa ett enkelt komplett program av bokexemplet, om man på förhand bestämmer antalet sidor i boken. Vi fastställer härmed att antalet sidor är 12. import java.util.*; class BookRead public static void main(string [] arg) Scanner tgb = new Scanner(System.in); int antalsidor = 12; System.out.println("Öppnar boken"); for( int nuvarande = 0; nuvarande < antalsidor; nuvarande++) System.out.println("Läser en sida i boken"); System.out.println("Stänger boken"); System.out.println("Lämnar tillbaks boken till biblioteket"); Detta bokexempel läser naturligtvis inte igenom någon riktig bok, men visar ändå ganska tydligt hur iterationen fungerar. Programmet följer exakt samma ordning som det schematiska exemplet ovan utan forsats. Då programmet körs utförs följande satser i tur och ordning Rad 6: Heltalsvariabeln antalsidor initieras till 12 Rad 7: Texten "Öppnar boken" skrivs till skärmen Rad 8: Heltalsvariabeln nuvarande initieras till noll. Detta är alltså en initieringslista med ett element. Variabeln nuvarande kallas allmänt för loopvariabel. Rad 8: Iterationsvillkoret kontrolleras. Om villkoret nuvarande < antalsidor, ( här: 0 < 12 : sant ) är sant ( ja ), utförs satsblocket tillhörande for-satsen. Rad 10: Texten "Läser en sida i boken" skrivs på skärmen Rad 8: Inkrementsatsen, nuvarande++, utförs. Variabeln nuvarande får alltså värdet 1 Rad 8: Iterationsvillkoret kontrolleras. Nu kan villkoret läsas som 1 < 12 : sant, och satsblocket tillhörande for-satsen utförs. Rad 10: Texten "Läser en sida i boken" skrivs på skärmen Rad 8: Inkrementsatsen, nuvarande++, utförs. Variabeln nuvarande får värdet 2 Iterationen fortsätter på detta vis med villkor, satsblock, inkrement, villkor, satsblock, inkrement osv. tills dess att villkoret inte längre är uppfyllt. Detta inträffar då variabeln nuvarande fått värdet 12. Satsutvärderingen blir då vid den sista iterationen Rad 8: Inkrementsats, nuvarande++ ger variabeln värdet 12. Rad 8: Iterationsvillkoret gör jämförelsen, nuvarande < antalsidor (nu 12<12: falskt).
Eftersom villkoret inte längre är sant avbryts iterationen och fortsätter med Rad 12: Utskrift av "Stänger boken" Rad 13: Utskrift av "Lämna tillbaks " Satserna i programmet utförs i exakt samma ordning som i det första schematiska bokexemplet. Övning: Övertyga dig själv om att det första schematiska exemplet fungerar på samma sätt som forsatsen i exemplet ovan Iterationsvariabeln Betrakta programavsnittet for( int i=0; i< 10;i++) System.out.print("i = "+ i+ ", "); utskriftssatsen i satsblocket skriver ut texten "i = ", därefter värdet på variabeln i, därefter ett kommatecken. Eftersom satsen står i en forsats kommer iterationsvillkoret och inkrementsatsen att avgöra hur många gånger System.out.print... utförs. Om man kör ett komplett program med ovanstående forsats kommer man att få följande utskrift, observera särskilt start och slutvärdet på i. i = 0, i = 1, i = 2, i = 3, i = 4, i = 5, i = 6, i = 7, i = 8, i = 9, Det som är särskilt intressant i denna forsats är hur iterationsvariabeln kan användas inuti for-satsen. Detta är en mycket användbar egenskap, i synnerhet vid olika typer av beräkningar. Om man använder println istället för print kommer i att skrivas ut som en tabell/i en kolumn. Denna typ av utskrift tillsammans med formatering av tal beskrivet i kursboken ger ett bra sätt att skriva ut tabeller med beräkningar. Exempel, summaberäkning med for-sats Antag att vi vill beräkna summan av serien 1+2+3+4+5+6+7+8+9+ +100 Utformning av lösning: De olika termerna i summan kan räknas fram med hjälp av for-satsen. För att beräkna summan krävs ytterligare en variabel av heltalstyp, (int) + (int) ger resultat av typen int. Startvärdet i for-satsen skall vara 1. Iterationsvillkoret skall vara utformat så att den sista iteration som utförs, skall vara för värdet 100. int totalsumma = 0; // viktigt att nollställa for( int i = 1; i< 101; i++) totalsumma += i; // öka total_summa med värdet på i System.out.println("summan är:"+ total_summa); Rad 1: Om man glömmer bort att nollställa totalsumma kan man få helt oväntade resultat. Rad 2: Initieringssatsen låter värdet på i börja med 1 eftersom summeringen skulle börja med termen 1. Att börja på noll ger inte ett felaktigt resultat men är helt onödigt. Rad 2: Iterationsvillkoret ska medge att satsblocket utförs för värdet i = 100 men inte i = 101, villkoret avbryter nu vid jämförelsen 101 < 101. Rad 4: Operatorn += används för att öka på värdet på variabeln totalsumma med värdet av i.
Kom ihåg utvärderingsordningen: initiering, villkor, satsblock, inkrement, villkor, satsblock, inkrement, villkor, satsblock, inkrement, villkor Resultatet blir: summan är:5050 1.2 Övning Skriv ett program som skriver ut treans multiplikationstabell upp till 10. Programutskrift 1*3 3 2*3 6 3*3 9 Tips: Skriv ut varje värde som en utmatning i en for-sats, låt iterationsvariabeln stega från 1 till 10. Tecknen "*3 " på varje rad kan skrivas ut som vanlig text. 1.3 while och do while- satserna Den andra typen av iterationssatser är villkorsloopar. Skillnaden mellan dessa satser och for- satsen är att de används när man inte utför en räknande iteration, i synnerhet då man på förhand inte känner till hur många iterationer som ska utföras. Ett vanligt förekommande sammanhang för dessa iterationer är för felkontroll av inmatningar från användaren. Villkorslooparna kommer två olika varianter, en med preevaluering, while, och en med postevaluering, do while. Preevaluering innebär att ett villkor utvärderas innan ett satsblock utförs medan postevaluering innebär att ett villkor utvärderas efter ett satsblock utförs. While-satsen While-satsen använder preevaluering dvs. först utvärdera villkor därefter utförs tillhörande satsblock. Formen på en while-sats är följande while ( iterationsvillkor ) sats / satsblock Funktionen hos satsen är densamma som hos for-satsen, men den saknar både initieringslista och inkrementsatslista. Exempel, inmatning av en födelsemånad. Programmet ska ta emot en inmatning om vilken månad som användaren är född i och därefter konstatera om användaren föddes tidigt på året eller sent på året. Programmet innehåller en felkontroll av inmatad månad. En programkörning kan se ut som Vilken månad är du född? Ange ett tal mellan 1 och 12. 19 Du har angett ett felaktigt tal, försök igen! -4 Du har angett ett felaktigt tal, försök igen! 2 Du är född tidigt på året. Programlösning
import java.util.*; class FödelseMånad public static void main(string [] args) int födelsemånad; Scanner tgb = Scanner( System.in ); System.out.println("Vilken månad är du född?"); System.out.println("Ange en siffra mellan 1 och 12."); födelsemånad = tgb.nextint(); // felkontroll while(födelsemånad < 1 födelsemånad > 12 ) System.out.println("Du har angett ett felaktigt tal"); System.out.println("försök igen!"); födelsemånad = tgb.nextint(); // slut felkontroll if ( födelsemånad <=6 ) cout <<"Du är född tidigt på året"<<endl; else cout <<"Du är född sent på året"<<endl; Observera att det finns två satser för samma inmatning i programmet, en före iterationen och en inuti iterationen. Inmatningssatsen inuti iterationen kommer bara att utföras om man har matat in ett felaktigt värde vid den första inmatningen. For-satsen som while-sats For-satsen och while-satsen skiljer sig bara på for-satsens initieringslista och dess inkrementlista. Eftersom en lista kan bestå av inget element är det syntaktiskt korrekt att helt utelämna dessa satser. Gör man det får man exakt samma funktion som hos while-satsen. Exemplet ovan hade även kunnat skrivas med for-sats genom att byta ut while-satsen mot for ( ; fodelse_manad < 1 fodelse_manad > 12 ; )... som tidigare Observera att for-satsens semikolon inte får utelämnas. Även om det är möjligt att använda for-satsen betyder det inte att det är lämpligt. Vi använder for-satsen för att uttrycka uppräkningar. Do while-satsen Do while-satsen har ett samma funktion som while-satsen med den skillnaden att den använder sig av postevaluering, villkoret om att fortsätta iterationen utförs efter det tillhörande satsblocket. Det får till följd att satsblocket till en do while-sats alltid kommer att utföras minst en gång. Formen på en do while-sats är do sats / satsblock while ( iterationsvillkor ); Exemplet ovan skrivet med en do while-sats kan bli
class FödelseMånad public static void main(string [] args) int födelsemånad; Scanner tgb = Scanner( System.in ); do System.out.println("Vilken månad är du född? "); System.out.println("Ange en siffra mellan 1 och 12."); födelsemånad = tgb.nextint(); while(födelsemånad < 1 födelsemånad > 12 ); if (födelsemånad <=6 ) System.out.println("Du är född tidigt på året"); else System.out.println("Du är född sent på året"); I denna variant finns det bara en sats som tar emot inmatningen av månaden, så programkoden är något enklare, men användaren får heller inget tydligt felmeddelande att inmatningen som gjordes var felaktig. En programkörning kan se ut som Vilken månad är du född? Ange ett tal mellan 1 och 12. 92 Vilken månad är du född? Ange ett tal mellan 1 och 12. 8 Du är född sent på året. Exempel, nästlade loopar, multiplikationstabellen På samma sätt som en villkorssats kan innehålla vilken annan sats som helst kan iterationssatser även innehålla iterationssatser. Det blir då en sk. nästlad iteration. Ett tydligt exempel på hur det kan fungera är multiplikationstabellen class MultiTable public static void main(string [] args) for( int i = 1; i <= 10;i++) // anger raden i tabellen for( int j = 1; j <= 10;j++) // skriv ett tal i tabellen System.out.print(""+i*j+"\t"); // \t är tab symbolen System.out.println(); /// nästa rad i tabellen Observera indenteringen (indraget) av programkoden i forsatserna. Resultatet blir
1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40 50 60 70 80 90 100 Observera att rad 10: System.out.print( ""+ i*j +"\t"); bara skriver ut ett tal åt gången, och resultatet innehållet en utskrift av hundra tal. Utskriftssatsen måste alltså ha utförts hundra gånger. Detta kommer sig av att den ena for-satsen ligger i den andres satsblock. För varje gång som den första forsatsen (rad 5) repeterar sitt satsblock kommer den inre for-satsen (rad 7) att utföra utskriftssatsen 10 gånger, vilket ger totalt hundra repetitioner av rad 9-10. 1.4 Övning Skriv multiplikationsprogrammet så att det använder while-satser istället. Not: Eftersom det är en uppräkning av heltal är en lösning med forsatser lämpligare men det är en god övning att omformulera for-satser till while-satser och tvärtom.