Instrukcje iteracyjne (pętle) Instrukcja for..to i for..downto Instrukcja while Instrukcja repeat..until echniki programowania I s.4-1
Zastosowanie instrukcji iteracyjnych Instrukcje iteracyjne (inaczej pętle) umożliwiają wielokrotne powtórzenie pewnego fragmentu kodu programu. Zastosowanie pętli zazwyczaj skraca kod programu, a w pewnych wypadkach jest niezbędne do jego stworzenia (powtórzenie fragmentu kodu nieznaną z góry liczbę razy). Przykład: algorytm wyświetlający kwadraty liczb z przedziału [1, 10] SAR SAR y = 1 2 i = 1 wyświetl y y = i 2 y = 2 2 wyświetl y wyświetl y i = i+1 10x SOP i > 10 echniki programowania I s.4-2
Rodzaje instrukcji iteracyjnych Podstawową różnicą pomiędzy instrukcjami iteracyjnymi jest miejsce sprawdzania warunku zakończenia. W pierwszym przypadku jest on sprawdzany na początku, przed wykonaniem powtarzanej instrukcji (pętla może nie wykonać żadnej iteracji) w drugim na końcu, po wykonaniu instrukcji (pętla zawsze wykona jedną iterację). Dodatkowo liczba powtórzeń może być określona w chwili startu, lub nieznana, zależna od pewnego warunku. SAR SAR SOP warunek instrukcja instrukcja warunek SOP Rys.3.1. Instrukcja iteracyjna z warunkiem na początku Rys.3.2. Instrukcja iteracyjna z warunkiem na końcu echniki programowania I s.4-3
Instrukcja iteracyjna for to for to sprawdza warunek zakończenia przed pierwszą iteracją (może nie wykonać się ani razu), ma z góry ustaloną (przed rozpoczęciem pętli) liczbę powtórzeń. W każdym kroku zwiększa wartość zmiennej sterującej. for z := w1 to w2 do instrukcja; Dla zmiennej przyjmującej wartości od w1 do w2 (rosnąco) wykonuj instrukcję. SOP SAR z := w1 z <= w2 z zmienna typu porządkowego w1,w2 wyrażenia typu zgodnego ze zmienną z o wartościach określonych przed początkiem pętli (zazwyczaj stałe) succ(z) funkcja zwracająca bezpośredni następnik aktualnej wartości zmiennej z instrukcja z := succ(z) yp porządkowy typ danych w którym każdy element ma ustalony następnik i poprzednik: typy całkowite, char, boolean Pętla for..to nie wykona żadnej iteracji jeżeli w1 > w2 echniki programowania I s.4-4
Instrukcja iteracyjna for..downto for..downto sprawdza warunek zakończenia przed pierwszą iteracją (może nie wykonać się ani razu), musi mieć z góry ustaloną (przed rozpoczęciem pętli) liczbę powtórzeń. W każdym kroku zmniejsza wartość zmiennej sterującej. for z := w1 downto w2 do instrukcja; Dla zmiennej przyjmującej wartości od w1 do w2 (malejąco) wykonuj instrukcję SOP SAR z := w1 z >= w2 instrukcja z,w1,w2 analogicznie do pętli for..to pred(z) funkcja zwracająca bezpośredni poprzednik aktualnej wartości zmiennej z Pętla for..downto nie wykona żadnej iteracji jeżeli w1 < w2 z := pred(z) echniki programowania I s.4-5
Przykład kwadraty liczb ależy zaprojektować algorytm, który oblicza kwadraty kolejnych liczb naturalnych od 1 do wartości określonej przez użytkownika. SAR n i := 1 i <= n sqrt(i) i := i+1 SOP Analiza Start odczyt wartości n n = 6 (wartość przykładowa) i = 1 Iter.1 1 <= 6, 1 2 = 1, i=1+1 = 2 Iter.2 2 <= 6, 2 2 = 4, i=2+1 = 3 Iter.3 3 <= 6, 3 2 = 9, i=3+1 = 4 Iter.4 4 <= 6, 4 2 = 16, i=4+1 = 5 Iter.5 5 <= 6, 5 2 = 26, i=5+1 = 6 Iter.6 6 <= 6, 6 2 = 36, i=6+1 = 7 Iter.7 Stop 7 <= 6 <-- false echniki programowania I s.4-6
Zastosowanie Komponent ListBox Przewijana lista elementów (dowolna długość) z możliwością modyfikacji zawartości w czasie działania aplikacji Wybrane własności (properties) ExtendedSelection włącza rozszerzoną selekcję w trybie MultiSelect Items ciąg łańcuchów znakowych, zawartość listy MultiSelect wielokrotny wybór, włącza możliwość zaznaczenia kilku elementów Sorted sortowanie, włącza automatyczne sortowanie zawartości listy Wybrane zdarzenia (events) OnClick kliknięcie; występuje przy zmianie elementu wybranego Dodawanie nowych elementów w czasie działania programu nazawa_listy.items.add(element); nazwa_listy.additem(element, nil); gdzie element to łańcuch znakowy, nowa pozycja listy. echniki programowania I s.4-7
Kwadraty liczb program procedure Form1.Button1Click(Sender: Object); var n, i: integer; begin n := StroInt(Edit1.ext); ListBox1.Clear; for i:=1 to n do end; ListBox1.Items.Add(IntoStr(sqr(i))); Uwaga 1: operacje nadawania wartości początkowej i powiększania zmiennej z algorytmu na str. 6 są wykonywane automatycznie przez pętlę for. Uwaga 2: instrukcja ListBox1.Clear czyści listę (usuwa istniejące elementy) i zapobiega jej rozbudowywaniu przy kolejnych uruchomieniach programu. Uwaga 3: Dodawanie kolejnych elementów listy można również wykonać instrukcją: ListBox1.AddItem(IntoStr(sqr(i)),nil); Pełny kod programu dostępny na stronie przedmiotu jako "Przykład08a" echniki programowania I s.4-8
Przykład znaki Program tworzy ciąg znaków w odwrotnej kolejności alfabetycznej z przedziału określonego przez użytkownika. SAR a, b i := a i >= b i i := pred(i) SOP procedure Form1.Button1Click( ); var a, b, i: Char; begin a := Edit1.ext[1]; b := Edit2.ext[1]; Label3.Caption := 'Wynik: '; for i:=a downto b do Label3.Caption := Label3.Caption + i; end; Pełny kod programu dostępny na stronie przedmiotu jako "Przykład09" echniki programowania I s.4-9
Przykład silnia Program wyznacza wartość silni korzystając z definicji: 0!=1, n!=1*2*3* *n SAR n s := 1 i := 2 i <= n s := s*i i := succ(i) s SOP Analiza Start odczyt wartości n (n=5) s = 1 Iter.1 i=2, s=1*2=2 Iter.2 i=3, s=2*3=6 Iter.3 i=4, s=6*4=24 Iter.4 i=5, s=24*5=120 wyświetlenie zmiennej s (120) Stop procedure Form1.Button1Click( ); var n, s, i: Integer; begin n := StroInt(Edit1.ext); s := 1; for i:=2 to n do s:=s*i; Edit2.ext := IntoStr(s); end; Pełny kod programu dostępny na stronie przedmiotu jako "Przykład10" echniki programowania I s.4-10
Instrukcja złożona Pętle for..to i for..downto powtarzają tylko jedną instrukcję. W celu wykonania w pętli kilku poleceń należy zastosować instrukcję złożoną (begin..end). Przykład tabliczka mnożenia procedure Form1.Button1Click(Sender: Object); var n, w, i: integer; s: string; begin n := StroInt(Edit1.ext); for i:=1 to 10 do begin w := n*i; s := IntoStr(i)+'*'+ IntoStr(n)+'='+ IntoStr(w); ListBox1.Items.Add(s); end; end; for i:=1 to 10 do w := n*i; s := IntoStr(i)+'*'+ IntoStr(n)+'='+ IntoStr(w); ListBox1.Items.Add(s); Pojedynczy wiersz "11*n=..."!!! Pełny kod programu dostępny na stronie przedmiotu jako "Przykład11" echniki programowania I s.4-11
Instrukcja iteracyjna while while sprawdza warunek zakończenia przed pierwszą iteracją (może nie wykonać się ani razu), nie ma z góry ustalonej liczby powtórzeń, zakończenie pętli zależy od wartości warunku. while warunek do instrukcja; SOP SAR warunek instrukcja warunek warunek logiczny zbudowany przy pomocy operatorów relacyjnych i logicznych (wykład 3., str.8.) Pętla while nie wykona żadnej iteracji jeżeli warunek ma na początku wartość false Dopóki warunek jest prawdziwy wykonuj instrukcję. Uwaga: Pętla while powtarza tylko jedną instrukcję. W celu wykonania w pętli kilku poleceń należy zastosować instrukcję złożoną. echniki programowania I s.4-12
Przykład kwadraty liczb Zmodyfikowana wersja przykładu 7a (algorytm str.6., kod str.8.) procedure Form1.Button1Click(Sender: Object); var n, i: integer; begin n := StroInt(Edit1.ext); ListBox1.Clear; i := 1; while ( i <= n ) do begin ListBox1.Items.Add(IntoStr(sqr(i))); i := i+1; end; end; Istotne zmiany: 1. Ustawienie wartości zmiennej sterującej przed pętlą 2. Inkrementacja (powiększanie) wartości zmiennej po obliczeniach 3. Konieczna instrukcja złożona Pełny kod programu dostępny na stronie przedmiotu jako "Przykład08b" echniki programowania I s.4-13
pętla Przykład poszukiwanie znaku SAR txt, z Algorytm wyznacza pozycję pierwszego wystąpienia znaku (zmienna "z") w łańcuchu znakowym (zmienna "txt"). Znak i przeszukiwany tekst są dowolne, będą określone na starcie programu. i := 1 i <= dł(txt) and txt[i] <> z Analiza Strat odczyt wartości txt, z txt = 'Delphi jest super' (17zn.) z = 'p' i = 1 i i := i+1 i <= dł(txt) and txt[i] = z SOP brak Iter1. 1<=17 i 'D'<>'p' --> i = 1+1 = 2 Iter2. 2<=17 i 'e'<>'p' --> i = 2+1 = 3 Iter3. 3<=17 i 'l'<>'p' --> i = 3+1 = 4 Iter4. 4<=17 i 'p'<>'p' <-- false i<=17 i 'p'='p' wyświetlenie zmiennej i (4) Stop instrukcja warunkowa Uwaga: dł(txt) określa długość łańcucha znakowego txt txt[i] odwołanie do i-tego znaku łańcucha txt echniki programowania I s.4-14
procedure Form1.Button1Click(Sender: Object); var txt: string; z : char; i : integer; begin txt := Edit1.ext; z := Edit2.ext[1]; i := 1; while ( i <= length(txt) ) and ( txt[i] <> z ) do i := i+1; Poszukiwanie znaku program if ( i <= length(txt) ) and ( txt[i] = z ) then Label3.Caption := 'Znak "'+z+'" na pozycji '+IntoStr(i) else Label3.Caption := 'Znak "'+z+'" nie występuje w tekście'; end; Uwaga: length() to standardowa funkcja języka Pascal, która określa długość łańcucha znakowego Konstrukcja txt[i] pozwala odwołać się do i-tego znaku łańcucha txt (wykład 3. str.14.) Pełny kod programu dostępny na stronie przedmiotu jako "Przykład12" echniki programowania I s.4-15
Instrukcja iteracyjna repeat..until repeat sprawdza warunek zakończenia po wykonaniu iteracji (na pewno wykona się jeden raz), nie ma z góry ustalonej liczby powtórzeń, zakończenie pętli zależy od wartości warunku. SAR instrukcja warunek SOP repeat instrukcja1;... instrukcja; until warunek; warunek warunek logiczny zbudowany przy pomocy operatorów relacyjnych i logicznych (wykład 1, f.13) Powtarzaj instrukcję chyba że warunek jest prawdziwy. Uwaga: Pętla repeat może powtarzać wiele instrukcji bez użycia instrukcji złożonej (w tym przypadku taką rolę pełnią słowa repeat i until). echniki programowania I s.4-16
Zmodyfikowana wersja przykładu 7a (algorytm str.6., kod str.8.) procedure Form1.Button1Click(Sender: Object); var n, i: integer; begin n := StroInt(Edit1.ext); ListBox1.Clear; i := 1; if ( i <= n ) then repeat ListBox1.Items.Add(IntoStr(sqr(i))); i := i+1; until ( i > n ); end; Przykład kwadraty liczb Istotne zmiany: 1. Ustawienie wartości zmiennej sterującej przed pętlą 2. Inkrementacja (powiększanie) wartości zmiennej po obliczeniach 3. Konieczna instrukcja warunkowa (pętla sprawdza warunek na końcu) 4. Instrukcja złożona nie jest potrzebna Pełny kod programu dostępny na stronie przedmiotu jako "Przykład08c" echniki programowania I s.4-17
Przykład pierwiastek sześcienny SAR x, e p1 := x p2 := p1 p1 := 1/3*(2p1+x/p1 2 ) p1-p2 <= e p1 SOP Algorytm oparty na metodzie ewtona-raphsona, wyznacza przybliżoną wartość pierwiastka sześciennego dowolnej liczby rzeczywistej (zmienna "x"). Jako pierwsze przybliżenie przyjmuje się dowolną wartość, kolejne wyznacza się na podstawie wzoru: p 1 3 k 1 2 pk 2 pk gdzie: p k to kolejne przybliżenie wartości pierwiastka. Obliczenia należy powtarzać do chwili osiągnięcia żądanej dokładności (zmienna "e"). Algorytm sprowadza się do wyznaczania kolejnych wyrazów ciągu liczbowego, do chwili gdy wartość bezwzględna różnicy pomiędzy wartością wyliczoną w kroku bieżącym (zmienna "p1") i poprzednim (zmienna "p2") będzie mniejsza lub równa założonej dokładności. x echniki programowania I s.4-18
Pierwiastek sześcienny program procedure Form1.Button1Click(Sender: Object); var x, e, p1, p2: Real; begin x := StroFloat(Edit1.ext); e := StroFloat(Edit2.ext); p1 := x; repeat p2 := p1; p1 := 1/3 * (2*p1 + x/sqr(p1)); until ( abs(p1-p2) <= e ); Label3.Caption := 'Wynik: '+FormatFloat('0.###############',p1); end; W typowych przypadkach algorytm jest bardzo szybko zbieżny (zazwyczaj w każdym kroku podwaja się liczba dokładnych cyfr przybliżenia), stąd na ogół uzyskuje się wartości znacznie dokładniejsze od przyjętego założenia. p. dla liczby 50 algorytm wyznacza pierwiastek jako: 3,6840315013 (przyjęta dokładność 0,001) wartość rzeczywista wynosi: 3,6840314986 Pełny kod programu dostępny na stronie przedmiotu jako "Przykład13a" echniki programowania I s.4-19
Zagnieżdżanie instrukcji iteracyjnych Zagnieżdżanie oznacza umieszczenie jednej instrukcji sterującej wewnątrz innej. W przypadku zagnieżdżenia instrukcji iteracyjnych w każdej iteracji pętli zewnętrznej wykonywane są wszystkie iteracje pętli wewnętrznej. SAR i := 1 i <= n j := 1 j <= m i*j j := j+1 SOP i := i+1 Analiza (dla n=2 i m=3) i = 1 Iter. z. 1. 1<=2 j = 1 Iter. w. 1. 1<=3, 1*1=1, j=1+1=2 Iter. w. 2. 2<=3, 1*2=2, j=2+1=3 Iter. w. 3. 3<=3, 1*3=3, j=3+1=4 Iter. w. 4. 4<=3, <-- false i = 1+1 = 2 Iter. z. 2. 2<=2 j = 1 Iter. w. 1. 1<=3, 2*1=2, j=1+1=2 Iter. w. 2. 2<=3, 2*2=4, j=2+1=3 Iter. w. 3. 3<=3, 2*3=6, j=3+1=4 Iter. w. 4. 4<=3, <-- false i = 2+1 = 2 Iter. z. 1. 3<=2 <-- false SOP echniki programowania I s.4-20
Przykład pierwiastek n-tego stopnia SAR x, n, e p1 := x p2 := p1 s := p1 i := 2 Algorytm jest uogólnieniem rozwiązania przedstawionego na str.18. Sposób postępowania jest analogiczny, kolejne przybliżenia wyznacza się na podstawie wzoru: 1 x pk 1 n 1 pk n1 n pk gdzie: n to stopień pierwiastka. Uwaga: w tej wersji algorytmu w każdym kroku należy obliczyć (n-1)-szą potęgę, co oznacza konieczność wykonania n-2 mnożeń (wewnętrzna pętla). i <= n-1 s := s*p1 p1 := 1/3*((n-1)p1+x/s) p1 i := i+1 p1-p2 <=e SOP echniki programowania I s.4-21
Pierwiastek n-tego stopnia program procedure Form1.Button1Click(Sender: Object); var x, e, p1, p2, s: real; n, i : integer; begin x := StroFloat(Edit1.ext); n := StroInt(Edit2.ext); e := StroFloat(Edit3.ext); p1 := x; repeat p2 := p1; s := p1; for i:=2 to n-1 do s:=s*p1; pętla wewnętrzna (n-1)-sza potęga pętla zewnętrzna właściwy algorytm p1 := 1/n * ((n-1)*p1 + x/s); until ( abs(p1-p2) <= e ); Label3.Caption := 'Wynik: '+FormatFloat('0.###############',p1); end; Uwaga: Wszystkie wnioski sformułowane dla algorytmu obliczającego pierwiastek sześcienny można uogólnić na algorytm wyznaczający pierwiastek n-tego stopnia Pełny kod programu dostępny na stronie przedmiotu jako "Przykład13b" echniki programowania I s.4-22