Upload
dangmien
View
250
Download
5
Embed Size (px)
Citation preview
Literatura
T. H. Cormen, C. E. Leiserson, R. L. Rivest, Wprowadzenie do
algorytmów, WNT, 1997,
J. Grębosz, Symfonia C++ standard, Editions 200 Kraków ,2008,
D. Harel, Rzecz o istocie informatyki (algorytmika), WNT, 1992,
K. Jamsa, Wygraj z C++, ZNI "MIKOM", 1996.
Tomasz Bielaczyc Algorytmy i język C++
Początek
W IV w. p. n. e. Euklides podał algorytm wyznaczania NWD dwóch liczb
naturalnych - jest to pierwszy znany algorytm.
W III w. p. n. e. Eratostenes podał metodę znajdowania liczb pierwszych.
Słowo algorytm wywodzi się od nazwiska perskiego matematyka z IX
wieku Muhammeda Alchwarizmi (łac. Algorismus), który podał reguły
dodawania, odejmowania, mnożenia i dzielenia liczb dziesiętnych.
Tomasz Bielaczyc Algorytmy i język C++
Pierwsze kalkulatory
William Oughtred stworzył suwak logarytmiczny w 1632 roku - po tym
jak John Napier odkrył logarytmy. W 1642 roku Blaise Pascal stworzył
“Pascaline“ - pierwszy mechaniczny kalkulator - posiadający 8 obrotowych
tarcz, dało się na nim wykonywać operacje dodawania i odejmowania na
ośmiocyfrowych liczbach (zbudował takich urządzeń koło pięćdziesięciu -
można je oglądać w muzeach).
W 1694 roku Gottfried Wilhelm Leibniz zbudował “Staffelwalze“ - wałek
korkowy - maszynę do mnożenia (którą zaprojektował w 1671 roku).
Thomas de Colmar skonstruował w 1820 roku kalkulator działający dzięki
bębnom z kołami zębatymi - był on masowo produkowany przez kolejne
100 lat. Kalkulatory bazujące na prototypie stworzonym przez Willgodta
Odhnera w 1890 roku używające tarcz z ruchomymi bolcami używane
były do lat siedemdziesiątych dwudziestego wieku.
Tomasz Bielaczyc Algorytmy i język C++
Pierwsze “komputery”
W 1833 roku Charles Babbage zbudował "maszyne różnicową" służącą
do obliczania pewnych wzorów matematycznych. Zrobił też projekt
"maszyny analitycznej" do realizacji algorytmów zakodowanych w postaci
otworów wydziurkowanych w kartach (wzorowanej na krośnie tkackim
wynalezionym w 1801 roku przez Josepha Jacquarda).
Kiedy Ada Byron zasugerowała, aby zilustrować działanie maszyny,
pokazując, jak obliczałaby liczby Bernoulliego powstał algorytm uważany
dziś za pierwszy program komputerowy.
Tomasz Bielaczyc Algorytmy i język C++
Pierwsze współczesne komputery
W 1890 roku Herman Hollerith zbudował maszyną tabulacyjną
umożliwiającą dokonanie spisu ludności w USA w niecałe 3 lata. Do
wprowadzania, sortowania i podliczania danych wykorzystywała
dziurkowane karty. W 1896 roku Hollerith założył firmę Tabulating
Machine Company, która w 1911 przekształciła się w International
Business Machines (IBM).
W 1939 Wiliam Hewlett i David Packard założyli firmę HP.
Pierwszy komputer używający systemu binarnego został stworzony w
1933 roku przez Konrada Zuse.
W 1945 roku powstał ENIAC - ważący 27 ton i zawierający 18000 lamp
eelektronowych komputer służył do obliczeń różnorakiego rodzaju. W
tym samym roku powstały tranzystory, dzięki którym kilka lat póżniej
prędkość i wydajność komputerów została zwielokrotniona.
Tomasz Bielaczyc Algorytmy i język C++
Asemblery
Pierwsze "prawdziwe" komputery powstały w latach 40-tych XX wieku.
Pierwsze języki programowania to asemblery. Są to języki bardzo zbliżone
do kodu maszynowego. Jedna instrukcja języka odpowiada tutaj jednej
instrukcji dla procesora. Języki tego typu nazywamy językami
programowania niskiego poziomu. Kompilatory (języki tłumaczące zapis
symboliczny na maszynowy) w tym przypadku również nazywane są
asemblerami.
Tomasz Bielaczyc Algorytmy i język C++
Języki wysokiego poziomu
Aby ułatwić pracę użytkownikowi powstały języki wysokiego poziomu. Są
to języki w dużym stopniu zrozumiałe dla użytkownika. Do przerobienia
na język maszynowy konieczny jest kompilator, który rozbija polecenia na
podpolecenia języka maszynowego.
Przykładowe dzisiaj stosowane języki wysokiego poziomu to Java, Pascal,
Python. Pierwszym takim językiem był Fortran stworzony w latach
50-tych przez Johna Backusa. Na przełomie lat 50-tych i 60-tych powstał
Algol pierwszy język zaprojektowany we współpracy międzynarodowej.
Tomasz Bielaczyc Algorytmy i język C++
Początki C
W 1966 roku Martin Richards zaprojektował język BCPL (Basic
Combined Programming Language). Jego następcą był język B,
natomiast w 1972 roku Dennis Ritchie i Ken Thompson stworzyli język C
(dla rozszerzenia możliwości języka B). Dopiero w 1978 roku język zyskał
(ogromne) zainteresowanie w związku z pojawieniem się książki Briana
Kerninghana i Dennisa Ritchiego pt. The C Programming Language
(Język C, WNT, 1988).
W 1981 roku po wprowadzeniu przez IBM komputera PC, język C
oderwał się od UNIXowych korzeni i stał się populanym językiem
mikrokomputerów.
Tomasz Bielaczyc Algorytmy i język C++
C++
Język C zyskał popularność wśród programistów, gdyż umożliwia
większą, niż inne języki kontrolę nad komputerem (można powiedzieć, że
jest językiem niższego poziomu, niż np. Java).
W roku 1983 Bjarne Stroustrup rozwinął C++. Rozszerza on C między
innymi o obiekty (struktury mogące przechowywać dane i funkcje).
Tomasz Bielaczyc Algorytmy i język C++
Kompilatory
Rozwojowi języka grozi zawsze rozbicie na wiele niezgodnych ze sobą
pakietów programowania. Kompilatory języka C dla PC są zgodne w
obszarach objętych normą ANSI/ISO (American National Standarts
Institute - Amerykański Narodowy Instytut Normalizacji, International
Organization for Standardization - Międzynarodowa Organizacja
Normalizacyjna), ale poza nimi występują różnice.
Tomasz Bielaczyc Algorytmy i język C++
Najkrótszy możliwy program
Najkrótszy możliwy program w języku C to
main() {}
Każdy program musi posiadać funkcję główną, której polecenia znajdują
się w nawiasie {}. (W zależności od kompilatora do funkcji głównej
często dodaje się przedrostek void lub int).
Oczywiście powyższy program nic nie robi.
Tomasz Bielaczyc Algorytmy i język C++
Instrukcja include
Aby móc używać podstawowych komend wejścia/wyjścia musimy
umieścić w programie ich definicje. Robimy to za pomocą instrukcji
#include. Jest to dyrektywa preprocesora (kompilator wykonuje ją przed
kompilowaniem). Dołącza ona plik odpowiedniej biblioteki.
W poniższym przypadku mówi kompilatorowi, aby pobrał plik stdio.h
i umieścił jego zawartość w tym miejscu programu.
Tomasz Bielaczyc Algorytmy i język C++
Pierwszy program
#include <stdio.h>
int main()
{
printf("Witaj świecie!"); //wypisuje na ekran:
// Witaj świecie!
}
Tomasz Bielaczyc Algorytmy i język C++
Biblioteki
W trakcie tego wykładu zamiast stdio.h będziemy używać biblioteki
iostream. Ponadto dodamy przestrzeń nazw poleceniem
using namespace std; (bez tego przed niektórymi poleceniami
konieczne byłoby dopisywanie przedrostka std::).
(Podobny do iostream z przestrzenią nazw std zasób poleceń, chociaż
mniejszy, daje biblioteka iostream.h.)
Tomasz Bielaczyc Algorytmy i język C++
Polecenia wejścia - wyjścia
Jako polecenia standartowego wyjścia (wypisywania na ekran) będziemy
wówczas mogli użyć cout (jest to polecenie języka C++) zamiast
komendy printf z biblioteki stdio.h. Dla standartowego wejścia
użyjemy komendy cin (a nie polecenia scanf).
Tomasz Bielaczyc Algorytmy i język C++
Polecenia wejścia - wyjścia
Wczytywane zmienne oddzielamy od siebie (oraz od polecenia cin)
sybmolem >>. Wypisywane zmienne oraz wypisywany tekst (który
wstawiamy w cudzysłów) odzielamy symbolem << (składnia poleceń
printf oraz scanf jest bardziej skomplikowana)
Tomasz Bielaczyc Algorytmy i język C++
Polecenia pomocnicze
Poleceniem system("chcp 1250"); otrzymujemy możliwość dostania
w konsoli polskich znaków - trzeba w tym celu we właściwościach konsoli
wybrać czcionka: Lucida Console.
Poleceniem ("cls"); możemy wyczyścić tekst w konsoli - po
uruchomieniu programu pojawi się tylko tekst tego programu dotyczący.
Aby konsola nie zniknęła natychmiast po wykonaniu zadania1 w treści
kodu programu musimy dopisać polecenie system("pause");
1dotyczy np. wxDev-C++Tomasz Bielaczyc Algorytmy i język C++
Zmienne typu char
Zmienna typu char odpowiada jednemu znakowi i zajmuje jeden bajt
pamięci (może ona służyć także do reprezentowania liczb w zakresie od
-128 do 127).
Tomasz Bielaczyc Algorytmy i język C++
Zmienne typu char
Poniższy program wczytuje, a następnie wypisuje dwie litery.
#include<iostream>
using namespace std;
int main( )
{
char a, b; //deklarujemy dwie zmienne typu char
cout<<"Podaj swoje inicjały\n"; //"\n"-przejście do nowej linii
cin >> a >> b; //wczytanie zmiennych a, b
cout<<"Imię zaczyna się od "<<a<<", a nazwisko od "<<b<<".\n";
}
Tomasz Bielaczyc Algorytmy i język C++
Tablica znaków
W poniższej funkcji głównej programu aby wczytać ciąg liter użyjemy
tablicy znaków typu char.
char IMIE[15]; //15 - maksymalna długość ciągu znaków
cout << "Jak masz na imię? \n";
cin >> IMIE; //wczytanie ciągu znaków
cout << "Witaj " << IMIE << "! \n";
Tomasz Bielaczyc Algorytmy i język C++
Zmienne typu string
Zamiast deklarować tablicę znaków możemy użyć zmiennej typu string.
Niektóre kompilatory wymagają dodania biblioteki string (czyli
dopisania w nagłówku #include <string>). Napiszmy jeszcze raz
podobny program
string imie, adres, dane;
cout << "Podaj swoje imię. \n";
cin >> imie;
cout << "Podaj swój adres. \n";
cin >> adres; //wpisujemy bez użycia spacji
Tomasz Bielaczyc Algorytmy i język C++
Zmienne typu string
Na koniec wypiszmy dane
cout << "imię: " << imie << ", adres: " << adres << endl;
(Ten sam efekt wypisania danych uzyskamy pisząc
dane="imię: "+imie+", adres: "+adres;
cout << dane << endl; //endl = "\n"
)
Tomasz Bielaczyc Algorytmy i język C++
Zmienna typu int
Jednym z najbardziej popularnych typów zmiennych jest zmienna typu
int. Typ int ma obecnie2 rozmiar czterech bajtów (32 bitów) i obejmuje
liczby całkowite z zakresu od -2147483648 (czyli -231) do 2147483647.
Zmienna unsigned mając 4 bajty reprezentuje liczby od 0 do 232−1.
Gdybyśmy chcieli działać na jeszcze większych liczbach możemy użyć
zmiennej typu long long o rozmiarze ośmiu bajtów.
2zależnie od kompilatora i od procesora, można to sprawdzić wpisując w programie
cout « sizeof(int);Tomasz Bielaczyc Algorytmy i język C++
Zmienna typu int
Dopiszmy do naszego programu pytanie o wiek.
int wiek;
int rok=2011; //deklarując zmienną możemy przypisać jej wartość
cout << "Ile lat skończyłeś(łaś) lub skończysz w tym roku? \n";
cin >> wiek;
rok = rok-wiek; //przypisanie nowej wartości zmiennej rok
cout << "Urodziłeś się w " << rok << " roku. \n";
Tomasz Bielaczyc Algorytmy i język C++
Działania, zakres int-a
Oczywiście −, +, ∗ są standartowymi działaniami. Operacja / daje dla
zmiennych całkowitych wynik dzielenia z resztą (działanie na int-ach
musi zwracać int-a). Działanie % daje resztę z dzielenia.
Łatwo podać przykład dwóch liczb będących w zakresie int-a, których
iloczyn bądź suma wychodzą poza ten zakres - wówczas otrzymamy
nieprawidłowy wynik.
Tomasz Bielaczyc Algorytmy i język C++
Kod ASCII
Kod ASCII (American Standard Code for Information Interchange)
przyporządkowuje liczby z zakresu 0-127 literom i innym symbolom. Duże
litery są reprezentowane liczbami od 65 do 90, a małe liczbami od 97 do
122. Wykonując poniższy program można sprawdzić jaką liczbą jest
kodowany dany znak.
Tomasz Bielaczyc Algorytmy i język C++
Kod ASCII
Pisząc
char znak;
cin >> znak;
int kod=znak;
otrzymamy przyporządkowanie znakowi wpisanemu z klawiatury jego
kodu ASCII. Następnie możemy go wypisać
cout<<"Znak "<<znak<<" jest kodowany liczbą "<<kod<<".";
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program proszący o podanie pięciu liter, a następnie wypisujący je
na ekran w odwrotnej kolejności.
ZadanieNapisz program pytający o imię, nazwisko oraz miasto zamieszkania, a
następnie wypisujący te dane na ekran.
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program proszący o podanie dwóch liczb całkowitych, a następnie
wypisujący ich sumę, różnicę, iloczyn oraz wynik dzielenia z resztą
pierwszej przez drugą i drugiej przez pierwszą.
ZadanieNapisz program pytający o rok i miesiąc urodzenia oraz wypisujący na
ekran ilość przeżytych miesięcy.
ZadaniePisząc c=a%b; przypisujemy zmiennej c resztę z dzielenia a przez b.
Napisz program obliczjący resztę z dzielenia pierwszej podanej liczby
przez drugą bez użycia %.
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program proszący o wpisanie kolejnych trzech znaków z klawiatury
i wypisujący ich kod ASCII.
ZadanieNapisz program proszący o podanie liczby z zakresu od 97 do 122, a
następnie wypisujący dla jakiej litery podana liczba jest kodem.
Tomasz Bielaczyc Algorytmy i język C++
Instrukcja if
Instrukcja warunkowa if umożliwia wykonanie pewnego polecenia lub
bloku poleceń przy założeniu, że spełniony jest odpowiedni warunek.
Może być postaci
if(warunek)
instrukcje
lub
if(warunek)
instrukcja1
else
instrukcja2
i tak dalej.
Tomasz Bielaczyc Algorytmy i język C++
Instrukcja if
Jeżeli instrukcja składa się z więcej niż jednego polecenia musi cała być
wzięta w nawias { }. W warunku często używamy operacji relacji:
== równy, > większy, >= większy lub równy, < mniejszy,
<= mniejszy lub równy, ! = różny
oraz operatorów logicznych
&& oraz, ‖ lub, ! nieprawda, że.
Tomasz Bielaczyc Algorytmy i język C++
Podzielność
Sprawdźmy podzielność jednej liczby całkowitej przez drugą.
int a, b;
cout << "Podaj a \n";
cin >> a;
cout << "Podaj b \n";
cin >> b;
if (a%b>0)
cout << "Liczba a nie jest podzielna przez b. \n";
else
cout << "Liczba b dzieli a. \n";
Tomasz Bielaczyc Algorytmy i język C++
Minimum
Znajdźmy teraz najmniejszą z trzech różnych liczb.
int a, b, c;
cout << "Podaj trzy różne liczby \n";
cin >> a >> b >> c;
if (a<b && a<c)
cout << "Pierwsza podadana liczba jest najmniejsza. \n";
else if (b<c)
cout << "Druga podadana liczba jest najmniejsza. \n";
else
cout << "Trzecia podadana liczba jest najmniejsza. \n";
Tomasz Bielaczyc Algorytmy i język C++
Typ zmiennoprzecinkowy
W poniższej funkcji użyjemy zmiennej typu float. Zajmuje ona 4 bajty
pamięci, ma zakres od 3.4 ·10−38 do 3.4 ·1038 i dokładność 6 cyfr
znaczących.
Przykładowo zapis 12.3456e+09 oznacza liczbę 12.3456 ·109, zapis
6.54321e-13 oznacza 6.54321 ·10−13.
Tomasz Bielaczyc Algorytmy i język C++
Równanie liniowe
Aby rozwiązać równanie liniowe ax = b najpierw wczytajemy dane.
float a, b, wynik;
cout <<"Rozwiążmy równanie liniowe postaci ax=b. \n";
cout << "a=";
cin >> a;
cout << "b=";
cin >> b;
Tomasz Bielaczyc Algorytmy i język C++
Równanie liniowe
Mamy trzy możliwości
if (a!=0)
{
wynik=b/a; //dla typu float / jest zwykłym dzieleniem
cout <<"Rozwiazaniem jest b/a=" <<wynik <<endl;
}
else if (b==0)
cout <<"Rozwiązaniem jest każda liczba rzeczywista.\n";
else
cout << "Równanie nie ma rozwiązań. \n";
Tomasz Bielaczyc Algorytmy i język C++
Instrukcja switch
W przypadku, gdy alternatywnych warunków jest więcej (i gdy da się je
przedstawić za pomocą wartości) warto użyć instrukcji switch.
Po wczytaniu danych
float a,b;
char dzialanie;
cout << "Wprowadz dane: <liczba> <dzialanie> <liczba> \n";
cin >> a >> dzialanie >> b;
możemy napisać funkcję definiującą wybrane działanie.
Tomasz Bielaczyc Algorytmy i język C++
Instrukcja switch
switch(dzialanie)
{
case ’+’: cout << a+b << endl; break;
case ’-’: cout << a-b << endl; break;
case ’*’: cout << a*b << endl; break;
case ’/’: if(b==0)
cout << "Nie dziel przez zero! \n"
else
cout << a/b << endl;
break;
default: cout << "Nieznane działanie" << endl;
}
Tomasz Bielaczyc Algorytmy i język C++
Dokładność
Jeśli po uruchomieniu powyższego programu wpiszemy sumowanie bardzo
dużej i bardzo małej liczby możemy dostać nieprawdziwy lub niedokładny
wynik. Przykładowo sumując 100000+0.002 otrzymamy wynik 100000.
Sześciocyfrowa dokładność zmiennych typu float nie pozwala otrzymać
precyzyjnego wyniku w tym przypadku.
Tomasz Bielaczyc Algorytmy i język C++
Dokładność
Możemy poprawić dokładność używając zmiennej typu double.
Ma on 8 bajtów i dokładność 15 cyfr znaczących. Można za jej pomocą
reprezentować liczby z zakresu od 1.7e−308 do 1.7e+308.
Aby program wypisywał wynik obliczeń ze zwiększoną dokładnością
musimy przed poleceniami wypisywania dodać polecenie
cout.precision(15);
Tomasz Bielaczyc Algorytmy i język C++
Inne działania
Jeżeli chcemy poza standardowymi działaniami otrzymać na przykład
sin(a), cos(a), log(a) lub ab poleceniem pow(a,b) albo całość z a
poleceniem floor(a), musimy dołączyć do programu bibliotekę math.h.
Napiszmy funkcję, która dla podanych liczb rzeczywistych a, b
sprawdza, czy większe jest ab, czy ba.
Tomasz Bielaczyc Algorytmy i język C++
include<math.h>
float a,b;
cout << "Wpisz dwie liczby \n";
cin >> a >> b;
if(pow(a,b)>pow(b,a))
cout<<"a^b="<<pow(a,b)<<"<b^a="<<pow(b,a)<<endl;
else if(pow(a,b)<pow(b,a))
cout<<"a^b="<<pow(a,b)<<"<b^a="<<pow(b,a)<<endl;
else
cout<<"a^b="<<pow(a,b)<<"=b^a="<<pow(b,a)<<endl;
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program proszący o podanie liczby całkowitej, a następnie
wypisujący jej wartość bezwzględną.
ZadanieNapisz (używając instrukcji switch) program pytający o ocenę jaką
dostałeś na ostatnim egzaminie i po wczytaniu cyfry wypisujący ocenę
pisemnie.
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program proszący o podanie trzech liczb całkowitych, a następnie
stwierdzający, która z nich (lub które) jest największa.
ZadanieNapisz program proszący o wybranie obliczenia pole koła lub pola trójkąta
równobocznego, następnie proszący o podanie średnicy (lub długości
boku) i obliczający (z dokładnością 15 cyfr) pole wybranej figury.
ZadanieNapisz program proszący o podanie parametrów a,b,c , a następnie
rozwiązujący równanie kwadratowe ax2+bx + c = 0.
Tomasz Bielaczyc Algorytmy i język C++
Pętla for
Pętla for ma postać
for(stan początkowy; warunek; zmiany)
instrukcje
Przykładowo pętla służąca do wypisania 20 kolejnych liczb parzystych
będzie wyglądać następująco
int i, n=20;
for(i = 0; i < n; i++) //instrukcje będą wykonywane dopóki i<n
cout << 2*i << ", "; //i++ oznacza zwiększenie i o 1
Tomasz Bielaczyc Algorytmy i język C++
Pętla for
Napiszmy funkcję proszącą o podanie liczby naturalnej n, a następnie dla
liczb i < n sprawdzający, czy i jest dzielnikiem n.
int i, n;
cout <<"Podaj liczbę n"<<endl;
cin >>n;
for(i = 2; i < n; i++)
{
if(n%i==0)
cout <<"Liczba "<<i<<" dzieli "<<n<<".\n";
else
cout <<"Liczba "<<i<<" nie dzieli "<<n<<".\n";
}
Tomasz Bielaczyc Algorytmy i język C++
Liczby pierwsze
Chcąc dostać odpowiedź na pytanie, czy n jest liczbą pierwszą w
powyższym programie zadeklarujemy dodatkowo zmienną odp=0 oraz
zmodyfikujemy warunek w następujący sposób
if(n%i==0)
odp=1;
a na koniec napiszemy
if(odp==0)
cout <<"Liczba "<<n<<" jest pierwsza.\n";
else
cout <<"Liczba "<<n<<" nie jest pierwsza.\n";
Tomasz Bielaczyc Algorytmy i język C++
Ciąg liczb losowych
Napiszmy program wczytujący losowy ciąg liczb z zakresu od 1 do 1000,
a następnie znajdujący element maksymalny. Aby móc losować liczby
poleceniem rand() potrzebujemy (dla niektórych kompilatorów)
biblioteki stdlib.h. Aby tablica "wylosowanych" liczb nie była za
każdym wykonaniem programu taka sama (początkowa wartość
generatora jest za każdym razem taka sama) wstawimy przed pętlą
polecenie srand(time(0)); które jako wartość początkową bierze liczbę
sekund, która upłynęła od północy 1 stycznia 1970 roku. Potrzebna jest
do tego (dla pewnych kompilatorów) biblioteka ctime.
(Ponadto w preambule możemy zdefiniować stałą N równą 20 poleceniem
#define N 20.)
Tomasz Bielaczyc Algorytmy i język C++
Maksimum
Losowanie ciągu liczb będzie wyglądać następująco
int main()
{
srand(time(0));
int i, max=0;
int T[N]; //deklarujemy tablicę (statyczną)
for(i = 0; i < N; i++)
{
T[i] = rand() % (1000);
cout << T[i] << endl;
}
}
Tomasz Bielaczyc Algorytmy i język C++
Maksimum
Dopiszmy pętlę znajdującą element maksymalny.
for(i = 0; i < N; i++)
if(T[i]>max)
max = T[i];
cout << "Maksymalna z powyższych liczb to " << max << endl;
Tomasz Bielaczyc Algorytmy i język C++
Złożoność
Zauważmy, że szukając maksymalnego elementu wykonaliśmy n operacji
porównania. Oznacza to, że program ma złożoność obliczeniową O(n) -
czas wykonania jest proporcjonalny do liczby n danych wejściowych
(rośnie liniowo ze wzrostem liczby elementów).
Tomasz Bielaczyc Algorytmy i język C++
Złożoność
Programy o złożoności O(n) działają dosyć szybko nawet dla dużych n.
Dużo wolniej działają programy o złożoności O(n2) (przykładowo dla
n = 10000 średnio szybkiemu komputerowi wykonanie programu zajmie
około jednej sekundy, czas rośnie tutaj z kwadratem, więc dla n = 40000
wykonanie programu zajmie około 16 sekund, dla n = 100000 - ponad
minutę). Dlatego warto, gdy tylko to możliwe, zastępować je programami
o złożoności O(n logn).
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program sprawdzający czy podana liczba jest liczbą pierwszą.
ZadanieNapisz program liczący silnię zadanej liczby. (Co się stanie, gdy wynik
przekroczy zakres inta?)
ZadanieNapisz program proszący o podanie liczby miesięcy n, kwoty k oraz
oprocentowania rocznego p (z miesięczną kapitalizacją) i liczący jaką
kwotę otrzymamy wpłacając k złotych na n miesięcy.
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program proszący o podanie liczby n, a następnie o wpisanie n
liczb rzeczywistych i liczący ich sumę. (Czy możemy dodawać liczby
bardzo duże do liczb bliskich zeru?)
ZadanieNapisz program wczytujący losowo ciąg 1000 liczb naturalnych
mniejszych od 10000 i sprawdzający, czy w tablicy znajduje się liczba
1000, a jeśli tak, to na którym miejscu.
ZadanieNapisz program wczytujący dla podanej liczby n < 10000 ciąg liczb
naturalnych długości n oraz znajdujący równocześnie (jedna pętla)
minimalny i maksymalny element tego ciągu. (Jaka jest najmniejsza, a
jaka największa ilość porównań, które program wykona?)Tomasz Bielaczyc Algorytmy i język C++
Pętla “do while“
Pętla do while ma postać
do
instrukcje
while(warunek);
Instrukcje będą wykonywane dopóki spełniony będzie zadany warunek
(zatem wykonanie instrukcji powinno między innymi zmieniać wartość
zadaną w warunku).
Tomasz Bielaczyc Algorytmy i język C++
Pętla ”do while“ - suma
Napiszmy pętlę sumującą kolejne podawane liczby do momentu, gdy
suma przekroczy wartość 100..
int a, suma=0;
cout << "Wpisuj kolejne liczby. \n";
do
{
cin >> a;
suma+=a; //równoznaczne z suma=suma+a;
cout << "suma=" << suma << endl;
}
while(suma<=100);
Tomasz Bielaczyc Algorytmy i język C++
Pętla ”while“
W powyższym przypadku instrukcja zostanie wykonana co najmniej raz.
Jeśli zastosujemy pętlę while zaczyniemy od sprawdzenia warunku, więc
możemy ani razu nie wykonać instrukcji. Pętla while jest postaci
while(warunek)
instrukcje
Tomasz Bielaczyc Algorytmy i język C++
Pętla ”while“ - potęgi
Napiszmy funkcję liczącą kolejną potęgę podanej liczby, dopóki jest ona
mniejsza niż 1000.
int liczba;
cout << "Podaj liczbę \n";
cin >> liczba;
int potega=liczba, wykladnik=1;
while(potega<1000)
{
cout << liczba <<"^"<< wykladnik << "=" << potega << endl;
potega*=liczba; //lub potega = liczba*potega;
wykladnik++;
}
Tomasz Bielaczyc Algorytmy i język C++
”do while“ vs ”while“
Zauważmy, że gdybyśmy użyli tutaj pętli do while, to w przypadku,
gdyby pierwsza podana liczba była większa od 1000, wypisany zostanie
pierwsza potęga tej liczby mimo, iż wypisywane miały być tylko potęgi
mniejsze od 1000.
Pętle do while, while oraz for można stosować zamiennie (w
powyższym programie po dokonaniu pewnych poprawek moglibyśmy użyć
pętli do while, a nawet for), jednak czasem użycie jednej jest dużo
wygodniejsze niż innych.
Tomasz Bielaczyc Algorytmy i język C++
Wyszukiwanie elementu w tablicy
Aby napisać algorytm sprawdzający, czy dany element znajduje się w
danej uporządkowanej tablicy liczb, możemy np. sprawdzić po kolei
wszystkie elementy tablicy. Algorytm taki ma złożoność pesymistyczną
O(n).
Tomasz Bielaczyc Algorytmy i język C++
Wyszukiwanie binarne
Algorytm wyszukiwania binarnego polega na wybraniu środkowego
elementu tablicy i sprawdzeniu czy jest on szukanym elementem, a jeśli
nie, to czy jest mniejszy czy większy od elementu szukanego. Jeśli jest
mniejszy, powtarzamy procedurę dla lewej połowy tablicy, jeśli większy,
dla prawej połowy. Ponieważ w każdym kroku zmniejszamy zakres
poszukiwań co najmniej dwukrotnie, więc algorytm ma złożoność
O(logn) (log rozumiany jest jako logarytm o podstawie 2). Poniższy
program sprawdza, czy we wczytanej wcześniej tablicy T takiej, że
T[i]<T[i+1] dla i ∈ {1, . . . ,N}, znajduje się liczba S .
Tomasz Bielaczyc Algorytmy i język C++
Wyszukiwanie binarne
int l=1, p=N, odp=0, n;
while (l<=p && odp==0)
{
n=(l+p)/2;
if (T[n] < S)
l=n+1;
else if (T[n] > S)
p=n-1;
else
odp = 1;
}
Tomasz Bielaczyc Algorytmy i język C++
Wyszukiwanie binarne
Na koniec wypiszemy wynik
if(wynik==1)
cout<<"Ciąg zawiera liczbę 200 \n";
else
cout<<"Ciąg nie zawiera liczby 200 \n";
Jeśli na koniec wynik=1, to znaczy, że nasz rosnący ciąg stu liczb
naturalnych zawiera liczbę 200.
Tomasz Bielaczyc Algorytmy i język C++
Potęgowanie binarne
Najprostszy algorytm obliczający nm polega na wykonaniu m−1
kolejnych mnożeń przez n. Algorytm potęgowania binarnego polega na
zastąpieniu działania nm równoważnym działaniem (n2)m/2, czyli
podstawieniem
n = n*n;
m = m/2;
gdy wykładnik jest parzysty, lub działaniem n ·nm−1, czyli podstawieniem
wynik = wynik*n;
m--;
gdy wykładnik jest nieparzysty.
Tomasz Bielaczyc Algorytmy i język C++
Potęgowanie binarne
Procedurę powtarzamy dopóki wykładnik jest różny od zera. Otrzymamy
przykładowo 210 = 45 = 4 ·44 = 4 ·162 = 4 ·256= 1024 ·2560.
Tomasz Bielaczyc Algorytmy i język C++
Algorytn Euklidesa
Pętlę while zastosujemy także w algorytmie Euklidesa, który służy do
obliczania największego wspólnego dzielnika podanych liczb a i b. Polega
on na obliczeniu r - reszty z dzielenia a przez b, zastąpieniu a przez b,
zaś b przez r oraz w przypadku b > 0, powtórzeniu całej procedury. W
momencie, kiedy b = 0, "obecne" a jest największym wspólnym
dzielnikiem.
Tomasz Bielaczyc Algorytmy i język C++
Algorytm Euklidesa
int a,b,r ;
cout << "Podaj dwie liczby naturalne.\n";
cin >> a >> b;
while(b>0)
{
r=a%b;
a=b;
b=r;
}
cout << "NWD(a,b)=" << a << endl;
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program wymnażający kolejne wczytywane liczby rzeczywiste i
wypisujący iloczyn na ekran, do momentu, gdy iloczyn przekroczy 30000.
ZadanieNapisz program sumujący wczytane liczby rzeczywiste i wypisujący sumę
na ekran, do momentu, aż wpisane zostanie zero.
ZadanieNapisz program raz za razem proszący o podanie dwóch liczb
naturalnych, i sprawdzający, czy pierwsza jest podzielna przez drugą, aż
do momentu, gdy po raz drugi pierwsza liczba będzie podzielna przez
drugą.
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program wczytujący losowo rosnący ciąg 1000 liczb naturalnych
mniejszych od 10000 i sprawdzający, czy w tablicy znajduje się liczba
1000, a jeśli tak, to na którym miejscu.
ZadanieNapisz program wczytujący podstawę i wykładnik i liczący binarnie
potęgę.
ZadanieNapisz program raz za razem proszący o podanie dwóch liczb naturalnych
i liczący ich największy wspólny dzielnik do momentu, gdy wynik wyniesie
2 lub 3.
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program proszący o wpisywanie kolejnych ocen i liczący na
bieżąco średnią, aż do momentu wpisania zera.
ZadanieNapisz program proszący o podanie kwoty początkowej k,
oprocentowania rocznego p (z miesięczną kapitalizacją) oraz kwoty
wypłacanej co miesiąc m (zaraz po kapitalizacji odsetek) i sprawdzający
kiedy opróżnimy konto (o ile nastąpi to przed upływem 10 lat) lub
obliczający stan konta po 10 latach.
Tomasz Bielaczyc Algorytmy i język C++
Sortowanie bąbelkowe
Istnieje wiele sposobów na uporządkowanie danego ciągu liczb w
kolejności od najmniejszej do największej. Jednym z prostszych jest
sortowanie bąbelkowe. Ma ono złożoność O(n2) (później podany
zostanie algorytm sortowania o optymistycznej złożoności O(n logn)).
Sortowanie bąbelkowe polega na kolejnym porównywaniu dwóch
sąsiadujących elementów ciągu i ewentualnym ich zamienianiu tak, aby
większy z nich występował jako późniejszy. Po jednokrotnym
przeglądnięciu w ten sposób całej tablicy największy element ląduje na
końcu. Po n−1 powtórzeniach tej procedury elementy tablicy będą
uporządkowane od najmniejszego do największego. Napiszmy funkcję
sortującą.
Tomasz Bielaczyc Algorytmy i język C++
Sortowanie bąbelkowe
for(i = 0; i < n-1; i++)
for(j = 0; j < n-i; j++)
if(T[j] > T[j+1])
swap(T[j],T[j+i]); //zamieniamy wartości miejscami
Zauważmy, że w wewnętrznej pętli bierzemy j do n-i. Elementy tablicy
od n-i do n są w tym momencie już posortowane.
Tomasz Bielaczyc Algorytmy i język C++
Sortowanie bąbelkowe
Na koniec wypisujemy posortowany ciąg
for(i=0; i<n; i++)
cout << T[i] << endl;
Tomasz Bielaczyc Algorytmy i język C++
Sortowanie przez wybór
Bardzo podobny jest algorytm sortowania przez wybór. Polega on na
znalezieniu najmniejszego elementu tablicy i zamienieniu go z pierwszym
elementem, następnie znalezieniu najmniejszego z pozostałych i
zamienieniu go z drugim itd.
Tomasz Bielaczyc Algorytmy i język C++
Przeliczanie systemów liczbowych
Aby napisać program przeliczający systemy, przykładowo z dziesiętnego
na szesnastkowy, musimy zdefiniować tablicę szesnastu znaków - każdy
przypisany jednej cyfrze zadanej liczby.
int ODP[7]; //w tę tablicę wpiszemy odpowiedniki cyfr
//rozwinięcia szesnastkowego zadanej liczby
int liczba, pozycja=0;
char CYFRA[]="0123456789ABCDEF"; //czyli CYFRA[0]=0;
// ... CYFRA[15]=F;
(Podobnie możemy definiować tablice int-ów, np.
int T[]={3,5,2,6,1} ustala rozmiar tablicy na 5. )
Tomasz Bielaczyc Algorytmy i język C++
Przeliczanie systemów liczbowych
Obliczając resztę z dzielenia naszej liczby przez 16 dostajemy ostatnią
cyfrę rozwinięcia, po podzieleniu całkowitym liczby przez 16 powtarzając
procedurę otrzymujemy kolejne cyfry, aż wynik całkowitego dzielenia
przez 16 wynosi zero.
cin >> liczba;
while(liczba!=0)
{
ODP[pozycja] = liczba%16;
liczba = liczba/16;
pozycja++;
}
Tomasz Bielaczyc Algorytmy i język C++
Przeliczanie systemów liczbowych
Teraz możemy wypisać wynik;
cout << "Wynik zapisany cyframi szesnastkowymi: \n";
for(i=pozycja; i>0; i--)
cout << CYFRA[ODP[i-1]];
Tomasz Bielaczyc Algorytmy i język C++
Liczby słownie
Za pomocą podobnego algorytmu możemy napisać program
wyświetlający podaną liczbę słownie (tzn. wypisujący kolejno cyfry tej
liczby. Po zdefiniowaniu nazw cyfr
string NAPIS[10]={"zero","jeden","dwa","trzy","cztery",
"piec","szesc","siedem","osiem","dziewiec"};
cyfry od ostatniej do pierwszej otrzymamy jako reszty z kolejnych dzieleń
zadanej liczby przez 10.
Tomasz Bielaczyc Algorytmy i język C++
Sito Erastotenesa
Eratostenes w trzecim wieku przed naszą erą przedstawił następujący
algorytm wyszukiwania liczb pierwszych. Wszystkie wielokrotności liczby
2 większe od niej samej oznaczamy jako liczby złożone. Z liczb większych
od 2 wybieramy najmniejszą niezaznaczoną jeszcze liczbę (czyli 3) i
wszystkie jej wielokrotności większe od niej samej oznaczamy jako
złożone (niektóre liczby będą zaznaczane więcej niż raz). Postępując dalej
według tej procedury jako liczby złożone oznaczamy wielokrotności 5, 7,
11 it.d. Dla danej liczby n wszystkie liczby mniejsze od n, które w efekcie
powyższej procedury nie zostały oznaczone jako złożone, są liczbami
pierwszymi.
Tomasz Bielaczyc Algorytmy i język C++
Sito Erastotenesa
Ustalmy liczbę n i wszystkie liczby mniejsze od niej oznaczamy jedynką.
cout << "Ile liczb sprawdzić? \n";
cin >> n;
int* T; //deklarujemy tablicę
T = new int[n]; //definiujemy rozmiar tablicy
for(i = 2; i < n; i++)
T[i] =1; //kolejne liczby zaznaczamy
//jako potencjalnie pierwsze
Tomasz Bielaczyc Algorytmy i język C++
Tablica jako wskaźnik do pamięci
Deklarując zmienną nadajemy nazwę pewnemu obszarowi pamięci,
natomiast nazwa tablicy wskazuje dokładnie na miejsce w pamięci, gdzie
ta tablica się zaczyna. Jeśli stosujemy dynamiczną alokację zmiennych
(czyli rozmiar tablicy definiujemy na etapie wykonywania programu),
musimy (dla niektórych kompilatorów) użyć powyższej składni lub
napisać int*T=new int[n]. Operator * oznacza, że deklarujemy
wskaźnik do pamięci. Operator new przydziela pamięć.
Tomasz Bielaczyc Algorytmy i język C++
Sito Erastotenesa
Zerem oznaczamy wszystkie liczby mniejsze od n, które są złożone,
for (i = 2; i <= n; i++)
if (T[i]==1)
for (j = i; j*i < n; j++)
T[i*j] =0;
i wypiszmy liczby pierwsze mniejsze od n (czyli te numery, dla których
wartość elenentu tablicy jest równa 1).
for (i = 2; i < n; i++)
if (T[i]==1)
cout << i << ", ";
Tomasz Bielaczyc Algorytmy i język C++
Schemat Hornera
Aby obliczyć wartość wielomianu Pn(x) = anxn +an−1xn−1+ . . .a1x +a0
w danym punkcie x należy wykonać n dodawań, n mnożeń przez
współczynnik ai oraz n(n−1)/2 mnożeń potrzebnych do podniesienia x
na każdym miejscu do odpowiedniej potęgi. Ilość tych działań można
zmniejszyć stosując schemat Hornera.
Tomasz Bielaczyc Algorytmy i język C++
Schemat Hornera
Schemat Hornera polega na rozpisaniu wielomianu
Pn(x) = anxn +an−1xn−1+ . . .a1x +a0 = x(anxn−1+an−1xn−2+ . . .a1)+a0 =
= x(x(anxn−2+an−1xn−3+ . . .a2)+a1)+a0 =
= x(x(. . .x(x ·an +an−1)+an−2)+ . . .+a1)+a0
i obliczeniu jego wartości. Zauważmy, że wówczas wykonane zostanie
jedynie n mnożeń oraz n dodawań, zatem zmniejszymy złożoność z O(n2)
do O(n).
Tomasz Bielaczyc Algorytmy i język C++
Schemat Hornera
Mając wczytane współczynniki wielomianu a[i] oraz wartość x użyć
można w tym celu pętli;
s=a[n];
for (int i=n-1; i>=0; i--)
s=s*x+a[i];
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program proszący o podanie 10 liczb, a następnie sortujący
(metodą bąbelkową) ten ciąg. Zrób to bez użycia polecenia swap
ZadanieNapisz program wczytujący dla podanej liczby n losowy ciąg długości n
oraz sortujący (przez wybór) ten ciąg. Omów złożoność programu.
ZadanieNapisz program zadający pytanie na jaki system od dwójkowego do
szesnastkowego zamienić zadaną liczbę zapisaną w systemie dziesiętnym,
a następnie wyświetlający wynik w zadanym systemie.
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program wypisujący zadaną liczbę jako ciąg słów oznaczających
jej kolejne cyfry.
ZadanieNapisz program znajdujący dla zadanej liczby naturalnej najlepsze
naturalne przybliżenie jej pierwiastka.
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program sprawdzający, ile jest liczb pierwszych mniejszych od
podanej liczby.
ZadanieNapisz program, który dla podanej liczby wspólczynników wczyta je po
kolei i korzystając ze schematu Hornera policzy wartość wielomianu w
zadanym punkcie. (Napisz program liczący wartość wielomianu bez
użycia schematu Hornera. Porównaj złożoność tych dwóch programów.)
Tomasz Bielaczyc Algorytmy i język C++
Macierz
Macierz wyrazić możemy dwuwymiarową tablicą. Aby wypisać wcześniej
zdefiniowaną macierz A o m kolumnach i n wierszach napiszemy
for(i=0; i<n; i++)
{
for(j=0; j<m; j++)
cout<<A[i][j]<<" ";
cout<<endl;
}
Tomasz Bielaczyc Algorytmy i język C++
Macierze
Aby zdefiniować macierz B jako transponowaną do A wystarczy podstawić
B[j][i]=A[i][j] (jeśli A ma rozmiary n×m, to B musi mieć rozmiary
m×n).Aby dodać dwie macierze A, i B (tych samych rozmiarów) wystarczy dla
każdych i,j dodać A[i][j]+B[i][j].
Tomasz Bielaczyc Algorytmy i język C++
Mnożenie macierzy
Zdefiniujmy dwie macierze takie, aby liczba kolumn pierwszej z nich była
równa liczbie wierszy drugiej.
float A[3][4] = {{1,2,0,0},
{1,3,2,0},
{3,0,1,1}};
float B[4][2] = {{1, 2},
{2, 0.6},
{0, 1},
{3, 5}};
Tomasz Bielaczyc Algorytmy i język C++
Mnożenie macierzy
Aby pomnożyć macierze A, i B musimy policzyć odpowiednie sumy
iloczynów;
float AB[3][2]={{0}}; //deklarujemy macierz AB
//na początku na każdym miejscu tablicy są zera
for(int i=0; i<3; i++)
for(int j=0; j<2; j++)
for(int k=0; k<4; k++)
AB[i][j] = AB[i][j]+A[i][k]*B[k][j];
Tomasz Bielaczyc Algorytmy i język C++
Mnożenie macierzy
Na koniec wypiszemy wynik:
for(int i=0; i<3; j++)
{
for(int j=0; i<j; i++)
cout << AB[i][j] << " ";
cout << endl;
}
Tomasz Bielaczyc Algorytmy i język C++
Metoda Gaussa - Jordana
Metoda Gaussa - Jordana rozwiązywania układów równań (mających
tyle samo zmiennych, co równań) polega na wpisaniu wspólczynników
układu w macierz uzupełnioną, a następnie wykonywaniu operacji na
wierszach macierzy.
Tomasz Bielaczyc Algorytmy i język C++
Metoda Gaussa - Jordana
Napiszmy program rozwiązujący układ trzech równań z trzema
niewiadomymi
x +2y = 3
3x +6y + z = 5
4x +2z = 8
Najpierw musimy wpisać w tablicę macierz współczynników,
float A[3][4]={{1, 2, 0, 3},{3, 6, 1, 5},{4, 0, 2, 8}};
Tomasz Bielaczyc Algorytmy i język C++
Metoda Gaussa - Jordana
Pierwszy wiersz mnożymy przez stałą, aby na pierwszym miejscu uzyskać
jedynkę, nastepnie odejmujemy ten wiersz pomnożony przez odpowiednie
stałe od pozostałych wierszy, aby na tym miejscu dostać zera. W
następnym kroku drugi wiersz mnożymy przez stałą, aby na drugim
miejscu uzyskać jedynkę, nastepnie odejmujemy ten wiersz pomnożony
przez odpowiednie stałe od pozostałych wierszy, aby na tym miejscu
dostać zera. Podobnie postępujemy dla każdego następnego wiersza.
Tomasz Bielaczyc Algorytmy i język C++
Metoda Gaussa - Jordana
for(k=0; k<3; k++)
{
for(j=k; j<4; j++)
A[k][j] = A[k][j]/A[k][k];
for(i=0; i<3; i++)
if(i != k)
for(j=k; j<4; j++)
A[i][j] = A[i][j]-A[i][k]*A[k][j];
}
Tomasz Bielaczyc Algorytmy i język C++
Metoda Gaussa - Jordana
Jeśli na miejscu, na którym powinniśmy uzyskać jedynkę znajduje się zero
musimy zamienić dany wiersz z którymś z kolejnych, który w tym miejscu
nie ma zera - jeśli każdy z nich ma na tym miejscu zero, to układ nie ma
jednoznacznego rozwiązania. Jeśli układ ma jednoznaczne rozwiązanie, to
po zastosowaniu powyższych przekształceń do wszystkich wierszy
otrzymujemy macierz diagonalną jednostkową (+ kolumna rozwiązań).
Tomasz Bielaczyc Algorytmy i język C++
Metoda Gaussa - Jordana
if(A[k][k]==0)
{
brakrozw=1;
for(i=k+1; i<3; i++)
if(A[i][k]!=0)
{
for( j=0; j<4; j++)
swap(A[i][j],A[k][j]);
brakrozw=0;
}
}
Tomasz Bielaczyc Algorytmy i język C++
Metoda Gaussa - Jordana
Na koniec możemy wypisać rozwiązanie
for(int i=0; i<3; i++)
cout << "x(" << i << ")=" << A[i][3] << endl;
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program proszący o podanie rozmiarów macierzy (nie większych
niż 5×5), a następnie wypisujący podaną macierz oraz macierz
transponowaną.
(Aby utworzyć tablicę dwuwymiarową dowolnego zadanego za pomocą
zmiennych rozmiaru musielibyśmy napisać
cin>>n>>m;
float**A=new float*[n];
for( i=0; i<n; ++i)
A[i]=new float[m];
Ponieważ w zadaniu rozmiar tablicy jest ograniczony od góry, więc nie
musimy stosować tej procedury.)
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program sumujący dowolne dwie macierze o zadanym rozmiarze
mniejszym od 5×5.
ZadanieNapisz program mnożący dowolne dwie macierze o zadanych rozmiarach
mniejszych niż 6×6 lub stwierdzający, że jest to niemożliwe.
ZadanieNapisz program, który po wczytaniu współczynników rozwiązuje układ
czterech równań liniowych lub stwierdza, że rozwiązanie jest niemożliwe.
Tomasz Bielaczyc Algorytmy i język C++
Funkcje
Funkcja główna nie musi być jedyną funkcją w programie. Często
wygodnie jest zdefiniować pewną procedurę, a następnie wywoływać w
programie jej wykonanie. Przy pisaniu dłuższych programów może to
znacznie ułatwić pracę - program staje się czytelniejszy i każdą funkcję
możemy wywoływać w programie dowolną ilość razy z różnymi
argumentami.
Funkcje umieszczamy w nagłówku - muszą one znajdować się poza
funkcją główną programu.
Tomasz Bielaczyc Algorytmy i język C++
Funkcja void
Funkcja może nie zwracać żadnej wartości (funkcja typu void), tylko
wykonywać jakąś czynność, np. wypisywanie na ekran.
void pisz(int liczba) /*argumentem tej funkcji jest zmienna
liczba typu int (funkcja może
mieć jeden lub więcej argumentów)*/
{
cout << "Podana liczba to " << liczba << endl;
}
Po zadeklarowaniu zmiennej (np. int a=5;) naszą funkcję wywołamy
poleceniem pisz(a);
Tomasz Bielaczyc Algorytmy i język C++
Funkcja typu int
Częto używamy funkcji, które zwracają jakąś wartość. Przykładowo
funkcja
int wyznacznik(int x, int y, int z, int v)
{
return(x*v-y*z);
}
zwraca wyznacznik macierzy 2×2.
Tomasz Bielaczyc Algorytmy i język C++
Funkcja typu int
Teraz możemy w funkcji głównej wczytać dane i wypisać wyznacznik
macierzy;
int a11,a12,a21,a22;
cout << "Podaj dane \n";
cin >> a11 >> a12 >> a21 >> a22;
cout << wyznacznik(a11,a12,a21,a22);
Tomasz Bielaczyc Algorytmy i język C++
Funkcja - algorytm Euklidesa
Napiszmy funkcję liczącą największy wspólny dzielnik dwóch liczb.
int NWD(int x, int y){
int r;
while(y!=0){
r=x%y;
x=y;
y=r;
}
return(x);
}
Tomasz Bielaczyc Algorytmy i język C++
Funkcja - algorytm Euklidesa
Możemy użyć jej na przykład do skracania ułamków;
int d,a,b;
do{
cout << "Podaj licznik i mianownik.\n";
cin << a << b;
if(b!=0){
d = NWD(a,b);
cout << "Wynik=" << a/d << "/" << b/d << endl;
}
else
cout << "Błędne dane.\n";
}
while(b!=0)
Tomasz Bielaczyc Algorytmy i język C++
Zmienne lokalne
Zauważmy, że zmienną r użytą w funkcji NWD zadeklarowaliśmy
wewnątrz funkcji. Jest to zmienna lokalna, tzn. jest widoczna tylko
wewnątrz funkcji. Zmienne deklarowane w funkcji głównej programu
także nazywamy zmiennymi lokalnymi. Deklarowanie zmiennych poza
jakąkolwiek funkcją (zmienne globalne) jest stosowane, gdy chcemy
korzystać z tej zmiennej w różnych funkcjach programu (w innym
wypadku wygodniej jest używać zmiennych lokalnych).
(Pamięć zarezerwowana dla zmiennej globalnej jest czyszczona przed
uruchomieniem programu, zatem zmienna globalna ma po
zadeklarowaniu wartość zero, podczas, gdy zmienna lokalna r przed
przypisaniem jej wartości przyjmuje pewną losową wartość.)
Tomasz Bielaczyc Algorytmy i język C++
Metoda połowienia przedziału
Metoda połowienia przedziału służy do znajdowania dla danej funkcji
ciągłej miejsca zerowego w zadanym przedziale, o ile na jego brzegach
funkcja przyjmuje przeciwne wartości. Miejsce zerowe wyznaczane jest z
określoną dokładnością.
Tomasz Bielaczyc Algorytmy i język C++
Metoda połowienia przedziału
W nagłówku zdefiniujmy stałą wyznaczającą dokładność rozwiązania oraz
funkcję f określającą naszą funkcję matematyczną.
const double dokl = 0.001;
double f(double x)
{
return tan(x/100);
}
Tomasz Bielaczyc Algorytmy i język C++
Metoda połowienia przedziału
W funkcji głównej musimy wczytać wartości a oraz b i jeśli f(a) i f(b)
są przeciwnych znaków, to wybieramy tę połówkę przedziału, na brzegach
której wartości są przeciwne i powtarzamy tę procedurę, aż do zbliżenia
się wartości funkcji do zera z zadaną dokładnością.
do{
s = (a+b)/2;
if(f(a)*f(s) < 0)
b = s;
else
a = s;
}
while(fabs(f(s)) > dokl);//fabs oznacza wartość bezwzględną
Tomasz Bielaczyc Algorytmy i język C++
Metoda połowienia przedziału
Na koniec możemy wypisać wynik
cout << "Miejsce zerowe funkcji f to " << s << endl; //f(s)=0
Tomasz Bielaczyc Algorytmy i język C++
Metoda siecznych
Podobny efekt możemy otrzymać stosując metodę siecznych. Możemy
ją zastosować jeśli f jest funkcją ciągłą przyjmującą na brzegach
przedziału (a,b) przeciwne wartości oraz taką, że f ′(x) 6= 0.
Tomasz Bielaczyc Algorytmy i język C++
Metoda siecznych
Dla danych a,b punkt c definiujemy punkt przecięcia osi OX z sieczną
łączącą (a, f (a)) oraz (b, f (b)), czyli
c = b− f (b)b−a
f (b)− f (a).
Za a podstawiamy wartość b, a za b wartość c i powtarzamy procedurę.
Postępujemy tak dopóki |f (c)| jest większe od ustalonej stałej
wyznaczającej dokładność.
Tomasz Bielaczyc Algorytmy i język C++
Metoda siecznych
Przedstawiony powyżej algorytm zapisany w języku C wyglądać będzie
następująco
do
{
c = b-f(b)*(b-a)/(f(b)-f(a));
a = b;
b = c;
}
while(fabs(f(c)) > dokl);
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program wczytujący licznik i mianownik i następnie skracający
zadany w ten sposób ułamek do momentu, gdy wynik wyniesie 12 .
ZadanieNapisz program znajdujący metodą połowienia przedziału miejsce zerowe
dla funkcji f (x) = tg( x100 ) pomiędzy dowolnymi punktami z dokładnością
0.0001 i wypisujący przybliżone miejsce zerowe oraz wartość funkcji w
tym punkcie.
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program znajdujący metodą siecznych miejsce zerowe dla funkcji
f (x) = tg( x100 ) pomiędzy dowolnymi punktami z dokładnością
0.000000001 i wypisujący przybliżone miejsce zerowe. Porównaj ilość
kroków, w jakiej ten i poprzedni program znajdować będą miejsce zerowe.
Tomasz Bielaczyc Algorytmy i język C++
Rekurencja - ciąg Fibinacciego
Ważnym aspektem stosowania funkcji jest fakt, iż umożliwiają one
rekurencje - tzn. wywołanie samej siebie. Funkcja zwracająca dany wyraz
ciągu Fibonacciego wyglądać będzie tak
int fib(int n)
{
if(n<=2)
return(1);
else
return(fib(n-2)+fib(n-1));
}
Tomasz Bielaczyc Algorytmy i język C++
Ciąg Fibinacciego
Po zadeklarowaniu w programie zmiennej k i przypisaniu jej wartości k-ty
wyraz ciągu Fibonacciego wypiszemy na ekran poleceniem
cout << fib(k).
Do zdefiniowania funkcji i jej wywołania możemy użyć tych samych nazw
zmiennych lub różnych - w każdym przypadku zmienne te musimy
zadeklarować osobno wewnątrz funkcji i osobno w funkcji głównej
programu.
Tomasz Bielaczyc Algorytmy i język C++
Rekurencja - symbol Newtona
Wartość symbolu Newtona można policzyć ze wzoru(nk
)= n!
(n−k)!k! .
Można też skorzystać z własności(nk
)=(n−1k−1
)+(n−1
k
)i napisać funkcję
rekurencyjną,
int newton(int n, int k)
{
if(n==k || k==0)
return 1;
else
return newton(n-1,k-1)+newton(n-1,k);
}
Tomasz Bielaczyc Algorytmy i język C++
Symbol Newtona
Po podaniu n oraz k wypiszemy wynik.
cout << "(n po k)= " << newton(n,k) << endl;
Tomasz Bielaczyc Algorytmy i język C++
Funkcja Ackermana
Przykładem funkcji rekurencyjnej jest funkcja Ackermana. Można zapisać
ją wzorem
F (m,n) =
n+1 m = 0
F (m−1,1) m > 0,n = 0
F (m−1,F (m,n−1)) m,n > 0
.
Tomasz Bielaczyc Algorytmy i język C++
Funkcja Ackermana
Funkcję Ackermana zapiszemy wzorem rekurencyjnym
int acker(int m, int n)
{
if(m==0)
return(n+1);
else if(n==0)
return(acker(m-1,1));
else
return(acker(m-1,acker(m,n-1)));
}
a wywołamy
cout << "acker("<<m<<","<<n<<")=" << acker(m,n) << endl;
Tomasz Bielaczyc Algorytmy i język C++
Rekurencja - algorytm Euklisesa
Pseudokod procedury rekurencyjnej obliczającej największy wspólny
dzielnik dwóch liczb wygląda następująco
euklid(a,b)
1 if b=0
2 then return a
3 else return eukl(b, a mod b)
Tomasz Bielaczyc Algorytmy i język C++
Rekurencja - algorytm Euklisesa
W języku C++ procedura rekurencyjna obliczająca największy wspólny
dzielnik przyjmie postać:
int euklid(int a, int b)
{
if(b==0)
return a;
else
return euklid(b,a%b);
}
Tomasz Bielaczyc Algorytmy i język C++
Poprawność algorytmu Euklidesa
Zauważmy, że jest to wersja rekurencyjna algorytmu euklidesa
(Na każdym kroku za a podstawiane jest b, a za b podstawiane jest
a (mod b) dopóki b 6= 0).
Ponadto zauważmy, że NWD(a,b) dzieli NWD(b,a(mod)b) oraz
NWD(b,a(mod)b) dzieli NWD(a,b), co dowodzi, iż powyższa funkcja
rzeczywiście wyznacza największy wspólny dzielnik dwóch liczb.
Tomasz Bielaczyc Algorytmy i język C++
Sortowanie szybkie
Sortowanie szybkie polega na przeniesieniu na początek tablicy
elementów mniejszych od pierwszego elementu, a na koniec większych, a
następnie powtarzaniu tej czynności dla początkowej i końcowej części
tablicy. Rekursja kończy się, gdy kolejny fragment uzyskany z podziału
zawiera tylko jeden element.
Tomasz Bielaczyc Algorytmy i język C++
Sortowanie szybkie
void sortuj(int T[],int L,int P){ //T[] <-> *T
int i=L, j=P, v=T[L];
do{
while (T[i]<v) i++;
while (v<T[j]) j--;
if (i<=j){
swap(T[i], T[j]); i++; j--;
}
}
while (i<=j);
if (L<j) sortuj(T,L,j);
if (i<P) sortuj(T,i,P);
}
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program, który dla podanej liczby n wypisuje n pierwszych
wyrazów ciągu Fibonacciego.
ZadanieNapisz program liczący silnię za pomocą funkcji rekurencyjnej.
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz programy liczące dla zadanych n oraz k wartość
(nk
)wprost ze
wzoru oraz rekurencyjnie. Porównaj szybkość i zakres poprawnego
działania obu programów.
ZadanieNapisz program wczytujący długość ciągu oraz kolejne elementy ciągu, a
następnie porządkujący je zgodnie z algorytmem szybkiego sortowania.
Omów pesymistyczną i optymistyczną złożoność tego algorytmu.
Tomasz Bielaczyc Algorytmy i język C++
Wczytywanie po znaku, ASCII
Pisząc j=getc(stdin); przypisujemy zmiennej j wczytany z klawiatury
znak (o ile j jest zadeklarowane jako char) lub wartość w kodzie ASCII
tego znaku (o ile j jest zadeklarowane jako int).
Pamiętamy, że ASCII (American Standard Code for Information
Interchange) jest to kod przyporządkowujący liczby z zakresu 0-127
literom, cyfrom i innym znakom.
Tomasz Bielaczyc Algorytmy i język C++
ASCII, wczytywanie po znaku
Poniższy program pozwala na wczytanie ciągu znaków dowolnej długości,
a po naciśnięciu klawisza enter (wartość 10 w kodzie ASCII) wypisuje
ich wartości w kodzie ASCII.
int j;
do
{
j=getc(stdin); //wczytywane są kolejne znaki
cout<<j<<", "; //i wypisywana jest ich wartość
}
while(j!=10); //aż do naciśnięcia ENTER
Tomasz Bielaczyc Algorytmy i język C++
ASCII - reprezentacja liczb
Po wykonaniu powyższego programu możemy zauważyć, że chcąc
poprawnie zinterpretować znaki reprezentujące cyfry musimy od
reprezantacji znaku odjąć 48.
Tomasz Bielaczyc Algorytmy i język C++
ASCII
Napiszmy program, który wczytuje ciąg znaków, a następnie po kolei
wypisuje, czy dany znak jest liczbą czy literą.
int j;
do
{
j=getc(stdin);
if(j>47&&j<58)
cout<<"cyfra \n";
else if((j>64&&j<91)||(j>96&&j<123))
cout<<"litera\n";
else
cout<<"ani cyfra, ani litera\n";
}
while(j!=10);Tomasz Bielaczyc Algorytmy i język C++
ASCII - tablica znaków
Aby wczytać ciąg znaków i zapamiętać go w tablicy najpierw
zadeklarujemy tablicę i pomocnicze zmienne
char A[100];
int i=0;
Następnie wczytamy tablicę znaków
do
{
i++;
A[i]=getc(stdin);
}
while(A[i]!=10);
Tomasz Bielaczyc Algorytmy i język C++
ASCII - tablica znaków
Aby wypisać wczytany ciąg znaków w odwrotnej kolejności napiszemy
for(j=i-1; j>0; j--)
cout<<A[j];
cout<<endl;
Tomasz Bielaczyc Algorytmy i język C++
System dwójkowy
Napiszmy program przeliczający podaną liczbę z systemu dwójkowego do
dziesiętnego. Najpierw deklarujemy zmienne i wczytujemy ciąg znaków
(złożony z zer i jedynek).
int A[31];
int i=0, r=0, k;
cout<<"Podaj liczbę w systemie dwójkowym.\n";
do
{
i++;
A[i]=getc(stdin)-48;
}
while(A[i]!=-38);
Tomasz Bielaczyc Algorytmy i język C++
System dwójkowy
Następnie obliczamy sumę odpowiednich potęg dwójki pomnożonych
przez odpowiednie współczynniki.
i--;
for(k=i; k>0 ; k--)
r+=(A[k]*pow(2,i-k));
cout<<r<<endl;
Tomasz Bielaczyc Algorytmy i język C++
Duże liczby
Napiszmy teraz program sumujący dwie dowolnie duże liczby
(wychodzące poza zakres int-a). Na początek wczytamy dwie liczby jako
tablice cyfr.
int A[100], B[100], i=0, j=0, r=0, k;
do
{
i++;
A[i]=getc(stdin)-48;
}
while(A[i]!=-38);
Tomasz Bielaczyc Algorytmy i język C++
Duże liczby
i podobnie
do
{
j++;
B[j]=getc(stdin)-48;
}
while(B[j]!=-38);
Załóżmy najpierw, że obie wczytane liczby są tej samej długości.
Tomasz Bielaczyc Algorytmy i język C++
Dodawanie pisemne
Ich sumę policzymy stosując schemat dodawania pisemnego.
A[0]=0; B[0]=0;
j--;
for(k=j; k>=0 ; k--)
{
B[k]=B[k]+A[k]+r;
if(B[k]>9)
{
r=1;
B[k]=B[k]-10;
}
else
r=0;
}Tomasz Bielaczyc Algorytmy i język C++
Dodawanie pisemne
Na koniec możemy wypisać wynik.
if(B[0]!=0)
cout<<B[0];
for(k=1; k<=j; k++)
cout<<B[k];
Tomasz Bielaczyc Algorytmy i język C++
Dodawanie pisemne
W przypadku, gdy wczytane liczby nie będą tej samej długości możemy
“przesunąć” mniejszą liczbę (tak aby była tej samej długości, co większa)
a na początkowych miejscach umieścić zera.
Powiedzmy, że pierwsza liczba jest mniejsza.
for(k=j-1; k>j-i; k--)
A[k]=A[k-j+i];
for(k=j-i; k>0; k--)
A[k]=0;
Tomasz Bielaczyc Algorytmy i język C++
Podzielność
Mając wczytaną liczbę w tablicy a[i] możemy sprawdzić jej podzielność
przez 3:
s=0;
for(k=0; k<i ; k++)
s+=A[k]
if(s%3==0)
cout<<"Wczytana liczba jest podzielna przez 3.\n";
else
cout<<"Wczytana liczba nie jest podzielna przez 3.\n";
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program wczytujący ciąg znaków oraz sprawdzający, czy najwięcej
wczytano dużych liter, małych liter, czy innych znaków.
ZadanieNapisz program wczytujący ciąg znaków oraz liczący sumę cyfr, które się
wśród tych znaków znalazły.
ZadanieNapisz program wczytujący dwie liczby jako ciągi znaków, a następnie
sprawdzający która z nich jest większa.
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz program wczytujący trzy liczby jako ciągi znaków, a następnie
dodający je pisemnie.
ZadanieNapisz program wczytujący dwie liczby - jedną jako ciąg znaków, drugą
typu int i mnożący je.
ZadanieNapisz program wczytujący liczbę jako ciąg znaków, a następnie
sprawdzający, czy jest ona podzielna przez 11.
Tomasz Bielaczyc Algorytmy i język C++
Wskaźniki
Wskaźnik nie przechowuje wartości zmiennej ale, podobnie jak tablica,
wskazuje miejsce w pamięci, w którym znajduje się zmienna danego typu.
W poniższym przykładzie symbol * pomiędzy int, a wskaz oznacza, że
wskaz jest wskaźnikiem do zmiennej typu int (a nie zmienną typu int).
int *wsk; //deklaracja wskaźnika
wsk=new int; //przydzielenie zmiennej miejsce w pamięci
*wsk=5; //zapisanie liczby 5 w tym miejscu pamięci
cout << *wsk << endl;
delete wsk; //zwolnienie pamięci wskazywanej przez wskaźnik
Tomasz Bielaczyc Algorytmy i język C++
Wskaźniki
Polecenie delete zwalnia miejsce w pamięci, w którym przechowywana
jest nasza zmienna - pamięć nie będzie zatem zajmowana przez cały czas
wykonywania programu, co ma miejsce przy normalnym deklarowaniu
zmiennych.
Tomasz Bielaczyc Algorytmy i język C++
Wskaźniki
int* T;
int n, i;
cout << "Podaj rozmiar tablicy. \n";
cin >> n;
T = new int[n];
cout << "Podaj elementy tablicy \n";
for (i=0; i<n; i++)
cin>>T[i];
cout << "Zawartosc tablicy: \n";
for (i=0; i<n; i++)
cout << T[i] << ", ";
delete [] T;
Tomasz Bielaczyc Algorytmy i język C++
Aliasy
Operator & adresu (referencji) występuje przy deklaracji zmiennej zwanej
referencją. W poniższym przykładzie symbol & pomiędzy int, a alias
oznacza, że zmienna alias jest typu referencyjnego i podszywa się pod
zmienną x typu int.
int x = 15;
int & alias = x;
cout << alias;
Tomasz Bielaczyc Algorytmy i język C++
Wskaźniki
Zamiast operatora * wyłuskania (dereferencji) w poniższym przypadku
int x=35;
int * wsk=&x;
*wsk = 45;
cout << x;
wygodniej użyć operatora referencji
int x=35;
int& alias=x;
alias = 45;
cout << x;
Tomasz Bielaczyc Algorytmy i język C++
Wskaźniki
Funkcja skracająca ułamek postaci
int skrac0(int a, int b)
{
int d=NWD(a,b);
a=a/d; b=b/d;
}
nie będzie działać, gdyż wartości wyliczone wewnątrz funkcji nie są
widoczne na zewnątrz.
Tomasz Bielaczyc Algorytmy i język C++
Wskaźniki
Nie możemy też użyć polecenia return w funkcji, gdyż funkcja ma
powinna zwracać licznik i mianownik skróconego ułamka. Ponieważ
polecenie return może zwracać tylko jedną wartość (pozostałe wartości
wyliczone wewnątrz funkcji nie są widoczne na zewnątrz), więc nie
osiągniemy tego standardową procedurą. Możemy jednak napisać funkcję
używając wskaźników, która zmienia miejsce w pamięci.
Tomasz Bielaczyc Algorytmy i język C++
Wskaźniki
Funkcję skracającą ułamek możemy napisać używając wskaźników.
void skrac1(int *a, int *b)
{
int d=NWD(*a,*b);
*a=*a/d; *b=*b/d;
}
Funkcję taką wywołamy poleceniem skrac1(&licz, &mian). Wynik
wypiszemy poleceniem cout << licz << "/" << mian << endl;
Tomasz Bielaczyc Algorytmy i język C++
Tablice a wskaźniki
Zauważmy, że funkcja sortowania szybkiego nie zawiera polecenia
zwrócenia wartości return, a jednak zmienia wartości w tablicy. Wynika
to stąd, że nazwa tablicy jest wskaźnikiem stałym, a nie nazwą zmiennej.
Tomasz Bielaczyc Algorytmy i język C++
Referencje
Do skracania ułamków możemy użyć także referencji
void skrac2(int &a, int &b)
{
int d=NWD(a,b);
a=a/d; b=b/d;
}
W tym przypadku funkcję wywołujemy poleceniem
skrac2(licz, mian).
Tomasz Bielaczyc Algorytmy i język C++
Struktury
Poleceniem struct możemy stworzyć strukturę złożoną ze zmiennych.
Stwórzmy strukturę o nazwie autor.
struct autor{
string imie, nazwisko, tytul; //deklarujemy zmienne
int rok; //czyli pola struktury
};
Tomasz Bielaczyc Algorytmy i język C++
Struktury
Możemy teraz zadeklarować zmienne typu autor oraz nadać im cechy.
autor os1, os2;
os1.imie = "Thomas";
os1.nazwisko = "Cormen";
os1.tytul = "Wprowadzenie do algorytmow";
os1.rok = 1997;
cin >> os2.imie >> os2.nazwisko >> os2.tytul >> os2.rok;
Tomasz Bielaczyc Algorytmy i język C++
Struktury
Zmiennym os1, os2 odpowiadają dane wpisanych osób. Możemy
wybrane z nich wypisać pisząc
cout << "Pierwszy autor nosi nazwisko " << os1.nazwisko << endl;
cout << "Drugi autor nosi imię " << os2.imie << endl;
Tomasz Bielaczyc Algorytmy i język C++
Struktury
Tworząc strukturę możemy dodać do niej funkcje - taką strukturę
nazywamy klasą.
struct autor{
string imie, nazwisko, tytul; //deklarujemy zmienne
int rok; //czyli pola klasy
void napisz();
}; //określamy funkcję
void autor::napisz() //czyli metodę klasy
{
cout << "Autorem " << tytul << " jest " << nazwisko << endl;
}
Tomasz Bielaczyc Algorytmy i język C++
Struktury
Teraz po zdefiniowaniu zmiennych os1 i os2 wypisywanie danych może
wyglądać następująco
os1.napisz();
os2.napisz();
Tomasz Bielaczyc Algorytmy i język C++
Struktury
Jeśli stworzymy strukturę o nazwie para
struct para {int licznik; int mianownik;};
będziemy mogli za jej pomocą napisać funkcję skracającą ułamki.
para skrac3(int a, int b){
int d=NWD(a,b);
para p; //deklaracja zmiennej p typu para
p.licznik = a/d;
p.mianownik = b/d;
return p;
}
Tomasz Bielaczyc Algorytmy i język C++
Struktury
Jest to funkcja typu para. Aby skrócić ułamek xy napiszemy
para p = skrac3(x, y);
cout << p.licznik << ’/’ << p.mianownik << endl;
Tomasz Bielaczyc Algorytmy i język C++
Rozszerzony algorytm Euklidesa
Za pomocą rozszerzonego algorytmu Euklidesa możemy dla danych
liczb całkowitych a,b znaleźć współczynniki całkowite x ,y tak, aby
NWD(a,b) = ax +by . W szczególności jeśli a i b są względnie pierwsze
otrzymujemy ax +by = 1.
(Oznacza to, że jeśli NWD(a,n) = 1, to ax = 1(modn), czyli x jest
multiplikatywną odwrotnością a modulo n.)
Tomasz Bielaczyc Algorytmy i język C++
Rozszerzony algorytm Euklidesa
Algorytm zapisany w pseudokodzie wygląda następująco
ext_eukl(a,b)
1 if b=0
2 then return (a,1,0)
3 else
4 (d’,x’,y’) <- ext_eukl(b,a mod b)
5 (d,x,y) <- (d’,y’,x’-[a/b]y’)
6 return (d,x,y)
Zauważmy, że
bx ′+a(mod b)y ′ = bx ′+ay ′−b[a/b]y ′ = ay ′+b(x ′− [a/b]y ′) = ax +by ,
czyli algorytm daje prawidłowy wynik.
Tomasz Bielaczyc Algorytmy i język C++
Rozszerzony algorytm Euklidesa
Aby zaimplementować go w języku C++ stworzymy strukturę złożoną z
trzech liczb całkowitych
struct Trojka
{
int d;
int x;
int y;
};
a następnie napiszemy funkcję rekurencyjną
Tomasz Bielaczyc Algorytmy i język C++
Rozszerzony algorytm Euklidesa
Trojka ext_eukl(int a, int b){
Trojka t;
if(b==0){
t.d = a; t.x = 1; t.y = 0;
}
else{
t=ext_eukl(b, a%b);
int tymczas=t.x;
t.x = t.y;
t.y = tymczas-(a/b)*t.y;
}
return t; }
Tomasz Bielaczyc Algorytmy i język C++
Rozszerzony algorytm Euklidesa
Po wczytaniu liczb a,b możemy wywołać funkcję i wypisać wynik na
ekran
Trojka rozw = ext_eukl(a, b);
cout <<"x="<<rozw.x<<", y="<<rozw.y<<", d="<<rozw.d<<endl;
Tomasz Bielaczyc Algorytmy i język C++
Zadania
ZadanieNapisz funkcję sumującą dowolne dwa ułamki zadane w postaci zwykłej.
ZadanieNapisz bazę danych, w której poszczególnym przedmiotom przypisane są
nazwa, czas trwania w semestrach, informacja, czy przedmiot kończy się
egzaminem oraz ocena.
ZadanieNapisz program, który dla wczytanych liczb całkowitych a,n znajduje
multiplikatywną odwrotność a modulo n o ile ta istnieje.
Tomasz Bielaczyc Algorytmy i język C++