172
Algorytmy i język C++ Tomasz Bielaczyc Tomasz Bielaczyc Algorytmy i język C++

Algorytmy i jezyk C++

Embed Size (px)

Citation preview

Algorytmy i język C++

Tomasz Bielaczyc

Tomasz Bielaczyc Algorytmy i język C++

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++