Algorytmy: lista kroków, pseudokod, schemat blokowy; sortowanie, wyszukiwanie, rekurencja
INF.03 · teoria
autor: redakcja · 02.11.2026
Analiza danych wejściowych i wyniku, trzy sposoby zapisu algorytmu oraz śledzenie jego działania. Wyszukiwanie liniowe i binarne, sortowanie bąbelkowe i rekurencja w Pythonie. Lekcja 10.2 kursu INF.03.
Algorytm to jednoznaczny ciąg czynności prowadzący od dopuszczalnych danych do oczekiwanego wyniku. Na egzaminie trzeba odczytać listę kroków, schemat blokowy albo kod i ustalić rezultat. W zadaniu praktycznym ta sama umiejętność pomaga zaplanować obliczenie, zanim pojawią się szczegóły składni JavaScript lub PHP.
Najpierw dane i warunki
Analiza problemu zaczyna się od wskazania wejścia i wyjścia. Dla wyszukiwania produktu wejściem może być lista identyfikatorów i szukany identyfikator. Wyjściem jest pozycja produktu albo informacja o braku. Trzeba też ustalić, czy lista jest uporządkowana, czy zawiera powtórzenia i od jakiego numeru liczymy pozycje. Bez tego określenie „znajdź produkt” jest za mało precyzyjne.
Założenie opisuje warunek dopuszczalnych danych. Jeżeli algorytm dzieli przez liczbę elementów, musi ustalić zachowanie dla pustej listy. Jeżeli szuka binarnie, wymaga właściwego uporządkowania danych. Przykład jednego poprawnego wyniku nie dowodzi działania dla wszystkich przypadków. Dlatego przygotowuje się także pustą listę, jeden element, szukaną wartość na końcu i wartość nieobecną.
Prześledzenie algorytmu polega na wykonaniu kolejnych kroków z zapisaniem stanu. W prostej tabeli pomocniczej można notować numer kroku, indeks i bieżący wynik. To szczególnie przydatne przy pętli, bo ostatnia wartość licznika po zakończeniu nie musi być ostatnią wartością używaną w jej treści. Odpowiedź wynika z przebiegu, a nie z liczby wierszy kodu.
Lista kroków, pseudokod i schemat
Lista kroków opisuje czynności zwykłym językiem. Dla większej z dwóch liczb wystarczy: wczytaj a i b, porównaj je, wypisz a gdy jest większe, a w przeciwnym przypadku wypisz b. Gdy liczby są równe, wypisanie którejkolwiek daje tę samą wartość. Ta decyzja powinna być jawna, aby odczytujący nie musiał jej dopowiadać.
Pseudokod to zapis podobny do programu, ale niezależny od dokładnej składni konkretnego języka. Musi mieć wyjaśnione operacje i znaczenie warunków. Słowo WYPISZ oznacza przekazanie wyniku, a nie utworzenie zmiennej. Strzałki przypisania można zastąpić słowem „ustaw”, żeby nie pomylić przypisania z matematyczną równością.
1
2
3
4
5
6
WCZYTAJ a, b
JEŻELI a > b
WYPISZ a
W PRZECIWNYM RAZIE
WYPISZ b
KONIEC
Schemat blokowy pokazuje czynności i kierunki przejść. Owal oznacza początek lub koniec, prostokąt operację, równoległobok wejście lub wyjście, a romb decyzję. Wyjścia z decyzji trzeba podpisać, na przykład TAK i NIE. Sama odległość bloków na rysunku nie wskazuje kolejności; pokazują ją linie kierunkowe.
Schemat wyboru większej liczby: po wczytaniu a i b warunek a > b kieruje do wypisania a albo b, a obie drogi prowadzą do końca
Dla a równego 7 i b równego 4 wybierana jest gałąź TAK i wynik 7. Dla 2 oraz 9 gałąź NIE daje 9. Dla 5 oraz 5 również wybierana jest gałąź NIE, ale wynik nadal wynosi 5. Ten trzeci przypadek sprawdza granicę warunku, której dwa pozostałe nie obejmują.
Wyszukiwanie liniowe i binarne
Wyszukiwanie liniowe sprawdza elementy kolejno, aż znajdzie pasujący lub dojdzie do końca. Nie wymaga uporządkowania. Dla listy 8, 3, 6, 3 i szukanej wartości 6 odwiedza indeksy 0, 1 oraz 2. Jeżeli zwracamy pierwsze trafienie, dla wartości 3 wynikiem będzie indeks 1. Indeks jest numerem pozycji, a nie samą znalezioną wartością.
1
2
3
4
5
6
7
8
defznajdz_liniowo(dane,szukana):
forindeksinrange(len(dane)):
ifdane[indeks]==szukana:
returnindeks
return-1
print(znajdz_liniowo([8,3,6,3],6))
Wynik to 2. Funkcja range (ZAKRES) tworzy kolejne indeksy od zera do liczby elementów bez ostatniej granicy, len podaje liczbę elementów, a return (ZWRÓĆ) kończy funkcję. Wynik -1 jest umowną informacją o braku. Nie należy potem bez sprawdzenia używać go jako indeksu w Pythonie, bo oznacza tam ostatni element listy.
Wyszukiwanie binarne wymaga uporządkowanej listy. Porównuje wartość środkową i odrzuca połowę zakresu, w której wynik nie może się znajdować. Dla rosnącej listy 2, 4, 6, 8, 10, 12, 14 i wartości 12 najpierw porównuje 8. Szukana jest większa, więc pozostają 10, 12, 14; kolejne porównanie 12 daje trafienie.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
defznajdz_binarnie(dane,szukana):
lewy,prawy=0,len(dane)-1
whilelewy<=prawy:
srodek=(lewy+prawy)//2
ifdane[srodek]==szukana:
returnsrodek
ifdane[srodek]<szukana:
lewy=srodek+1
else:
prawy=srodek-1
return-1
print(znajdz_binarnie([2,4,6,8,10,12,14],12))
Wynik to 5. Operator podwójnego ukośnika wykonuje dzielenie całkowite w dół. Granice przesuwają się poza sprawdzony środek, dlatego zakres maleje. Pozostawienie tej samej granicy może prowadzić do nieskończonej pętli. Na nieuporządkowanej liście odrzucana połowa mogłaby zawierać szukaną wartość, więc gwarancja poprawności znika.
Sortowanie i liczba operacji
Sortowanie to uporządkowanie elementów według przyjętej relacji, na przykład rosnących cen. Sortowanie bąbelkowe porównuje sąsiadów i zamienia ich miejscami, gdy są w złej kolejności. Po pełnym przebiegu największy element rozpatrywanego zakresu znajduje się na końcu. Następny przebieg może więc ominąć tę końcową pozycję.
1
2
3
4
5
6
dane=[5,2,4,1]
forkoniecinrange(len(dane)-1,0,-1):
foriinrange(koniec):
ifdane[i]>dane[i+1]:
dane[i],dane[i+1]=dane[i+1],dane[i]
print(dane)
Wynik to lista [1, 2, 4, 5]. W pierwszym przebiegu kolejne zamiany dają [2, 5, 4, 1], [2, 4, 5, 1] i [2, 4, 1, 5]. Pierwszy przebieg nie sortuje całej listy: ustawia na końcu 5. Równoległe przypisanie w Pythonie zamienia wartości bez ich utraty. Przy zwykłym nadpisaniu jednej komórki przed odczytem drugiej potrzebna byłaby zmienna pomocnicza.
Porządek rosnący dopuszcza równe sąsiadujące wartości. W pokazanej wersji zamieniamy elementy tylko wtedy, gdy lewy jest większy, więc elementy równe nie zamieniają się bezpośrednio miejscami. Przy porządkowaniu rekordów według ceny może mieć znaczenie zachowanie wcześniejszej kolejności produktów o tej samej cenie. Taką własność nazywa się stabilnością sortowania. Sam poprawny porządek wartości nie dowodzi stabilności. W zwykłym pytaniu o liczby wystarczy wyznaczyć kolejność, ale przy rekordach trzeba odczytać, co polecenie mówi o równych kluczach.
Liczba porównań opisuje koszt działania niezależnie od szybkości konkretnego komputera. Wyszukiwanie liniowe może przejrzeć wszystkie n elementów. Binarne po kolejnych podziałach potrzebuje liczby kroków rosnącej logarytmicznie. Prosta wersja sortowania bąbelkowego wykonuje około n razy n porównań dla dużych n. Zapis O(n), O(log n) i O(n²) opisuje tempo wzrostu kosztu, a nie dokładny czas w sekundach. Przebiegi sortowań porównuje wizualizacja algorytmów.
Rekurencja i zakończenie
Rekurencja to rozwiązanie, w którym funkcja wywołuje samą siebie dla mniejszego lub prostszego przypadku. Musi istnieć przypadek bazowy kończący wywołania oraz krok prowadzący w jego stronę. Silnia liczby n to iloczyn liczb od 1 do n, przy czym silnia zera wynosi 1. Przyjmujemy wyłącznie nieujemne liczby całkowite.
1
2
3
4
5
6
7
defsilnia(n):
ifn==0:
return1
returnn*silnia(n-1)
print(silnia(4))
Wynik to 24. Wywołania schodzą przez 4, 3, 2, 1 do 0, a następnie zwracają wyniki 1, 1, 2, 6 i 24. Bez przypadku bazowego wywołania nie kończyłyby się poprawnie. Dla ujemnego wejścia odliczanie w dół także nie osiągnie zera. To pokazuje znaczenie założenia o dopuszczalnym wejściu. Dla dużych danych trzeba dodatkowo uwzględnić ograniczenie głębokości wywołań środowiska.
Na egzaminie
Przy schemacie zacznij od wejścia i idź po zaznaczonych przejściach. Przy pętli policz dokładne indeksy, a przy rekurencji rozpisz zejście do przypadku bazowego oraz powrót. Nie utożsamiaj jednego przebiegu sortowania z pełnym wynikiem. Przy wyszukiwaniu binarnym sprawdź wymagane uporządkowanie i sposób liczenia pozycji.
Pułapka: algorytm może dawać dobry wynik dla jednego przykładu, a nadal być błędny. Pusta lista, powtórzenia i wartości graniczne sprawdzają inne ścieżki.
W praktyce najpierw zapisz oczekiwane wyniki krótkich przykładów, a potem uruchom kod. Składnię odpowiedniego języka opisują działy JS i PHP. Ten etap ma potwierdzić sposób rozwiązania, niezależnie od miejsca jego późniejszego użycia.