Sunteți pe pagina 1din 225

Executarea unui program in mod simplu se face cu combinatia de taste CTRL si F5

CONSTRUCTIA PROGRAMELOR IN Visual C++.Net


1)Intru in Visual studio.net
2)File/new project
3)Visual C++ si aleg Win32 console project
4)dau numele proiectului
Ca mai jos
Apasam pe iconul Object browser
Dubluc click pe
Apas PE
OBJECT
5) BROWSER

APAS PE
ACEASTA
OPTIUNE
SCRIU PROGRAMUL SI O SA–
L RULEZ cu CTRL si F5

Il rulez
apasand
dublu clic
asa am vazut executia

INTRARE/IESIERE VISUAL c++.NET


Operaţii de intrare/ieşire în C++

C++ defineşte propriul său sistem de intrare/ieşire orientat pe obiecte. Ca şi sistemul


de I/E din C, cel din C++ este complet integrat. Aceasta înseamnă că diferitele aspecte ale
intrărilor sau ieşirilor din C++, cum ar fi operaţiile cu consola sau cu discul, sînt doar
perspective diferite ale aceluiaşi mecanism.
Sistemul de I/E din C este foarte bogat, flexibil şi puternic. Întrebarea care se pune pe
bună dreptate este de ce este necesară introducerea unui mecanism nou în C++. Răspunsul este
acela că sistemul de I/E din C nu cunoaşte obiectele, iar pentru a asigura un suprot complet
pentru programarea orientată pe obiecte, a fost necesară crearea unui sistem astfel orientat.
Acesta trebuie să poată opera cu obiectele create de utilizator. Mai există însă şi alte avantaje
ale utilizării sistemului de I/E definit în C++, care pot ieşi în evidenţă chiar în aplicaţii care nu
sînt scrise orientate pe obiecte.
Stream-uri în C++

Ca şi sistemul de I/E dinj C, cel din C++ operează pe fluxuri de informaţie - stream-
uri. Un stream este o entitate logică care produce sau primeşte informaţie. Un stream este legat
de un echipament fizic prin intermediul sistemului de I/E din C++. Toate stream-urile se
comportă la fel, chiar dacă echipamentele fizice la care sînt conectate efectiv pot să fie foarte
diferite. Aceleaşi funcţii de I/E pot opera, teoretic, asupra oricărui tip de echipament fizic. De
exemplu, aceeaşi funcţie care scrie într-un fişier poate fi folosită şi pentru a scrie la imprimantă
sau pe ecran. Avantajul acestei abordări este că interfaţa este astfel standardizată, unificată şi
deci trebuie cunoscută doar această modalitate universală de acces.

Ierarhia de clase pentru stream-uri

C++ asigură suportul pentru sistemul său de I/E în fişierul antet IOSTREAM.H. Aici
sînt definite două ierarhii de clase care admit operaţii de I/E. Clasa cu nivelul cel mai scăzut se
numeşte streambuf şi asigură operaţiile de bază de intrare şi de ieşire. Această clasă nu va fi
folosită direct decît dacă se doreşte derivarea propriilor clase de I/E. A doua ierarhie porneşte
cu clasa ios, care acceptă I/E formatate. Ierarhia completă este prezentată în fig. 8.1. Din
ierarhie fac parte clasele istream, ostream şi iostream Aceste clase sînt folosite pentru a crea
stream-uri capabile să introducă, să obţină şi respectiv să facă ambele operaţii. Dar se observă
că din ios mai sînt derivate multe alte clase pentru utilizarea fişierelor de pe disc şi formatarea
în memorie. Clasa ios conţine şi ea multe funcţii şi variabile membre care controlează sau
urmăresc operaţiile fundamentale asociate stream-ului. Dacă sistemul de I/E din C++ este
folosit în manieră normală, membrii clasei ios vor fi capabili să lucreze cu orice stream.

Clasa streambuf oferă o zonă de memorie tampon (buffer) şi metodele de lucru


asociate pentru operaţii cu caracter general, cu formatare minimă (sau fără formatare). Din
streambuf sînt derivate clasele :

- filebuf, specializată pe operaţii cu fişiere


- strstreambuf, pentru operaţii de formatare a datelor în memorie (similare celor
efectuate de sscanf() şi sprintf() din C)
Fig.. Clasele de intrare/ieşire din C++

Obiecte aparţinînd celor trei clase sînt utilizate de a doua ierarhie, avînd ca bază clasa
ios.
Clasa ios conţine adresa unui obiect streambuf, variabila de stare (care conţine
erorile înregistrate la ultimul transfer), variabile de control al formatării datelor şi un set de
funcţii. Acestea permit efectuarea aunor operaţii de intrare/ieşire de bază, cu sau fără formatare
şi control al erorilor folosind un obiect streambuf. Clasa ios este baza unei ierarhii mai
complexe, în care se foloseşte şi moştenirea multiplă. Toate clasele derivate sînt capabile de
operaţii cu sau fără formatare şi control al erorilor, datorită calităţilor moştenite de la ios, dar
sînt dedicate unor tipuri de operaţii diferite.
Se disting 3 direcţii de specializare, cărora le corespund următoarele categorii de clase :

1. Operaţii cu caracter general, folosind un streambuf :


- clasa istream, derivată din ios, pentru transferuri de la un obiect streambuf.
Obiectele
clasei reprezintă dispozitive de intrare.
- clasa ostream, derivată din ios, pentru transferuri către un obiect streambuf
(dispozitive de ieşire).
- clasa iostream, derivată din istream şi ostream pentru operaţii bidirecţionale
(dispozitive de intrare/ieşire).

2. Operaţiuni cu fişiere, utilizînd un filebuf :


- clasa fstreambase este derivată din ios şi constituie un nivel intermediar, care are
rolul de a adăuga aspectele specifice operaţiilor cu fişiere disc. Din fstreambase şi
clasele din categoria precedentă sînt derivate următoarele clase.
- clasa ifstream, derivată din istream şi fstreambase, pentru operaţii de intrare.
- clasa ofstream, derivată din ostream şi fstreambase, pentru operaţii de ieşire.
clasa fstream, derivată din iostream şi fstreambase, pentru operaţii de
intrare/ieşire.

3. Operaţii de formatare în memorie, folosind un obiect strstreambuf :


- clasa strstreambase este derivată din ios şi reprezintă nivelul intermediar, care
adaugă aspectele specifice fomării în memorie. Din strstreambase şi clasele din
categoria 1 sînt derivate dublu următoarele clase.
- clasa istrstream este derivată din istream şi strstreambase, pentru operaţii de citire.
- clasa ostrstream, derivată din ostream şi strstreambase, pentru operaţii de scriere.
- clasa strstream, derivată din iostream şi strstreambase, pentru operaţii de
citire/scriere.

Un stream C++ este deci un obiect aparţinînd uneia din clasele din cele 3 categorii
enumerate mai sus.

Stream-uri predefinite în C++

Cînd îşi începe execuţia un program scris în C++, se deschid automat patru stream-uri
încorporate. Acestea sînt :

Stream Semnificaţie Clasa din care face Dispozitiv Echivalent în C


parte implicit
cin intrare standard istream_withassign tastatură stdin
cout ieşire standard ostream_withassign ecran stdout
cerr ieşire standard pentru ostream_withassign ecran stderr
eroare (fără memorare)
clog versiune cu memorie ostream_withassign ecran fără echivalent
tampon pentru cerr

Implicit, stream-urile standard sînt folosite pentru a comunica cu consola. Însă, în


mediile care admit redirecţionarea I/E (DOS, Unix, Windows, OS/2), stream-urile standard pot
fi redirecţionate spre alte echipamente sau fişiere.
Standardul ANSI C++ mai defineşte patru stream-uri : win, wout, werr şi wlog, care
sînt folosite pentru seturile lărgite de caractere necesare anumitor limbi.

Clasele istream, ostream şi iostream

Clasele istream şi ostream (şi implicit toate derivatele lor, inclusiv iostream) dispun
de seturi de funcţii de intrare/ieşire şi supradefinesc cei doi operatori de deplasare (shift) pentru
a efectua transferul de informaţie cu un stream şi formatarea pentru tipurile de bază :
 operatorul << pentru operaţii de ieşire
 operatorul >> pentru operaţii de intrare

a. Clasa ostream
În clasa ostream, operatorul << este supradefinit sub forma :
ostream& operator <<(tip_de_baza);
şi se mai numeşte şi operator de inserare (într-un stream). Operatorul admite ca operanzi o
expresie de un tip fundamental oarecare şi (implicit) adresa obiectului din clasa ostream
specificat la apelare (un dispozitiv de ieşire). Rolul său este de a transfera valoarea expresiei, cu
un format adecvat, către acel stream. În plus, întoarce ca rezultat adresa dispozitivului pentru a
permite operaţii de ieşire multiple, înlănţuite. Exemplu (cunoscut de altfel din capitolele
precedente) :

float r=4.4, i=6.74;


cout <<”Numar complex, re = ”<< r <<”, im = ” << i << “\n”;

O secvenţă prea lungă se poate continua pe rîndul următor, ca în exemplul de mai jos
(o reluare a exemplului anterior):

cout <<”Numar complex, re = ”<< r


<<”, im = ” << i << “\n”;

Aşa cum ne aşteptăm, secvenţa va determina afişarea textului :

Numar complex, re = 5.5, im = 6.74

Operatorul este supradefinit astfel încît să admită toate tipurile fundamentale şi este
prevăzut pentru fiecare un format implicit (de aceea nu este obligatorie specificarea unui
format). Pentru tipurile pointer se afişează adresa completă în hexazecimal, cu segment şi
deplasament. În particular, pentru tipul (char*) se afişează şirul de caractere şi nu adresa. Pentru
afişarea adresei pentru acest tip de pointer se face o conversie explicită la tipul (void*). Mai jos
e prezentat un exemplu simplu pentru aceasta :

char str[]=”Exemplificare”;
int i, *p=&i;

cout << str << “\n”;


cout << (void*)str << “\n”;
cout << &i << “=” << p;

Se va afişa :

Exemplificare
0x8f55ffe6
0x8f55fff0=0x8f55fff0

Clasa dispune de o serie de funcţii membre, care asigură transferul informaţiei fără
formatare şi operaţii de poziţionare :

ostream& put(char c) - transferă caracterul c către dispozitivul apelant


Exemplu :
char c;
cout.put( c ); // echivalent cu cout << c;
ostream& write(const char *tab, int n) - transferă blocul de octeţi tab, de lungime n, fără nici
o modificare, către dispozitivul apelant
Exemplu :
char text[]=”Mesaj”;
cout.write(text, strlen(text));

ostream& seekp(long n) - efectuează poziţionarea absolută în stream, pe octetul n


(numerotarea se face de la zero).

ostream& seekp(long n, seek_dir ref) - poziţionare relativă în stream, cu referinţa la tipul


enumerare seek_dir, declarat împreună cu ios (funcţie supradefinită). Valorile din
enumerare sînt {beg, cur, end} şi semnifică începutul, poziţia curentă şi sfîrşitul
stream-
ului.

long tellp() - întoarce poziţia absolută în stream

ostream& flush() - goleşte tamponul, transferînd datele către dispozitivul fizic asociat.

b. Clasa istream

În clasa istream operatorul >> este supradefinit sub forma :

istream & operator >>(&tip_de_baza);

şi se mai numeşte operator de extragere (dintr-un stream).


Operatorul primeşte ca argumente adresa unei variabile de un tip fundamental oarecare
(în afară de tipul pointer) şi adresa unui obiect din clasa istream (implicit). Citeşte din
dispozitivul de intrare o valoare pe care o înscrie în variabilă, după efectuarea operaţiei de
conversie la reprezentarea internă a datelor. Pentru operanzi de tip (char*) se citeşte şi
memorează un şir de caractere, iar celelalte tipuri pointer nu sînt admise.
Deoarece întoarce adresa dispozitivului, poate fi utilizat pentru operaţii de intrare
multiple, de exemplu :

cin >> x >> y;

Ca delimitatori ai valorilor citite se utilizează “spaţiile albe”, adică oricare dintre


caracterele blanc, tab orizontal (\t), tab vertical (\v), linie nouă (\n), retur (\r), pagină nouă (\f).
Delimitarea se aplică şi pentru şirurile de caractere şi din acest motiv şirurile care conţin spaţii
albe nu vor fi citite corect.
O serie de funcţii disponibile pentru această clasă asigură transferuri fără formatare şi
operaţii de poziţionare :

istream& get(char &) - extrage din dispozitivul de intrare un caracter (inclusiv spaţii
albe) şi îl
înscrie în variabila de tip char primită ca parametru
Exemplu :

// copiaza cin la cout


while(cin.get( c)) cout.put( c);
Funcţia este supradefinită de două ori, prin versiunile :

int get() - citeşte din stream şi întoarce ca rezultat un caracter (EOF la sfîrşitul
fişierului).

Exemplu :

while(c=cin(get)!=EOF) cout.put( c); // echivalent cu exemplul


// precedent

istream& get(char *str, int n, char delim=”\n”); - citeşte caractere din stream
în şirul
str pînă la întîlnirea delimitatorului specificat (implicit linie nouă) sau pînă la
completarea a (n-1) caractere sau pînă la sfîrşit de fişier. Delimitatorul poate
fi
orice valoare char şi nu este extras din stream. Şirul str este completat cu
terminatorul “\0”

istream& getline(char *str, int n, char delim=”\n”); - este similară cu funcţia precedentă
get() dar extrage şi delimitatorul fără a-l înscrie însă în şirul str. Funcţia substituie cu
succes operatorul de extragere >> pentru şiruri de caractere care includ spaţii albe. În
particular, valoarea implicită “\n” este adecvată citirii unei linii de text.

istream& read(char* tab, int n); - citeşte n octeţi din stream în tabloul tab. Spre deosebire
de
funcţiile precedente, nici un caracter de delimitare nu întrerupe citirea (nu se face nici o
interpretare a şirului de octeţi citit).

int gcount(); - întoarce numărul de caractere citite la ultima operaţie.

int peek(); - întoarce caracterul următor fără să-l extragă din stream.

istream& putback(char); - reinserează un caracter în stream.

Funcţiile
long tellg();
ostream& seekg(long n);
ostream& seekg(long n, seek_dir);

sînt similare cu tellp() şi seekp(), membre ale clasei ostream.

// Sa se scrie un mesaj pe o linie


#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
cout << "Hello World!\n";
return 0;
}
// sa se scrie trei fraze pe verticala.

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
cout << "I am Blaxxon," << endl;
cout << "the godlike computer." << endl;
cout << "Fear me!" << endl;

return 0;
}
// sa se scrie trei fraze pe orizontala.

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
cout << "I am Blaxxon, ";
cout << "the godlike computer. ";
cout << "Fear me!" << endl;

return 0;
}
// sa se scrie trei fraze pe verticala cu distanta de un rand intre
ele.

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
cout << "I am Blaxxon," << endl << endl;
cout << "the godlike computer." << endl << endl;
cout << "Fear me!" << endl;

return 0;
}
// sa se scrie transformarea din grade Celsius in grade Fahrenheit

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
double ctemp, ftemp;

cout << "Input a Celsius temp and press ENTER: ";


cin >> ctemp;
ftemp = (ctemp * 1.8) + 32;
cout << "Fahrenheit temp is: " << ftemp;

return 0;
}

// Sa se scrie evaluarea unei expresii pe coloane cu operatorul


//CAST (fortez tipul rezultatului)
#include "stdafx.h"
#include<iostream>
using namespace std;

int main()
{
cout << "Hello there.\n";
cout << "Here is 5: " << 5 << "\n";
cout << "The manipulator ." << endl;

cout << "Here is a very big number:\t" << 70000 << endl;
cout << "Here is the sum of 8 and 5:\t" << 8+5 << endl;
cout << "Here's a fraction:\t\t" << (float) 5/8 << endl;
cout << "And a very very big number:\t" << (double) 7000 *
7000 <<endl;

cout << "Don't forget to replace Jesse Liberty with your


name...\n";
cout << "Jesse Liberty is a C++ programmer!\n";
return 0;
}
// sa se scrie transformarea din grade Celsius in grade Fahrenheit
//evaluarea facandu-se direct cu formula

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {

// Declare ctemp as a floating-pt variable.

double ctemp;

// Prompt and input value of ctemp (Celsius Temp).

cout << "Input a Celsius temp and press ENTER: ";


cin >> ctemp;

// Convert ctemp and output results.

cout << "Fahrenheit temp is: " << (ctemp * 1.8) + 32;

return 0;
}
// sa se scrie transformarea din grade Celsius in grade Fahrenheit
//evaluarea facandu-se direct cu formula

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {

// Declare n as a floating-pt variable.

double n;

// Prompt and input value of n.


cout << "Input a number and press ENTER: ";
cin >> n;

// Calculate and output the square.

cout << "The square is: " << n * n;

return 0;
}
// sa se scrie transformarea din grade Fahrenheit in grade Celsius

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
double ctemp, ftemp;

cout << "Input a Fahrenheit temp and press ENTER: ";


cin >> ftemp;
ctemp = (ftemp - 32) / 1.8;
cout << "Celsius temp is: " << ctemp;

return 0;
}
// sa se scrie transformarea din grade Fahrenheit in grade Celsius
//direct ca expresie

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
double ftemp;

cout << "Input a Fahrenheit temp and press ENTER: ";


cin >> ftemp;
cout << "Celsius temp is: " << (ftemp - 32) / 1.8;

return 0;
}
// sa se scrie n la puterea 3

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {

// Declare n as a floating-pt variable.

double n;

// Prompt and input value of n.

cout << "Input a number and press ENTER: ";


cin >> n;

// Calculate and output the square.


cout << "The cube is: " << n * n * n;

return 0;
}

//sa se scrie pe doua linii un mesaj si sa se dea exemplu de folosire


//a comentariilor
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
/* this is a comment
and it extends until the closing
star-slash comment mark */
cout << "Hello World!\n";
// this comment ends at the end of the line
cout << "That comment ended!\n";

// double slash comments can be alone on a line


/* as can slash-star comments */
return 0;
}
//sa se demonstreze nr de octeti ocupat de tipurile de date
cunoscute
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
cout << "The size of an int is:\t\t" << sizeof(int) << "
bytes.\n";
cout << "The size of a short int is:\t" << sizeof(short) << "
bytes.\n";
cout << "The size of a long int is:\t" << sizeof(long) << "
bytes.\n";
cout << "The size of a char is:\t\t" << sizeof(char) << "
bytes.\n";
cout << "The size of a float is:\t\t" << sizeof(float) << "
bytes.\n";
cout << "The size of a double is:\t" << sizeof(double) << "
bytes.\n";

return 0;
}

//sa se initializeze doua variabile in forma diferite


#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
unsigned short int Width = 5, Length;
Length = 10;

// create an unsigned short and initialize with result


// of multiplying Width by Length
unsigned short int Area = Width * Length;
cout << "Width:" << Width << "\n";
cout << "Length: " << Length << endl;
cout << "Area: " << Area << endl;
return 0;
}
TIPURI DE DATE ,OPERATORI,INSTRUCTIUNI
DECIZIONALE

TIPURI INTREGI

Tipurile intregi sunt:


 unsigned char→caracter fara semn, ocupa 8 biti si ia valori intre 0 si 255;
 char→caracter, ocupa 8 biti si ia valori intre -128 si 127;
 unsigned int→intreg fara semn,ocupa 16 biti si ia valori intre 0 si 65535;
 short int→intreg scurt, ocupa 16 biti si ia valori intre -32768 si 32767;
 int→intreg, ocupa de regula 16 biti si ia valori intre -32768 si 32767;
 unsigned long→intreg lung fara semn, ocupa 32 de biti si ia valori intre 0 si
4.294.967.295;
 long→intreg lung cu semn, ocupa 32 de biti si ia valori intre -2.147.483.648 si
2.147.483.647.
Variabilele de tip intreg folosesc pentru memorarea datelor codul
complementar.Caracterele se memoreaza prin codul ASCII.

TIPURI REALE

Variabilele de tip real retin numere cu zecimale.Tipurile reale sunt:



float→ocupa 32 de biti si ia valori intre 3.4x10-38 si 3.4x1038;

double→ocupa 64 de biti si ia valori intre 1.7x10-308 si 1.7x10308;

long double→ocupa 80 de biti si ia valori intre 3.4x10-4932 si 1.1x104932.
pentru memorare datelor se foloseste reprezentarea in virgula mobila.
Operatorii aritmetici:

+ adunare, - scadere, * produs, / impartire, % - restul impartirii intregi

++, -- incrementare si decrementare
Operatori relationali:

<,>

= = egal

                   <= mai mic sau egal

                          >= mai mare sau egal

                           != diferit
Operatori logici:

&& - si logic

|| -sau logic

! - negatie logica
Instructiunea IF

if (expresie) instructiune1 ;
else
instructiune2;
// sa se implemeteze un program care determina media aritmetica a
trei numere
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
void main(void)
{
int a,b,c;
float s;
cin>>a;
cin>>b;
c=a/2+b/2;
s=(a+b+c)/3;
cout<<"Media aritmetica este="<<s;

Obs: Cand apar expresii de tipul :


++variabila
sau
--variabila;
spunem ca se realizeaza o preincrementare, respectiv predecrementare. In cazul preincrementarii, variabila
va primi ca valoare 1+valoarea initiala. Daca preincrementarea apare intr-o expresie se realizeaza intai
aceasta operatie si abia apoi celelalte operatii care mai apar in expresie (preincrementarea are prioritate
mai mare).La fel la predecrementare.La postincrementare intai se face oparatia cu variavila nemarita,apoi
dupa efectuarea expresiei se marestre variabila cu 1.La fel la postdecrementare.
}
// sa se implemeteze un program care determina
//functionarea operatorilor de incrementare.post
incrementare,decrementare
//postdecerementare
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

void main(void)
{
int a,b,i=3;
a=++i; //preincrementare a lui i
cout<<a;
b=a--; //postdecrementare
cout<<"a="<<a<<"\n";
cout<<"b="<<b<<"\n";
a+=++b; //atribuire compusa
cout<<"a="<<a<<"\n";
cout<<"b="<<b<<"\n";
}

//sa se creeze un tip de date utilizator care sa se numeasca USHORT


#include "stdafx.h"
#include<iostream>
using namespace std;
typedef unsigned short int USHORT; //typedef defined

void main()
{
USHORT Width = 5;
USHORT Length;
Length = 10;
USHORT Area = Width * Length;
cout << "Width:" << Width << "\n";
cout << "Length: " << Length << endl;
cout << "Area: " << Area <<endl;
}
//sa se determine limitele unui tip de data
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
unsigned short int smallNumber;
smallNumber = 65535;
cout << "small number:" << smallNumber << endl;
smallNumber++;
cout << "small number:" << smallNumber << endl;
smallNumber++;
cout << "small number:" << smallNumber << endl;
return 0;
}
//prin fortarea tipului de date in CHAR se afiseaza caracterele
//care au codul ascii numarul convertit
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
for (int i = 32; i<128; i++)
cout << (char) i;
return 0;
}
//sa se creeze un tip de date enumerare
//componentele sale se numara de la zero
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
enum Days { Sunday, Monday, Tuesday, Wednesday, Thursday,
Friday,Saturday };

Days DayOff;
int x;

cout << "What day would you like off (0-6)? ";
cin >> x;
DayOff = Days(x);

if (DayOff == Sunday || DayOff == Saturday)


cout << "\nYou're already off on weekends!\n";
else
cout << "\nOkay, I'll put in the vacation day.\n";
return 0;
}
//sa se dea valori diferite aceleasi variabile
//o sa se retina ultima valoare si sa se puna in acelasi timp
//in doua variabile rezultatul unei expresii
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
int a=0, b=0, x=0, y=35;
cout << "a: " << a << " b: " << b;
cout << " x: " << x << " y: " << y << endl;
a = 9;
b = 7;
y = x = a+b;
cout << "a: " << a << " b: " << b;
cout << " x: " << x << " y: " << y << endl;
return 0;
}
#include "stdafx.h"
//sa se demonstreze ce face prefixarea si postfixarea incrementarii
#include<iostream>
using namespace std;
int main()
{
int myAge = 39; // initialize two integers
int yourAge = 39;
cout << "I am: " << myAge << " years old.\n";
cout << "You are: " << yourAge << " years old\n";
myAge++; // postfix increment
++yourAge; // prefix increment
cout << "One year passes...\n";
cout << "I am: " << myAge << " years old.\n";
cout << "You are: " << yourAge << " years old\n";
cout << "Another year passes\n";
cout << "I am: " << myAge++ << " years old.\n";
cout << "You are: " << ++yourAge << " years old\n";
cout << "Let's print it again.\n";
cout << "I am: " << myAge << " years old.\n";
cout << "You are: " << yourAge << " years old\n";
return 0;
}
//sa se testeze operatorii relationali
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
int RedSoxScore, YankeesScore;
cout << "Enter the score for the Red Sox: ";
cin >> RedSoxScore;

cout << "\nEnter the score for the Yankees: ";


cin >> YankeesScore;

cout << "\n";

if (RedSoxScore > YankeesScore)


cout << "Go Sox!\n";

if (RedSoxScore < YankeesScore)


{
cout << "Go Yankees!\n";
cout << "Happy days in New York!\n";
}
if (RedSoxScore == YankeesScore)
{
cout << "A tie? Naah, can't be.\n";
cout << "Give me the real score for the Yanks: ";
cin >> YankeesScore;

if (RedSoxScore > YankeesScore)


cout << "Knew it! Go Sox!";

if (YankeesScore > RedSoxScore)


cout << "Knew it! Go Yanks!";

if (YankeesScore == RedSoxScore)
cout << "Wow, it really was a tie!";
}

cout << "\nThanks for telling me.\n";


return 0;
}
// Programul care urmeaza calculeaza maximul dintre doua numere
citite este:

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int a,b,max;
cout<<"a="; cin>>a;
cout<<"b="; cin>>b;
if (a>b) max=a;
else max=b;
cout<<"maximul este"<<max;
}

//verificarea tipului unui triunghi


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

void main()
{
int a,b,c;
cout<<"test de triunghi"<<endl;
cout<<"introduceti numerele intregi a,b,c"<<endl;
cin>>a>>b>>c;
if (a==b && a==c)
cout<<"triunghi echilateral"<<endl;
else if ((a*a+b*b==c*c) || (a*a+c*c==b*b) || (b*b+c*c==a*a) )
cout<<"triunghi dreptunghic"<<endl;
else if ( ( (a+b>c) && (a+c>b)&& (b+c>a)
)
)
cout<<"numerele nu pot alcatui un
triunghi"<<endl;
else if(a==b || b==c || a==c)
cout<<"triunghi
isoscel"<<endl;
else
cout<<"triunghi oarecare"<<endl;
}

//verificarea tipului unei progresii


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

void main()
{
int a,b,c;
cout<<"introduceti a"<<endl;
cin>>a;
cout<<"introduceti b"<<endl;
cin>>b;
cout<<"introduceti c"<<endl;
cin>>c;
if (((float)(a+b)/2==c )||((float)(a+c)/2==b) ||((float)(b+c)/2==a ))
cout<<"aritmetica";
if ( (a*c==b*b) || (a*b==c*c) ||(b*c==a*a)) cout<<"geometrica";
else cout<<"neverificata";
}

Se citesc trei variabile reale a, b si c.Sa se calculeze


a+b, c>0
e= a*b, c=0
a-b, c<0

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
double a,b,c,e;
cout<<"a="; cin>>a;
cout<<"b="; cin>>b;
cout<<"c="; cin>>c;
if (c>0) e=a+b;
else
if (c==0) e=a*b;
else e=a-b;
cout<<e;
}

// sa se determine paritatea lui n

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
int n, remainder;

// Get a number from the keyboard.

cout << "Enter a number and press ENTER: ";


cin >> n;

// Get remainder after dividing by 2.

remainder = n % 2;

// If remainder is 0, the number input is even.

if (remainder == 0)
cout << "The number is even.";
else
cout << "The number is odd.";

return 0;
}
// sa se determine paritatea lui n
// dar in loc de conditie avem de evaluat o expresie

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
int n;

// Get a number from the keyboard.

cout << "Enter a number and press ENTER: ";


cin >> n;

// Get remainder after dividing by 2.


// If remainder is 0, the number input is even.

if (n % 2 == 0)
cout << "The number is even.";
else
cout << "The number is odd.";

return 0;
}
//sa se verifice utilitatea comenzii Else
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
int firstNumber, secondNumber;
cout << "Please enter a big number: ";
cin >> firstNumber;
cout << "\nPlease enter a smaller number: "; cin >>
secondNumber;
if (firstNumber > secondNumber)
cout << "\nThanks!\n";
else
cout << "\nOops. The second is bigger!";

return 0;
}
//sa se dea un exemplu prin care sa se arate ca in cazul a doua IF-
uri imbricate
//Else apartine primului IF
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
int x;
cout << "Enter a number less than 10 or greater than 100: ";
cin >> x;
cout << "\n";

if (x > 10)
{
if (x > 100)
cout << "More than 100, Thanks!\n";
}
else // not the else intended!
cout << "Less than 10, Thanks!\n";
return 0;
}
//sa se explice folosirea operatorului conditional
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
int x, y, z;
cout << "Enter two numbers.\n";
cout << "First: ";
cin >> x;
cout << "\nSecond: ";
cin >> y;
cout << "\n";

if (x > y)
z = x;
else
z = y;

cout << "z: " << z;


cout << "\n";

z = (x > y) ? x : y;

cout << "z: " << z;


cout << "\n";
return 0;
}
// Exercitiul 2.2.2.txt
// Acest program testeaza operatorul && logic
#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
int n;

cout << "Enter an age and press ENTER: ";


cin >> n;

if (n > 12 && n < 20)


cout << "Subject is a teenager.";
else
cout << "Subject is not a teenager.";

return 0;
}
// Exercitiul 2.2.2.txt
// Acest program testeaza operatorul && logic
#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
int n;

cout << "Enter a number and press ENTER: ";


cin >> n;

if (n >= 0 && n <= 100)


cout << "Number is in range.";
else
cout << "Number is not in range.";

return 0;
}
// Exercitiul 2.2.2.txt
// Acest program testeaza operatorul "sau" || logic
#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
int n;

cout << "Enter a number and press ENTER: ";


cin >> n;
if (n < 0 || n >= 100)
cout << "Number is in range.";
else
cout << "Number is not in range.";

return 0;
}

Instructiunea expresie

In C++ exista instructiunea expresie si este de forma:


expresie;
Se observa ca instructiunea expresie se termina cu “ ; ”.Daca expresia este vida, obtinem asa-numita
instructiune vida.
// . Programul urmator interschimba continutul a doua variabile
care //au fost citite.La sfarsit, se afiseaza noul continut al
//variabilelor.
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int a,b,c;
cout<<"a="; cin>>a;
cout<<"b="; cin>>b;
c=a; a=b; b=c;
cout<<"a="<<a<<endl;
cout<<"b="<<b<<endl;
}
// Se citesc doua valori intregi a si b.Se cere sa se afiseze media
lor aritmetica.
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int a,b;
float medie;
cout<<"a="; cin>>a;
cout<<"b="; cin>>b;
medie=float (a+b)/2;
cout<<"media este "<<medie;
}
Instructiunea compusa

Pentru a putea scrie mai multe instructiuni care sa fie interpretate de compilator ca una
singura se foloseste instructiunea compusa.Aceasta are forma urmatoare:

{
i1;
i2;
:
:
In ;
}

// Programul care urmeaza calculeaza radacinii ecuatiei de gradul 1

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
float a,b,x;
cout<<"a="; cin>>a;
cout<<"b="; cin>>b;
if (a)
{
x= -b/a;
cout<<x;
}
else
if (b==0) cout<<"infinitate de solutii";
else cout<<"nu are solutie";

Instructiunea switch

Instructiunea switch are forma generala:


switch (expresie)
{
case exp1:secventa instructiuni1;break;
case exp 2:secventa instructiuni2;break;
……………………..
case expn:secventa instructiunin;break;
[default :secventa instructiunin+1];
}
}
// Programul care urmeaza testeaza comanta switch

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int i;
cin>>i;
switch(i)
{
case 1 : cout<<"am citit 1"; break;
case 2 : cout<<"am citit 2"; break;
default : cout<<"am citit altceva";
}
}

INSTRUCTIUNI REPETITIVE
Instructiunea while

Forma generala a acestei instructiuni este:


while (expresie) instructiune
Instructiunea DO WHILE

Aceasta instructiune este asemanatoare cu structura REPEAT UNTIL.Forma ei este


urmatoarea:
do
instructiune
while(expresie);

Instructiunea FOR

Instructiunea for are forma generala:


for (expresieinitializare;expresietest;expresieincrementare) instructiune
 Expresieinitializare se foloseste, de regula, pentru initializarea variabilei de ciclare.Este de remarcat
faptul ca in cadrul acestei expresii este posibil chiar sa declaram variabila de ciclare (cu valoare
initiala).
 Expresietest se foloseste pentru a testa daca se executa instructiunea subordonata – daca expresia
produce la evaluare o valoare diferita de 0, instructiunea subordonata for se executa.
 Expresieincrementare se foloseste pentru incrementarea variabilei de ciclare.

// sa se afiseze 1 2 3 ...n cu while

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
int i, n;

// Get a number from the keyboard and initialize i.

cout << "Enter a number and press ENTER: ";


cin >> n;
i = 1;

while (i <= n) { // While i less than or equal to n,


cout << i << " "; // Print i,
i = i + 1; // Add 1 to i.
}

return 0;
}
// 1 Suma a n numere introduse de utilizator cu WHILE
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

void main()
{
float a;
int i,n;
float suma=0;
i=1;
cout<<"\nNumarul de elemente=";
cin>>n;
while(i<=n)
{
cout<<"Elementul "<<i<<"este: ";
cin>>a;
suma=suma+a; //se mai poate scrie suma+=a
i++;
}
cout<<"Suma este= "<<suma;
}
// Suma primelor n numere naturale. cu WHILE
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

void main()
{
int n;
int i;
int suma=0;
cout<<"n=";
cin>>n;
i=1;
while(i<=n)
{
suma=suma+i;
i++;
}
cout<<"Suma este: "<<suma;
}

// Acest program testeaza daca un nr e prim sau nu


#include "stdafx.h"
#include <iostream>
#include<math.h>
using namespace std;

int main() {
int n; // Number to test for prime-ness
int i; // Loop counter
int is_prime; // Boolean flag

// Assume that a number is prime until proven otherwise

is_prime = true;

// Get a number from the keyboard.

cout << "Enter a number and press ENTER: ";


cin >> n;

// Test for prime-ness by checking for divisibility


// by all whole numbers from 2 to sqrt(n).
i = 2;
while (i <= sqrt(static_cast<double>(n))) {
// While i is <= sqrt(n),
if (n % i == 0) // If i divides evenly into n,
is_prime = false; // n is not prime.
i++; // Add 1 to i.
}

// Print results

if (is_prime)
cout << "Number is prime.";
else
cout << "Number is not prime.";

return 0;
}
// . Se citeste n, numar natural.Sa se calculeze suma cifrelor sale
(pentru n=213, se va tipari 6)cu WHILE
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int n,s=0;
cout<<"n="; cin>>n;
while (n)
{
s=s+n%10;
n=n/10;
}
cout<<s;
}
// . Se citeste n, numar natural.Sa se afiseze numarul obtinut
prin //inversarea cifrelor sale (pentru n=412,se va tipari214).
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int n,ninv=0;
cout<<"n="; cin>>n;
while (n)
{
ninv=ninv*10+n%10;
n=n/10;
}
cout<<"numarul inversat "<<ninv;
}
// . Se citeste n, numar natural.Sa se afiseze numarul obtinut prin
inversarea cifrelor sale (pentru n=412,se va tipari214).
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int n,ninv=0;
cout<<"n="; cin>>n;
while (ninv=ninv*10+n%10,n/=10);
cout<<ninv;
}
// . Se citeste n, numar natural.Sa se afiseze numarul obtinut
prin //inversarea cifrelor sale (pentru n=412,se va tipari214).
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int n,ninv=0;
cout<<"n="; cin>>n;
while (ninv*=10,ninv+=n%10,n/=10);
cout<<ninv;
}
// Exercitiul 2.2.2.txt
// Acest program testeaza daca un nr e prim sau nu folosind si
comanda break
#include "stdafx.h"
#include <iostream>
#include<math.h>
using namespace std;

int main() {
int n; // Number to test for prime-ness
int i; // Loop counter
int is_prime; // Boolean flag

// Assume that a number is prime until proven otherwise

is_prime = true;

// Get a number from the keyboard.

cout << "Enter a number and press ENTER: ";


cin >> n;

// Test for prime-ness by checking for divisibility


// by all whole numbers from 2 to sqrt(n).

i = 2;
double sqrt_n = sqrt(static_cast<double>(n));
while (i <= sqrt_n) { // While i is <= sqrt(n),
if (n % i == 0) { // If i divides evenly into n,
is_prime = false; // n is not prime.
break;
}
i++; // Add 1 to i.
}
// Print results

if (is_prime)
cout << "Number is prime.";
else
cout << "Number is not prime.";

return 0;
}

// sa se afiseze N1+1 N2+2 N3+3 ...n2 cu while

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
int i, n1, n2;

// Get a numbers n1 and n2 from the keyboard.

cout << "Enter first number and press ENTER: ";


cin >> n1;
cout << "Enter second number and press ENTER: ";
cin >> n2;

i = n1;

while (i <= n2) { // While i less than or equal to n2,


cout << i << " "; // Print i,
i = i + 1; // Add 1 to i.
}

return 0;
}
// Exercitiul 2.2.2.txt
// Acest program afseaza numerele de la n la 1, in ordine inversa CU
WHILE.
#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
int i, n;

// Get a number from the keyboard and initialize i to n.

cout << "Enter a number and press ENTER: ";


cin >> n;
i = n;

while (i > 0) { // While i greater than 0,


cout << i << " "; // Print i,
i = i - 1; // Add 1 to i.
}

return 0;
}
// Exercitiul 2.2.2.txt
// Acest program afseaza numerele de la n la 1, in ordine inversa CU
DO ..WHILE.
#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
int i, n;

// Get a number from the keyboard and initialize i to n.

cout << "Enter a number and press ENTER: ";


cin >> n;
i = n;

do { // While i greater than 0,


cout << i << " "; // Print i,
i = i - 1; // Add 1 to i.
}while (i > 0);

return 0;
}
// Sa se calculeze suma primelor n numere naturale.
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int n,s=0,i=1;
cout<<"n="; cin>>n;
do
{ s=s+i;
i=i+1;
} while (i<=n);
cout<<s;
}
// Sa se calculeze suma primelor n numere naturale.
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int n,s=0,i=1;
cout<<"n="; cin>>n;
do s+=i++; while (i<=n);
cout<<s;
}
// . Se citeste n, numar natural.Sa se descompuna in factori primi.
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
main ( )
{
int n,i=2,fm;
cout<<"n="; cin>>n;
do
{
fm=0;
while (n%i==0)
{
fm++; // sau fm=fm+1;
n/=i; // sau n=n/i;
}
if (fm) cout<<i<<"la puterea "<<fm<<endl;
i++;
} while (n!=1);
}
// . Programul urmator listeaza numerele 5, 4, 3, 2, 1.
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int i;
for (i=5;i>=1;i--) cout<<i<<" ";
}
// . Se citeste n (numar natural).Se cere sa se efectueze suma
primelor n numere naturale.Exemplu: n=3, s=1+2+3=6.

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main( )
{
int i,n,s=0;
cout<<"n="; cin>>n;
for (i=1;i<=n;i++) s+=i; // sau s=s+i;
cout<<"suma primelor n numere naturale este "<<s;
}
// . Se citeste n (numar natural).Se cere sa se efectueze suma
primelor n numere naturale.Exemplu: n=3, s=1+2+3=6.

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main( )
{
int i,n,s=0;
cout<<"n="; cin>>n;
for (i=1;i<=n;s+=i++);
cout<<"suma primelor n numere naturale este "<<s;
}
// Sa se calculeze suma: s=0,1+0,2+…+0,9.

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main( )
{
int i;
float s=0.0;
for (i=1;i<=9;i++) s+=(float)i/10;
cout<<s;
}
// . Se citeste n un numar natural.Sa se calculeze suma
S=1+1*2+1*2*3+…+1*2*…*n.

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main( )
{
int i,s=0,p=1,n;
cout<<"n="; cin>>n;
for (i=1;i<=n;i++)
{
p*=i; // p=p*i;
s+=p; // s=s+p;
}
cout<<s;
}
// Se citesc n numere intregi.Se cere sa se afiseze cel mai mare
numar citit.Exemplu: daca avem n=4, iar numerele sunt –7, 9, 2, 3, se
va afisa 9.

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main( )
{
int i,max,n,nr;
cout<<"n="; cin>>n;
cout<<"nr="; cin>>nr;
max=nr;
for (i=2;i<=n;i++)
{
cout<<"nr="; cin>>nr;
if (nr>max) max=nr;
}
cout<<"maximul este "<<max;
}
// Se citeste un numar natural.Sa se afiseze numarul obtinut prin
inversarea cifrelor sale."

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int i,s,n,ninv;
cout<<"n="; cin>>n;
for (ninv=0;n>0;)
{
ninv=ninv*10+n%10;
n=n/10;
}
cout<<ninv;
}
// Se citeste un numar natural.Sa se afiseze numarul obtinut prin
inversarea cifrelor sale."

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int i,s,n,ninv;
cout<<"n="; cin>>n;
for (ninv=0;n>0;n/=10) ninv=ninv*10+n%10;
cout<<ninv;
}

// afisarea lui 1 2 3 ..n cu For


#include "stdafx.h"
#include <iostream>
#include<math.h>
using namespace std;

int main() {
int i, n;

// Get a number from the keyboard and initialize i.

cout << "Enter a number and press ENTER: ";


cin >> n;

for (i = 1; i <= n; i++) // For i = 1 to n,


cout << i << " "; // Print i.

return 0;
}
// afisarea lui n1+1 n1+2 n1+3 ..n2 cu For
#include "stdafx.h"
#include <iostream>
#include<math.h>
using namespace std;

int main() {
int i, n1, n2;

// Get n1 and n2 from the keyboard.

cout << "Enter first number and press ENTER: ";


cin >> n1;
cout << "Enter second number and press ENTEr: ";
cin >> n2;

for (i = n1; i <= n2; i++) // For i = n1 to n2,


cout << i << " "; // Print i.

return 0;
}
// Exercitiul 3.1.2.txt
// Acest program afiseaza numerele de la n la 1 cu FOR

#include "stdafx.h"

#include <iostream>
using namespace std;

int main() {
int i, n;

// Get a number from the keyboard and initialize i.

cout << "Enter a number and press ENTER: ";


cin >> n;

for (i = n; i >= 1; i--) // For i = n down to 1


cout << i << " "; // Print i.

return 0;
}
// Exercitiul 3.1.2.txt
// Acest program determina DACA UN NUMAR E PRIM SAU NU cu FOR

#include "stdafx.h"
#include <iostream>
#include <math.h>
using namespace std;

int main() {
int n; // Number to test for prime-ness
int i; // Loop counter
int is_prime; // Boolean flag

// Assume that a number is prime until proven otherwise

is_prime = true;

// Get a number from the keyboard.

cout << "Enter a number and press ENTER: ";


cin >> n;

// Test for prime-ness by checking for divisibility


// by all whole numbers from 2 to sqrt(n).

for (i = 2; i <= sqrt((double) n); i++) {


if (n % i == 0)
is_prime = false;
}

// Print results

if (is_prime)
cout << "Number is prime.";
else
cout << "Number is not prime.";

return 0;
}
// Acest program determina daca un numar este prim,
// folosind o instructiune for si cod optimizat.
//

#include "stdafx.h"

#include <iostream>
#include <math.h>
using namespace std;

int main() {
int n; // Number to test for prime-ness
int i; // Loop counter
int is_prime; // Boolean flag

// Assume that a number is prime until proven otherwise

is_prime = true;

// Get a number from the keyboard.

cout << "Enter a number and press ENTER: ";


cin >> n;

// Test for prime-ness by checking for divisibility


// by all whole numbers from 2 to sqrt(n).
double sqrt_n = sqrt(static_cast<double>(n));

for (i = 2; i <= sqrt_n; i++) {


if (n % i == 0) {
is_prime = false;
break;
}
}

// Print results

if (is_prime)
cout << "Number is prime.";
else
cout << "Number is not prime.";

return 0;
}
Functii matematice

Fiecare dintre functiile prezentate mai jos are prototipul in math.h :

 Functia abs are forma generala: int abs(int x); Aceasta inseamna ca are un parametru de tip int, iar rezultatul
este tot de tip int. Inaintea numelui se gaseste tipul rezultatului.Rolul ei este de a intoarce |x| (modulul lui x).
Iata cum arata un program care o foloseste (tipareste 1234):

#include <iostream.h>

#include <math.h>

main ( )

int n= -1234;

cout<<abs(n);

 Functia fabs are forma generala double fabs(double x);


are acelasi rol cu abs, numai ca intoarce valoarea unui numar real (chiar double).

 Functia labs are forma generala long int labs(long int x);
are acelasi rol cu abs, numai ca intoarce valoarea unui intreg

lung.

 Functia acos are forma generala double acos(double x); si calculeaza valoarea functiei arccos(x): [-
1,1][0,π].
 Functia asin are forma generala double asin(double x); si calculeaza valoarea functiei arcsin(x): [-
1,1][-π/2,π/2].
 Functia atan are forma generala double atan(double x); si
calculeaza valoarea functiei arctg(x):R(-π/2,π/2).

 Functia atan2 are forma generala


double atan2(double y,double x)

si calculeaza arctg(y/x).Rezultatul este in intervalul (-π,π).

 Functia ceil are forma generala double ceil(double x); si calculeaza |x| a lui x (rotunjirea se face in minus).
 Functia floor are forma generala double floor(double x); si
calculeaza valoarea rotunjita a lui x (rotunjirea se face in plus).

 Functia cos are forma genarala double cos(double x); si calculeaza valoarea functiei cos(x):R[-1,1].
 Functia sin are forma generala double sin(double x); si
calculeaza valoarea functiei sin(x):R[-1,1].

 Functia tan are forma generala double tan(double x); si calculeaza valoarea functiei tg(x):R—{k*π+π/2|k din
Z}R.
 Functia exp are forma generala double exp(double x); si calculeaza functia e x:RR*+.
 Functia log are forma generala double log(double x); si
calculeaza functia ln(x): R*+R, unde ln(x)=loge(x).

 Functia log10 are forma generala double log10(double x); si calculeaza functia lg(x): R*+R, unde
lg(x)=log10(x).
 Functia pow are forma generala double pow(double x, double y); si calculeaza xy.
Observatie: Este sarcina programatorului, ca pentru o astfel de functie, valoarea argumentului

sa fie in domeniul de definitie al functiei respective.

VECTORI SI MATRICE

Tablouri in C++

In C++ tipul tablou se declara astfel:

tip nume[numar natural1] [numar natural2]…[numar naturaln]

Adresarea unei componente se face prin indice, care se trece intre paranteze drepte, iar

componentele au indici intre 0 si 99.

//suma elementelor unui vector


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

void main()
{
static int x[10]={1,2,3,4,5,6,7,8,9,10};
int i,s=0,n=10;
for(i=0;i<n;i++) s+=x[i];
cout<<" s="<<s<<endl;
}

// // Exercitiul 5.1.2.txt
// Acest program afiseaza sase intregi impreuna cu totalul lor.

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

int main() {
int i, sum = 0;
int scores[6] = {10, 22, 13, 99, 4, 5};

for(i = 0; i < 6; i++) {


cout << scores[i] << " ";
sum = sum + scores[i];
}
cout << endl << "The sum is " << sum << endl;

return 0;
}

// Se citeste un numar natural.Sa se afiseze un vector

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int v[100],n,i;
cout<<"numar de componente"; cin>>n;
for (i=0;i<n;i++)
{
cout<<"v["<<i+1<<"]=";
cin>>v[i];
}
for (i=0;i<n;i++) cout<<v[i]<<endl;
}
// sa se initializeze un vector

#include "stdafx.h"

#include <iostream>
#include <math.h>
using namespace std;
int main() {
int i;
double V[5] = {0.5, 1.5, 2.5, 3.5, 4.5};

for(i = 0; i < 5; i++) {


cout << V[i] << " ";
}

return 0;
}
// Se citeste un numar natural.Sa se afiseze un vector
//obtinut prin copierea de componente

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int n,i;
float a[50], b[50];
cout<<"numar de componente"; cin>>n;
for (i=0;i<n;i++)
{
cout<<"a["<<i+1<<"]=";
cin>>a[i];
}
for (i=0;i<n;i++) b[i]=a[i];
for (i=0;i<n;i++) cout<<b[i]<<endl;
}

// sa se initializeze un vector DE INTREGI


//INDICII PLEACA DE LA VALOAREA ZERO

#include "stdafx.h"

#include <iostream>
#include <math.h>
using namespace std;
int main() {
int i;
int scores[8] = {5, 15, 25, 35, 45, 55, 65, 75};

for(i = 0; i < 8; i++) {


cout << scores[i] << " ";
}

return 0;
}
// Se citeste un numar natural.Sa se afiseze maximul dintr-un vector

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int v[9],n,i,max;
main ( )
{
cout<<"n ="; cin>>n;
for (i=0;i<n;i++)
{
cout<<"v["<<i+1<<"]=";
cin>>v[i];
};
int max=v[0];
for (i=0;i<n;i++)
if (v[i]>max) max=v[i];
cout<<"valoarea maxima citita este "<<max;
}
// Se citeste un numar natural.Sa se determine daca sunt elemente
distincete intr-un vector si nu avem deloc identice
//dintr-un vector

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int v[9],n,i,j,gasit;
main ( )
{
cout<<"n ="; cin>>n;
for (i=0;i<n;i++)
{
cout<<"v["<<i+1<<"]=";
cin>>v[i];
}
gasit=0;
for(i=0;i<n && !gasit;i++)
for(j=0;j<n && !gasit;j++)
if (v[i]==v[j]) gasit=1;
if (gasit) cout<<"numerele nu sunt distincte";
else cout<<"numerele sunt distincte";
}
// Se citeste un numar natural.Sa se determine apartenenta unui
element la un vector

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int mult[9], n,e,i,gasit;


main ( )
{
cout<<"numarul de elemente ale multimii "; cin>>n;
for (i=0;i<n;i++)
{
cout<<"mult["<<i+1<<"]="; cin>>mult[i];
}
cout<<"elementul considerat "; cin>>e;
gasit=0;
for(i=0;i<n && !gasit;i++)
if (mult[i]==e) gasit=1;
if (gasit) cout<<"elementul apartine multimii";
else cout<<"elementul nu apartine multimii";
}
// Se citeste un numar natural.Sa se determine
//diferenta a doua multimi

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int multa[9], multb[9],multc[9],n,m,i,j,k,gasit;


main ( )
{
cout<<"numarul de elemente al multimii A "; cin>>n;
for (i=0;i<n;i++)
{
cout<<"mult["<<i+1<<"]="; cin>>multa[i];
}
cout<<"numarul de elemente al multimii B "; cin>>m;
for (i=0;i<m;i++)
{
cout<<"mult["<<i+1<<"]="; cin>>multb[i];
}
k=0;
for (i=0;i<n;i++)
{
gasit=0;
for (j=0;j<=m && !gasit;j++)
if (multa[i]==multb[j]) gasit=1;
if (!gasit) multc[k++]=multa[i];
}
cout<<"A-B"<<endl;
for (i=0;i<k;i++) cout<<multc[i]<<endl;
}
// Se citeste un numar natural.Sa se determine
//reuniunea a doua multimi

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
int multa[9], multb[9],multc[9],n,m,i,j,k,gasit;
main ( )
{
cout<<"numarul de elemente al multimii A "; cin>>n;
for (i=0;i<n;i++)
{
cout<<"mult["<<i+1<<"]="; cin>>multa[i];
}
cout<<"numarul de elemente al multimii B "; cin>>m;
for (i=0;i<m;i++)
{
cout<<"mult["<<i+1<<"]="; cin>>multb[i];
}
k=0;
for (i=0;i<n;i++)
{
gasit=0;
for (j=0;j<=m && !gasit;j++)
if (multa[i]==multb[j]) gasit=1;
if (!gasit) multc[k++]=multa[i];
}
cout<<"A reunit cu B"<<endl;
for (i=0;i<m;i++) cout<<multb[i]<<endl;
for (i=0;i<k;i++) cout<<multc[i]<<endl;
}
// Se citeste un numar natural.Sa se determine
//intersectia a doua multimi

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int multa[9], multb[9],multc[9],n,m,i,j,k,gasit;


main ( )
{
cout<<"numarul de elemente al multimii A "; cin>>n;
for (i=0;i<n;i++)
{
cout<<"mult["<<i+1<<"]="; cin>>multa[i];
}
cout<<"numarul de elemente al multimii B "; cin>>m;
for (i=0;i<m;i++)
{
cout<<"mult["<<i+1<<"]="; cin>>multb[i];
}

k=0;
for (i=0;i<n;i++)
{
gasit=0;
for (j=0;j<=m && !gasit;j++)
if (multa[i]==multb[j]) gasit=1;
if (gasit) multc[k++]=multa[i];
}
cout<<"A intersectat cu B"<<endl;
for (i=0;i<k;i++) cout<<multc[i]<<endl;
}
// Se citeste un numar natural.Sa se determine
//produsul cartezian a doua multimi identice

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int n,m,i,j;
cout<<"numarul de elemente al multimii A "; cin>>n;
cout<<"numarul de elemente al multimii B "; cin>>m;
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
cout<<i<<" "<<j<<endl;
}
// Se citeste un numar natural.Sa se determine
//produsul cartezian a doua multimi diferite

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

char multa[9],multb[9];
int n,m,i,j;
main ( )
{
cout<<"numarul de elemente al multimii A "; cin>>n;
for (i=0;i<n;i++)
{
cout<<"mult["<<i+1<<"]="; cin>>multa[i];
}
cout<<"numarul de elemente al multimii B "; cin>>m;
for (i=0;i<m;i++)
{
cout<<"mult["<<i+1<<"]="; cin>>multb[i];
}
for (i=0;i<=n;i++)
for (j=0;j<=m;j++)
cout<<multa[i]<<" "<<multb[j]<<endl;
}
// Se citeste un numar natural.Sa se determine
//submultimile unei multimi

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int multa[9],n,i,s;
main ( )
{
cout<<"numarul de elemente al multimii A "; cin>>n;
for (i=0;i<n;i++)
multa[i++]=0;
do
{
multa[n-1]++;
for (i=n-1;i>=1;i--)
if (multa[i]>1)
{
multa[i]-=2;
multa[i-1]+=1;
}
s=0;
for (i=0;i<n;i++) s+=multa[i];
for (i=0;i<n;i++)
if (multa[i]) cout<<i+1<<" ";
cout<<endl;
} while (s<n) ;
cout<<"multimea vida ";
}
// Sortarea prin selectarea minimului (maximului)

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int a[9],n,i,j,k,man,min;
main ( )
{
cout<<"n="; cin>>n;
for (i=0;i<n;i++)
{
cout<<"a["<<i+1<<"]="; cin>>a[i];
} ;
for (i=0;i<n-1;i++)
{
int min=a[i];k=i;
for (j=i+1;j<n;j++)
if (a[j]<min)
{
min=a[j];
k=j;
}
man=a[k];
a[k]=a[i];
a[i]=man;
}
for (i=0;i<n;i++) cout<<a[i]<<endl;
}
// Se citeste un numar natural.Sa se determine
//sortarea prin interschimbare

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
int a[9],n,i,j,k,man,gasit;
main ( )
{
cout<<"n="; cin>>n;
for (i=0;i<n;i++)
{
cout<<"a["<<i+1<<"]="; cin>>a[i];
} ;
do
{
gasit=0;
for (i=0;i<n-1;i++)
if (a[i]>a[i+1])
{
int man=a[i];
a[i]=a[i+1];
a[i+1]=man;
gasit=1;
}
} while (gasit);
for (i=0;i<n;i++) cout<<a[i]<<endl;
}

// Se citeste un numar natural.Sa se determine


//sortarea prin selectie

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int a[9], b[9], n,i,j,k,gasit;


main ( )
{
cout<<"n="; cin>>n;
for (i=0;i<n;i++)
{
cout<<"a["<<i+1<<"]="; cin>>a[i];
} ;
b[0]=a[0];
for (i=1;i<n;i++)
{
j=i-1;
while (j>=0 && a[i]<b[j]) j--;
for (k=i-1;k>=j+1;k--) b[k+1]=b[k];
b[j+1]=a[i];
}
for (i=0;i<n;i++) cout<<b[i]<<endl;
}
// Se citeste un numar natural.Sa se determine
//sortarea prin interclasare

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
main ( )
{
int a[100],b[100],c[200],m,n,i,j,k;
cout<<"m="; cin>>m;
for (i=0;i<m;i++)
{
cout<<"a["<<i+1<<"]="; cin>>a[i];
} ;
cout<<"n="; cin>>n;
for (i=0;i<n;i++)
{
cout<<"b["<<i+1<<"]="; cin>>b[i];
} ;
i=j=k=0;
while (i<m && j<n)
if (a[i]<b[j]) c[k++]=a[i++];
else c[k++]=b[j++];
if (i<m)
for (j=i;j<m;j++) c[k++]=a[j];
else
for (i=j;i<n;i++) c[k++]=b[i];
for (i=0;i<k;i++) cout<<c[i]<<endl;
}

// Se citeste un numar natural.Sa se determine


//cautarea binara

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int a[100],n,i,li,ls,k,nr,gasit;
cout<<"n="; cin>>n;
for (i=0;i<n;i++)
{
cout<<"a["<<i+1<<"]="; cin>>a[i];
} ;
cout<"nr="; cin>>nr;
li=0;ls=n-1;gasit=0;
do
{
k=(li+ls)/2;
if (a[k]==nr)
{
cout<<"gasit pe pozitia "<<k+1;
gasit=1;
}
else
if (a[k]<nr) li=k+1;
else ls=k-1;
} while (li<=ls && !gasit);
if (li>ls) cout<<"negasit";
}

// Se citeste un numar natural.Sa se afiseze o matrice


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int m,n,i,j,a[9][9];
cout<<"m ="; cin>>m;
cout<<"n ="; cin>>n;
for (i=0;i<m;i++)
for (j=0;j<n;j++)
{
cout<<"a["<<i+1<<","<<j+1<<"]=";
cin>>a[i][j];
}
for (i=0;i<m;i++)
{
for (j=0;j<n;j++) cout<<a[i] [j]<<" ";
cout<<endl;
}
}
// Se citeste m si n natural.Sa se determine
//schimbarea a doua linii intre ele

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int mat[10][10],m,n,i,j,x,y,man;
cout<<"m="; cin>>m;
cout<<"n="; cin>>n;
for (i=0;i<m;i++)
for (j=0;j<n;j++)
{
cout<<"mat["<<i+1<<","<<j+1<<"]=";
cin>>mat[i][j];
};
cout<<"x="; cin>>x;
cout<<"y="; cin>>y;
cout<<endl;
for (i=0;i<m;i++)
{
for (j=0;j<n;j++) cout<<mat[i][j]<<" ";
cout<<endl;
}
for (j=0;j<n;j++)
{
man=mat[x-1][j];
mat[x-1][j]=mat[y-1][j];
mat[y-1][j]=man;
}
cout<<endl;
for (i=0;i<m;i++)
{
for (j=0;j<n;j++) cout<<mat[i][j]<<" ";
cout<<endl;
}
}
// Se citeste m si n natural.Sa se determine
//parcurgerea pe spirala a unei matrice

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int mat[10][10],n,i,j,k;
cout<<"n="; cin>>n;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
cout<<"mat["<<i<<","<<j<<"]=";
cin>>mat[i][j];
}
for (k=1;k<=n/2;k++)
{
for (i=k;i<=n-k+1;i++) cout<<mat[k][i]<<endl;
for (i=k+1;i<=n-k+1;i++) cout<<mat[i][n-
k+1]<<endl;
for (i=n-k;i>=k;i--) cout<<mat[n-k+1][i]<<endl;
for (i=n-k;i>=k+1;i--) cout<<mat[i][k]<<endl;
}
}

TIPUL DE DATE SIR DE CARACTERE

Memorarea si declararea vectorilor de caractere


In memoria interna, o constanta de tip sir este retinuta sub forma unui vector de caractere.Conventia este ca

ultimul octet sa retina 0 (caracterul nul).Pentru fiecare caracter este retinut codul ASCII.

Vectorii de caractere pot fi initializati la declarare, caracterul nul fiind memorat automat.

// // Exercitiul 5.1.2.txt
// Acest program afiseaza copierea si concaternarea unor fraze
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;

int main() {
char str[600];
char name[100];
char addr[200];
char work[200];

// Get three strings from the user.

cout << "Enter name and press ENTER: ";


cin.getline(name, 99);
cout << "Enter address and press ENTER: ";
cin.getline(addr, 199);
cout << "Enter workplace and press ENTER: ",
cin.getline(work, 199);

// Build the output string, and then print it.

strcpy(str, "\nMy name is ");


strcat(str, name);
strcat(str, ", I live at ");
strcat(str, addr);
strcat(str, ",\nand I work at ");
strcat(str, work);
strcat(str, ".");

cout << str;

return 0;
}

/
// Exercitiul 7.1.1.txt
// Aceasta versiune de program utilizeaza varianta "n" a functiilor
strcpy si
// strcat, pentru a evita depasirea limitelor de lungime a sirului.

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;

int main() {
char str[600];
char name[100];
char addr[200];
char work[200];

// Get three strings from the user.

cout << "Enter name and press ENTER: ";


cin.getline(name, 99);
cout << "Enter address and press ENTER: ";
cin.getline(addr, 199);
cout << "Enter workplace and press ENTER: ",
cin.getline(work, 199);

// Build the output string, and then print it.

strncpy(str, "\nMy name is ", 599);


strncat(str, name, 599 - strlen(str));
strncat(str, ", I live at ", 599 - strlen(str));
strncat(str, addr, 599 - strlen(str));
strncat(str, ",\nand I work at ", 599 - strlen(str));
strncat(str, work, 599 - strlen(str));
strncat(str, ".", 599 - strlen(str));

cout << str;

return 0;
}

// Exercitiul 7.1.2.txt
// Aceasta versiune de program utilizeaza varianta "n" a functiilor
strcpy si
// strcat, pentru a evita depasirea limitelor de lungime a sirului.
// De asemenea, aceasta versiune utilizeaza si directiva #define,
astfel incat sa o puteti
// testa cu diferite valori ale lui STRMAX, prin modificarea unei
linii, dupa care
// trebuie sa recompilati.
//rcat, pentru a evita depasirea limitelor de lungime a sirului.

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;

#define STRMAX 599

int main() {
char str[STRMAX + 1];
char name[100];
char addr[200];
char work[200];

// Get three strings from the user.

cout << "Enter name and press ENTER: ";


cin.getline(name, 99);
cout << "Enter address and press ENTER: ";
cin.getline(addr, 199);
cout << "Enter workplace and press ENTER: ",
cin.getline(work, 199);

// Build the output string, and then print it.

strncpy(str, "\nMy name is ", STRMAX);


strncat(str, name, STRMAX - strlen(str));
strncat(str, ", I live at ", STRMAX - strlen(str));
strncat(str, addr, STRMAX - strlen(str));
strncat(str, ",\nand I work at ", STRMAX - strlen(str));
strncat(str, work, STRMAX - strlen(str));
strncat(str, ".", STRMAX - strlen(str));

cout << str;

return 0;
}

// sa se transforme in majuscule un sir

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;
#include <ctype.h>

int main() {
char s[100];
int i;
int length = strlen(s);

cout << "Enter string to convert and press ENTER: ";


cin.getline(s, 99);

cout << "The converted string is:" << endl;

for (i = 0; i < length; i++)


s[i] = toupper(s[i]);
for (i = 0; i < length; i++)
cout<<s[i];

return 0;
}

//SA SE TRANSFORME IN MINUSCULE

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;
#include <ctype.h>

int main() {
char s[100];
int i;

cout << "Enter string to convert and press ENTER: ";


cin.getline(s, 99);
int length = strlen(s);
cout << "The converted string is:" << endl;

for (i = 0; i < length; i++)


s[i] = tolower(s[i]);
for (i = 0; i < length; i++)
cout<<s[i];

return 0;
}

// Se memoreze un vector de caractere

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
char a[20];
int i;
for (i=0;i<10;i++) cin>>a[i];
a[10]=0;
for (i=0;i<10;i++) cout<<a[i];
}

Functia cin.get(vector_de_caractere, int nr, char=’\n’) , care citeste un sir de caractere, memorat sub forma

unui vector cu nr-1 componente, pana la intalnirea caracterului dat.Al treilea parametru este optional.Daca nu

este trecut, se presupune ca este ‘\n’.

// Se memoreze maxim trei caractere

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
char a[10];
cin.get(a,3);
cout<<a;

}
// Se memoreze doua fraze

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char sir1[1000], sir2[25];
cout<<"sir 1 "; cin.get(sir1,1000);
cin.get ( );
cout<<"sir 2 "; cin.get(sir2,25);
}

Tipul char*

Limbajul C++ permite ca un vector de caractere sa fie adresat incepand de la un anumit octet al sau.
 Octetii memoriei interne sunt numerotati incepand cu 0.
 Numarul de ordine al unui octet in memoria interna se numeste adresa octetului respectiv.
 Prin definitie, adresa unui vector de caractere este ardesa primului sau octet.
 O variabila de tipul char* poate retine adresa unui vector de caractere.
 In C++ numele unui vector de caractere este o adresa constanta de vector si poate fi atribuit unei variabile de
tip char*.

// Se piarda cate o litera incepand de la stanga la dreapta

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char a[ ]="masa";
cout<<a+1<<" "<<a+2<<" "<<a+3;
}
// Se piarda cate o litera incepand de la stanga la dreapta

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{ char a[ ]="Exemplu", *p;
p=a; cout<<p<<endl;
p++; cout<<p<<endl; // { ne deplasam pe urmatorul octet}
p++; cout<<p<<endl;
cout<<p[1]<<endl; //{ se tipareste numai acest octet}
cout<<p-a;
}
FUNCTII CARE OPEREAZA CU SIRURI DE CARACTERE
Functia strlen are rolul de a returna lungimea efectiva a unui sir (in calculul lungimii nu intra caracterul
nul).Forma generala este:
size_t strlen (char*);
 size_t este un tip intreg, utilizat in adresarea memoriei (il putem privi ca pe tipul unsigned int)
 argumentul este de tip char* - un vector de caractere
 Functia strcpy are forma generala:
char *strcpy (char* dest,char* sursa);
si are rolul de a copia sirul de adresa sursa la adresa dest.
 Functia standard strcat are forma generala:
char *strcat (char* dest, char* sursa);
si rolul de a adauga sirului de adresa dest sirul de adresa sursa.Sirul de adresa sursa ramane
nemodificat.Aceasta operatie se numeste concatenare si nu este comutativa
 Functia strncat are forma generala:
char *strncat (char *dest, const char *sursa, size_t nr);
si acelasi rol ca strcat cu deosebirea ca adauga sirului destinatie primii nr octeti ai sirului
sursa.Adaugarea se face inaintea caracterului nul.
 Functia strchr are forma generala:
char *strchr (char *s, int c);
si rolul de a cauta caracterul c in sirul s.Cautarea se face de la stanga la dreapta.In cazul in care caracterul
este gasit, functia
intoarce adresa subsirului care incepe cu prima aparitie a caracterului citit si se termina cu caracterul nul al
sirului in care se face cautarea.
 Functia strrchr are forma generala:
char *strrchr (const char *s, int c);
si are acelasi rol cu strchr , deosebirea fiind data de faptul ca returneaza adresa ultimei aparitii a
caracterului – cautarea se
face de la dreapta catre stanga.
 Functia strcmp are forma generala:
int strcmp (const char *s1, const char *s2);
si rolul de a compara doua siruri de caractere.Valoarea returnata este:
 <0, daca s1<s2;
 =0, daca s1=s2;
 >0, daca s1>s2;
Mecanismul prin care se compara doua siruri de caractere este urmatorul:
Fie m numarul de caractere ale sirului s1 si n numarul de caractere ale sirului s2.Sa presupunem ca
primele i caractere ale lui s1 coincid cu primele i ale lui s2.
 In cazul in care codul caracterului i+1 al sirului s1 este mai mare decat codul caracterului corespunzator al
sirului s2, avem s1>s2.
 In cazul in care codul corespunzator i+1 al sirului s1 este mai mic decat codul caracterului corespunzator al
sirului s2, avem s1<s2.In cazul in care avem egalitate, avem patru posibilitati:
 Ambele siruri au un numar strict mai mare de caracatere decat i+1, caz in care se compara ca inainte
caracterele de pe pozitia i+2;
 s1 are i+1 caractere, iar s2 are un numar de caractere mai mare decat i+1, in acest caz s1<s2;
 s2 are i+1 caractere, iar s1 are un numar de caractere mai mare decat i+1, in acest caz s1>s2;
 atat s1 cat si s2 au i+1 caractere, caz in care s1=s2.

Functia strstr are forma generala:


char *strstr (const char *s1, const char *s2);
si rolul de a identifica daca sirul s2 este subsir al sirului s1.
Daca acesta este identificat, functia returneaza adresa de inceput in cadrul sirului s1, altfel returneaza
adresa 0.Cautarea se face de la stanga la dreapta.
 Functia stricmp are forma generala:
int strcmp(char *s1,char *s2);
si are acelasi rol ca strcmp, cu deosebirea ca nu face distinctie intre literele mari si mici.
 Functia strtok are forma generala:
char *strtok(char *s1, const char *s2);
 Functia strcspn are forma generala:
size_t strcspn(const char *s1, const char *s2);
si rolul de a returna numarul de caractere ale sirului s1 (caractere consecutive care incep obligatoriu
cu primul caracter) care nu se gasesc in sirul s2.
 Functia standard strspn are forma generala:
size_t strspn(char *s1, char *s2);
si rolul de a returna numarul de caractere ale sirului s1 (caractere consecutive care incep obligatoriu
cu primul caracter) care se gasesc in sirul s2.
 Functia strlwr are forma generala:
char *strlwr(char *s);
si converteste toate literele mari in litere mici.Restul literelor raman neschimbate, iar functia
intoarce adresa s.
 Functia strupr are forma generala:
char *strupr(char *s);
si converteste toate literele mici in litere mari.Restul literelor raman neschimbate, iar functia
intoarce adresa s.
 Functia strpbrk are forma generala:
char *strpbrk(char *s1, char *s2);
si actioneaza astfel:
 Cauta primul caracter al sirului s1 in s2.Daca este gasit,
returneaza adresa sa din cadrul sirului s1 si executia se termina, altfel trece la pasul urmator.
 Cauta al doilea caracter al sirului s1 in s2.Daca este gasit,
returneaza adresa sa din cadrul sirului s1 si executia se termina, altfel trece la pasul urmator.
 …
 Daca nici un caracter al sirului s1 nu apartine sirului s2, functia returneaza adresa nula.
Urmatoarele functii au prototipul in stdlib.h si folosesc pentru conversia valorilor
numerice in sir si invers.
 Functia atof converteste un sir catre tipul double si are forma generala:
double atof (const char *s);
Daca conversia esueaza (se intalneste un caracter nenumeric), valoarea intoarsa este 0.Daca primele
caractere ale sirului sunt albe, acestea sunt ignorate.
Aceste observatii sunt valabile si pentru urmatoarele 3 functii.
 Functia _atold converteste un sir catre tipul long double:
long double _atold(const char *s);
 Functia atoi converteste un sir catre tipul int:
int atoi(const char *s);
 Functia atol converteste un sir catre tipul int:
long atol(const char *s);

// sa se determine lungimea unui sir de caractere

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{ char a[100];
cin.get(a,100);
cout<<"Sirul citit are "<<strlen (a)<<"caractere";
}
// Se se copieze un sir in alt sir

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{ char a[100]="un sir",b[100]="alt sir";
strcpy (a,b);
cout<<a;
}

// Sa se concaterneze doua siruri


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char a[20]="mama",b[100]="merge";
strcat (a,b);
cout<<a;
}

// Sa se spuna pozitia unde e gasit un caracter


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char a[100], *t,c;
cout<<"Introduceti sirul "; cin.get(a,100);
cout<<"caracterul cautat "; cin>>c;
t=strchr(a,c);
if (t) cout<<"Indicele este "<<t-a;
else cout<<"Sirul nu contine acest caracter ";
}

// Sa se spuna pozitia unde e gasit un caracter si de cate ori e


gasit si pe ce pozitii
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char a[100], *t,c;
cout<<"Introduceti sirul "; cin.get(a,100);
cout<<"caracterul cautat "; cin>>c;
t=a-1;
do
{
t++;
t=strchr(t,c);
if (t) cout<<"Indicele este "<<t-a<<endl;
} while (t);
}

// Sa se spuna care din doua siruri e mai mare ca valoare


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char a[100],b[100];
int semnal;
cout<<"Introduceti sirul a "; cin>>a;
cout<<"Introduceti sirul b "; cin>>b;
semnal=strcmp(a,b);
if (semnal<0) cout<<"a<b";
else
if (semnal>0) cout<<"a>b";
else cout<<"a=b";
}

// Sa se se sorteze alfabetic n cuvinte


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{ char cuvinte[10][25], man[25];
int i,n,gasit;
cout<<"n="; cin>>n;
for (i=0;i<n;i++)
{
cout<<"cuvant ";
cin>>cuvinte[i];
}
do
{ gasit=0;
for (i=0;i<n-1;i++)
if (strcmp(cuvinte[i], cuvinte[i+1])>0)
{
strcpy(man,cuvinte[i]);
strcpy(cuvinte[i],cuvinte[i+1]);
strcpy(cuvinte[i+1],man);
gasit=1;
}
}
while (gasit);
for (i=0;i<n;i++) cout<<cuvinte[i]<<endl;
}

// Sa se determine daca al doilea cuvant e subsir al primului


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{ char sir[1000], subsir[25], *t;
cout<<"Introduceti textul "; cin.get(sir,1000);
cin.get( );
cout<<"Introduceti subsirul cautat "; cin.get(subsir,25);
t=strstr(sir,subsir);
if (t) cout<<"este subsir si are indicele "<<t-sir;
else cout<<"nu este subsir";
}

// Sa se stearga toate aparitiile unui sir intr-un subsir


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char sir[1000], subsir[25], *p;
int lung_subsir;
cout<<"introduceti textul"; cin.get(sir,1000);
cin.get( );
cout<<"introduceti subsirul"; cin.get(subsir,25);
lung_subsir=strlen(subsir);
p=strstr(sir,subsir);
while (p)
{
strcpy(p,p+lung_subsir);
p=strstr(p,subsir);
}
cout<<sir;
}

// Sa se inlociuasca toate aparitiile unui sir intr-un sir cu alt


sir
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char sir[100],man[100],sterg[25],adaug[25],*p;
int lung_sterg,lung_adaug;
cout<<"introduceti textul"; cin.get(sir,100);
cin.get( );
cout<<"inlocuim subsirul"; cin.get(sterg,25);
cin.get( );
cout<<"cu subsirul "; cin.get(adaug,25);
lung_sterg=strlen(sterg);
lung_adaug=strlen(adaug);
p=strstr(sir,sterg);
while (p)
{
man[0]=0; // subsir vid;
strncat(man,sir,p-sir);
strcat(man,adaug);
strcat(man,p+lung_sterg);
strcpy(sir,man);
p=strstr(p+lung_adaug,sterg);
}
cout<<sir;
}

// Sa se afiseze cuvintele dintr-o fraza pe vericala


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char sir[1000],separator[ ]=", ", *p;
cin.get(sir,1000);
p=strtok(sir,separator);
while (p)
{
cout<<p<<endl;
p=strtok(NULL, separator);
}
}

// Sa se eleimine blancurile si virgulele dintr-un sir


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char sir[1000],separator[ ]=", ", *p;
cin.get(sir,1000);
p=strtok(sir,separator);
while (p)
{
cout<<p;
p=strtok(NULL, separator);
}
}

// Sa se determine daca un sir e numare sau alceva


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{ char cuvant[100],cifre[ ]="0123456789";
cout<<"Introduceti cuvantul "; cin>>cuvant;
if (strspn(cuvant,cifre)==strlen(cuvant))
cout<<"numeric";
else cout<<"nenumeric";
}

// Sa se determine daca un sir nu are numere deloc


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{ char cuvant[100],cifre[ ]="0123456789";
cout<<"Introduceti cuvantul "; cin>>cuvant;
if (strcspn(cifre,cuvant)==10) cout<<"corect";
else cout<<"incorect";
}

// Sa se transforme un sir in majuscule


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char a[20];
cout<<"Introduceti cuvantul"; cin>>a;
cout<<strupr(a);
}

// Sa se afisesze toate caracterele dintr-un sir care sunt in alt


sir
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char cuvant1[10],cuvant2[10],*p;
cout<<"Introduceti primul cuvant "; cin>>cuvant1;
cout<<"Introduceti al doilea cuvant "; cin>>cuvant2;
p=strpbrk(cuvant1,cuvant2);
while (p)
{
cout<<p[0]<<endl;
p++;
p=strpbrk(p,cuvant2);
}
}

// Sa se sumeze numerele dintr-o fraza cu numere separate prin


separatori
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char sir[1000],separator[ ]=" ", cifre[ ]="0123456789.+-",
*p;
double s=0;
cin.get(sir,1000);
p=strtok(sir,separator);
while (p)
{
if (strspn(p,cifre)==strlen(p))
s+=atof(p);
p=strtok(NULL, separator);
}
cout<<"suma numerelor intalnite in sir este "<<s;
}

// Sa se transforme un numar real in sir si sa se aproximeze


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
double numar;
int zec,semn;
char numar_sir[20]=" ",numar_prel[20]=" ";
cout<<"n="; cin>>numar;
strcpy(numar_sir,ecvt(numar,19,&zec, &semn));
cout<<"Sirul este "<<numar_sir<<" "<<zec<<" "<<semn<<endl;
if (semn) strcat(numar_prel,"-");
strncat(numar_prel,numar_sir,zec);
strcat(numar_prel,".");
strncat(numar_prel,numar_sir+zec,3);
cout<<numar_prel;
}

// Sa se determine daca un numar e intr-un interval si daca e numar


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main (void)
{
char numar[20], *adresa;
long v;
cin>>numar;
v=strtol(numar,&adresa,10);
if (adresa-numar!=strlen(numar))
cout<<"Data contine caractere nenumerice";
else
if (v<10 || v>20)
cout<<"Data numerica in afara limitei ";
else cout<<v<<endl;
}

FISIERE
Notiunea de fisier
Definitie: Se numeste fisier o colectie de date omogene (adica de acelasi tip), stocate pe
suport extern si accesata printr-un nume, care reprezinta numele fisierului.
Exemple:
1.Programele sub forma executabila sunt memorate pe suport sub forma de fisiere.Acestea se
recunosc dupa extensia numelui, care este .exe sau .com.
2.Programele in format sursa (adica textul introdus de programator) sunt stocate si ele sub
forma de fisiere.Acestea pot fi recunoscute dupa extensia lor .pas pentru surse Pascal si .cpp pentru
surse C++.
3.Informatiile de natura economica sunt memorate, de asemenea, sub forma de
fisier.Informatiile referitoare la un material constituie o inregistrare, iar ansamblul inregistrarilor constituie
fisierul propriu-zis.
In C++ se lucreaza cu doua tipuri de fisiere:
a) Fisiere text;
b) Fisiere binare.
Notiunea de fisier text
Fisierele text se caracterizeaza prin urmatoarele:

 Datele sunt memorate sub forma unei succesiuni de caractere.


 Fiecare caracter este memorat prin utilizarea codului ASCII.
 Un fisier text se termina intotdeauna cu caracterul EOF, care permite ca la prelucrare sa poata
fi identificat sfarsitul fisierului.Daca dorim sa-l introducem de la tastatura, se tasteaza CTRL+Z.
 Fisierul text se considera alcatuit din una sau mai multe linii.O linie, mai putin ultima, se
termina prin caracterul newline (\ n).
 O variabila speciala, numita pointer, retine intotdeauna un octet al fisierului.

Schema unui fisier text este urmatoarea:

M a r iii n \n 1 H EOF

pointer

Orice editor de texte lucreaza cu fisiere text.


Cin si cout sunt doua tipuri speciale de fisiere text, care nu sunt memorate pe suport extern, ci
corespund dispozitivelor standard de intrare, respectiv de iesire.
Fisierul cin este privit ca fiind de intrare, adica fluxul de date este de la el catre memoria
interna.El este asimilat tastaturii, iar programul citeste datele din acest fisier.
Fisierul cout este privit ca unul de iesire, adica fluxul de date este de la memoria interna catre
el.El este asimilat monitorului, iar programul scrie astfel in acest fisier.
Toate scrierile / citirile efectuate in / din aceste fisiere sunt identice cu cele efectuate in / din
fisierele memorate pe suport magnetic.
In fisierele text putem scrie sau citi cu sau fara format.Chiar daca scriem fara format, exista
anumite reguli implicite care trebuie respectate.
Citiri / scrieri cu format
Citirile / scrierile cu format sunt caracterizate de urmatoarele notiuni:
1. Latimea –width- se utilizeaza la scriere si are rolul de a stabili numarul de caractere utilizate
pentru afisarea unei date.
2. Precizia –precision- se utilizeaza la scriere si se foloseste pentru a stabili numarul de
zecimale care vor fi afisate pentru o valoare reala.
3. Caracterul de umplere –fill- se utilizeaza la scriere, in cazul in care data propriu-zisa ocupa
mai putini octeti decat latimea, si precizeaza caracterul care se afiseaza in spatiile neocupate de data.
4. Alinierea se utilizeaza in cazul in care data propriu-zisa ocupa mai putin decat latimea si
precizeaza unde anume sa fie afisata data, la stanga –left- sau la dreapta –right-.
5. Salt sau nu peste caracterele albe.

In limbajul C++ exista biblioteca iostream.h in care sunt definite cateva variabile si constante
cu rol important in efectuarea de citiri / scrieri cu format.Variabilele sunt:
int x_precision;
int x_width;
int x_fill;
long x_flags;

 x_precision retine numarul de zecimale ce vor fi afisate pentru un numar real;


 x_width retine numarul de pozitii pe care se efectueaza afisarea (latimea).Valoarea este
retinuta pana cand se efectueaza prima afisare,dupa care variabila este initializata cu 0;
 x_fill retine caracterul care va fi afisat in cazul in care numarul pozitiilor pe care se face
afisarea este mai mare decat cel al pozitiilor efectiv ocupate de date;
 x_flags retine anumiti parametri pentru formatarea intrarilor / iesirilor, care sunt memorati la
nivel de bit si vor fi analizati in amanunt.Pentru a usura accesul la bit s-au definit constantele:
 skipws=0x0001 - caracterele albe care preced valoarea care trebuie citita sunt sarite;
 left=0x0002 - datele se tiparesc aliniate la stanga;
 right=0x0004 - datele se tiparesc aliniate la dreapta;
 internal=0x0008 - se foloseste la tiparirea semnului unui
numar sau a specificatorului de baza;
 dec=0x0010 - conversie in zecimal;
 oct=0x0020 - conversie in octal;
 hex=0x0040 - conversie in hexazecimal;
 showbase=0x0080 - afisarea indicatorului de baza;
 showpoint=0x0100 -forteaza afisarea punctului zecimal;
 uppercase=0x0200 - in cazul afisarii in hexa, se vor utiliza litere mari;
 showpos=0x0400 - valorile numerice sunt afisate precedate de semn;
 scientific=0x0800 - afisarea valorilor reale se face prin utilizarea formei stiintifice (1e -
8);
 fixed=0x1000 - afisarea valorilor reale se face prin utilizarea formei normale (-
12.45).

Accesul propriu-zis la variabilele respective se face cu ajutorul unor functii speciale, numite
manipulatori.Pentru utilizarea acestora se include fisierul antet iomanip.h.
Exemple de manipulatori:

 setw(int) – stabileste latimea;


 setprecision(int) – stabileste precizia (numarul de zecimale)
 setfill(char) – stabileste caracterul de umplere
 setiosflags(masca) – seteaza bitii din masca
 resetiosflags(masca) – reseteaza bitii din masca

Observatii:

1. De regula, utilizarea manipulatorilor are efect numai asupra primei citiri / scrieri, chiar daca operatia
recpectiva este scrisa in cadrul aceleiasi expresii.Una dintre exceptiile de la aceasta regula este saltul
peste caracterele albe.
2. In cazul in care latimea nu este suficienta, ea este ignorata.
3. Daca numarul de zecimale nu este precizat prin manipulator, atunci se tiparesc cel mult 6 zecimale
(daca valoarea respectiva are 6 zecimale).
4. In cazul in care nu a fost specificat caracterul de umplere, acesta este
blank-ul.
5. Conversia bazelor 8, 10, 16 se poate realiza simplificat prin utilizarea manipulatorilor oct dec hex.

Fisiere text memorate pe suport magnetic

Toate operatiile de citire / scriere efectuate asupra fisierelor cu numele logic cin / cout pot fi
efectuate si asupra fisierelor text memorate pe suport magnetic.
Pentru a putea fi prelucrat, orice fisiere are doua nume:
- un nume logic, folosit in program pentru referirea fisierului;
- un nume fizic, sub care fisierul se afla memorat pe suportul extern
In C++, pentru a putea lucra usor asupra fisierelor sunt definite anumite constante, dupa cum
urmeaza:
 in =0x01 – fisierul se deschide pentru citire;
 out =0x02 – fisierul se deschide pentru scriere;
 ate =0x04 – dupa deschidere, salt la sfarsitul fisierului;
 app =0x08 – deschidere pentru a scrie la sfarsitul fisierului;
 trunc =0x10 – daca fisierul care se deschide exista, in locul sau se creeaza
altul
 nocreate =0x20 – deschide fisierul doar daca acesta exista (nu este permisa crearea lui)
 noreplace =0x40 – daca fisierul exista, el poate fi deschis doar pentru consultare
 binary =0x80 – fisier binar – se utilizeaza constructorul ofstream(), apoi se utilizeaza metoda
open, in forma generala.

Orice program care lucreaza cu fisiere pe suport magnetic trebuie sa includa fisierul antet
fstream
Declararea fisierelor text memorate pe suport
magnetic

Forma generala a unei declaratii de fisier text memorat pe suport magnetic este:
fstream nume_logic(char*nume_fizic,int mod_de_deschidere);
Modul de deschidere (pentru citire, scriere etc) se descrie cu ajutorul constantelor prezentate
anterior si operator.

Observatii:

1. Calea se declara cu doua caractere backslash (\\).Caracterul respectiv este folosit pentru a scrie
secvente escape si, din acest motiv, pentru a fi inclus
intr-un sir de caractere este necesar sa fie scris de doua ori.
2. In anumite cazuri, numele fizic al fisierului trebuie citit de la tastatura.Astfel, avem posibilitatea ca
programul sa prelucreze fisiere cu orice nume fizic.In acest caz, declaratia fisierului trebuie sa contina
adresa vectorului de numere si sa fie plasata dupa citirea sirului respectiv.
Prelucrarea fisierelor text

In general, prelucrarea unui fisier se face dupa urmatoarea schema:

while (daca nu este sfarsit de fisier)


{
citeste
prelucreaza
}

Pentru detectarea sfarsitului de fisier, C++ contine o functie specializata, numita eof( ).Pentru a
preciza fisierul al carui sfarsit se testeaza, functia trebuie precedata de numele logic al fisierului si
punct.In cazul detectarii sfarsitului de fisier, functia returneaza o valoare diferita de 0, altfel returneaza 0.
Exista mai multe functii cu ajutorul carora programatorul poate actiona asupra pointerului dintr-un fisier
de intrare:
 Functia long tellp( ) returneaza pozitia pointerului la un moment dat.Pozitia este relativa la
inceputul fisierului.
 Functia seekp(long, seek_dir) pozitioneaza pointerul.Primul parametru reprezinta pozitia, iar al
doilea reperul in raport de care este calculata pozitia.
In acest sens, au fost definite 3 constante.Pentru accesul la ele se foloseste si de aceasta data ios:
 beg – inceput de fisier;
 cur – pozitia curenta in fisier;
 end – sfarsit de fisier.
Cand stabilim o pozitie aflata in stanga reperului, primul parametru este negativ, iar in dreapta
reperului, parametrul este pozitiv.

Variabila de stare. Controlul erorilor


Orice obiect stream moşteneşte din clasa ios un cuvînt de stare care descrie modul în
care a decurs operaţia precedentă. Aceasta este o variabilă de tip întreg (numită state - stare), ]n
care fiecare bit reprezintă un indicator de eroare. Pentru a facilita accesul la aceşti indicatori, în
clasa ios este declarat tipul enumerare io_state, sub forma :

public:
enum io_state {
goodbit = 0x00, // operatie corecta
eofbit=0x01, // s-a ajuns la sfirsitul fisierului
failbit=0x02, // operatie esuata
badbit=0x04, // operatia a fost nevalida
hardfail=0x80 // eroare irecuperabila
};

Valoarea 1 a unui bit semnifică apariţia erorii respective. Trebuie reţinut că nu mai pot
fi executate operaţii cu un stream pînă cînd condiţia de eroare care eventual a intervenit nu a
fost eliminată şi bitul respectiv de eroare a fost resetat.
Clasa ios şi (firesc!) derivatele sale dispun de funcţii membre care pot citi şi modifica
indicatorii de stare :

int eof() - este nenulă dacă eofbit este 1


int bad() - este nenulă dacă badbit este 1
int fail() - este nenulă dacă failbit este 1
int good() - este nenulă dacă operaţia s-a încheiat fără erori
int rdstate() - întoarce valoarea cuvîntului de stare
void clear(int i=0) - înscrie valoarea parametrului în cuvîntul de stare; valoarea implicită
determină ştergerea indicatorilor de eroare

Exemplu (pentru un stream numit fis) :

fis.clear(); // anuleaza toti indicatorii de eroare



fis.clear(ios::badbit); // pune badbit pe 1 si restul pe 0

fis.clear(ios::failbit | fis.rdstate()); // pune pe 1 failbit
iar
// ceilalti ramin neschimbati

Operatorii () şi ! sînt astfel supradefiniţi încît un stream să poată fi testat ca o variabilă


logică, folosind :

expresia (fis) - are valoarea zero dacă s-au înregistrat erori la operaţia precedentă şi
nenulă dacă
nu a fost eroare
expresia !(fis) - are valoarea !(fis) - invers decît mai sus

Exemplu (reluare) :

while(cin.get( c)) cout.put( c); // copiaza cin la cout , (cin)=0


// la sfirsitul fisierului

Formatarea datelor

De multe ori, programatorul doreşte să formateze datele de intrare/ieşire în modul dorit


de el, fie că o face pentru a prezenta sau introduce datele într-un anumit mod, fie pentru a
structura datele în modul dorit, atunci cînd lucrează cu fişiere. C++ pune la dispoziţia
programatorului un set foarte flexibil şi diversificat de instrumente în acest scop, prin accesul la
variabile pentru controlul formatului, prin manipulatori şi prin funcţii membre.

Variabile pentru controlul formatului


Formatul datelor de intrare/ieşire este controlat de următoarele variabile declarate în
clasa ios :

- cuvîntul de format : long int x_flags


- variabile întregi care determină, pentru operaţiile de ieşire :
- dimensiunea cîmpului de format : int x_width
- caracterul de completare a cîmpului de format : int x_fill (implicit este spaţiu)
- precizia pentru valori în virgulă mobilă (adică numărul de zecimale) : int
x_precision

Cuvîntul de format conţine un număr de indicatori care sînt biţi individuali. Ei pot fi
referiţi folosind un set de indicatori declaraţi în clasa ios, cu valori corespunzătoare poziţiei
bitului în cuvînt :

public:
enum {
skipws =0x0001, // sare peste spatii (intrare)
left =0x0002, // aliniere stinga (iesire)
right =0x0004, // aliniere dreapta (iesire)
internal =0x0008, // completare interna cu spatii,pornind de
la
// un semn sau de la caracterul
bazei(iesire)
dec =0x0010, // conversie zecimala
oct =0x0020, // conversie octala
hex =0x0040, // conversie hexa
showbase =0x0080, // afisarea bazei in care este convertit
// numarul (iesire)
showpoint =0x0100, // afisarea punctului zecimal si a
zerourilor
// finale - chiar fara semnificatie (iesire)
uppercase =0x0200, // afisare hexa cu litere mari (iesire)
showpos =0x0400, // determina afisarea “+” pentru numere
// pozitive (altfel nu se afiseaza nimic)
scientific =0x0800, // afisarea numerelor reale in format cu
// exponent - format stiintific (iesire)
fixed =0x1000, // numere reale in format cu punct fix,
// implicit cu 6 zecimale
unitbuf =0x2000, // bufferul este golit dupa fiecare iesire
stdio =0x4000 // la fel dupa scriere in stdout sau stderr
};

Se pot de asemenea indica trei cîmpuri de biţi :

adjustfield - conţine biţii left, right şi internal, care specifică modul de aliniere în spaţiul
alocat afişării
basefield - conţine biţii dec, oct şi hex care precizează baza de reprezentare a unei valori
întregi
floatfield - conţine biţii scientific şi fixed care specifică modul de reprezentare a valorilor în
virgulă mobilă.

În cîmpurile de biţi enumerate mai sus, doar cîte un bit poate fi activ (adică =1).
Indicatorii prezentaţi au valori implicite pentru afişări în formatele cele mai uzuale
(de exemplu numărul de spaţii alocat este cel minim necesar, alinierea se face la stînga, valorile
întregi se afişează în zecimal, fără indicarea bazei iar cele în virgulă mobilă sînt în format cu
punct zecimal).
Modificarea indicatorilor de format se realizează cu ajutorul unor funcţii membre ale
claselor stream sau a unor operatori numiţi manipulatori.

Manipulatori

Orice manipulator primeşte ca parametru şi întoarce ca rezultat adresa stream-ului


asupra căruia acţionează, astfel încît pot fi inseraţi în cadrul expresiilor de intrare/ieşire. În
funcţie de prezenţa sau lipsa unui parametru suplimentar cu rol de control al formatării, se
disting două categorii :

1. Manipulatorii fără parametri - sînt operatori care pot fi folosiţi în expresii de


intrare/ieşire cu sintaxa :
out << manipulator
sau
in >> manipulator
unde in şi out sînt fluxuri de intrare sau de ieşire, oarecare. În continuare este dată
lista de manipulatori fără parametri :

dec - activeaza bitul dec (intrare/iesire)


hex - activeaza bitul hex (intrare/iesire)
oct - activeaza bitul oct (intrare/iesire)
ws - activeaza bitul skipws (intrare)
endl - insereaza caracterul “\n” si goleste bufferul (iesire)
ends - insereaza caracterul “\0” (iesire)
flush - goleste tamponul (iesire)

Exemplu :

int i=127, j=1023;


cout << i << “=”<<hex << i << endl;
cout <<dec << j << “=” << hex << j << endl;
cout << i << endl;

Programul va afişa :

127=7f
1023=7ff
7f

Reţinem din exemplul prezentat că iniţial indicatorul de bază implicit a fost dec=1
(deci reprezentarea zecimală) iar după o modificare, se menţine pînă la următoarea operată
de programator (spre exemplu, în ultima linie, i este afişat în hex, ca şi la precedenta operaţie de
afişare).
Programatorul poate defini şi alţi manipulatori fără parametri, folosind declaraţii de
tipul:
istream& nume_manipulator(istream&);
ostream& nume_manipulator(ostream&);

Astfel, în exemplul următor, este definit un manipulator pentru operaţii de intrare care
afişează un mesaj “prompter” - de invitaţie :
istream& prompt(istream& in)
{
in >> hex;
cout << “Introduceti valoarea adresei (hexa) : “;
return in;
}

main()
{

cin >> prompt >> adr; // utilizarea manipulatorului definit mai sus
}

2. Manipulatorii cu parametri - sînt declaraţi în fişierul antet iomanip.h şi pot fi


utilizaţi în expresii de intrare/ieşire cu sintaxa :

out << manipulator(parametru);


in >> manipulator(parametru);

Aceşti manipulatori sînt funcţii cu prototipul de forma :

istream& nume_manip(parametru)
ostream& nume_manip(parametru)

Iată în continuare lista de manipulatori parametrici :

- setbase(int n) - stabileşte baza de numeraţie la n= 8, 10 sau 16


- resetioflags(long ) - pune pe 0 în biţii specificaţi în argument
- setioflags(long ) - pune pe 1 biţii specificaţi în argument
- setfill(int ) - defineşte caracterul de umplere
- setprecision(int ) - stabileşte precizia pentru numerele reale
- setw(int ) - stabileşte dimensiunea cîmpului de format pentru operaţia
următoare

Crearea unor manipulatori cu parametri de către programator este posibilă, dar printr-o
procedură mai complicată.
Controlul formatului folosind funcţii membre

Există un set de funcţii membre în ios care oferă alternative pentru controlul
formatului:

long setf(long ) - activează indicatorii de format specificaţi de argument (fără a modifica alţi
biţi) şi întoarce valoarea anterioară a cuvîntului de control al formatului. Exemplu :

stare = in.setf(ios::showbase | ios::hex) ;

Funcţia este supradefinită cu o variantă cu prototipul :

long setf(long, long) - care activează indicatorul specificat de primul argument în cadrul
cîmpului selectat de al doilea argument. Ceilalţi biţi ai cîmpului sînt dezactivaţi, iar
restul
cuvîntului de format nu se modifică. Funcţia întoarce valoarea anterioară a cîmpului.
Exemplu :

stare_baza=out.setf(ios::hex, ios::basefield); // schimbarea bazei


// (dar se retine baza precedenta in stare_baza)

out.setf(stare_baza, ios::basefield); // revenire la baza veche

long unsetf(long ) - dezactivează (anulează) indicatorii specificaţi de argument şi întoarce


valoarea anterioară a cuvîntului de format

char fill() - întoarce caracterul de umplere curent; este supradefinită cu varianta :

char fill(char ) - care modifică valoarea caracterului de umplere cu valoarea parametrului şi


întoarce valoarea anterioară

int precision() - întoarce valoarea curentă a preciziei; este supradefinită cu varianta:

int precision(int ) - care modifică valoarea curentă a preciziei şi întoarce valoarea sa


precedentă

int width() - întoarce valoarea actuală a dimensiunii cîmpului de afişare; este supradefinită
cu:

int width(int ) - care modifică dimensiunea cîmpului conform argumentului şi întoarce


valoarea anterioară.

//SA SE scrie trei fraze pe verticala intr-un fisier

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;

int main() {
char filename[81];

cout << "Enter a file name and press ENTER: ";


cin.getline(filename, 80);
ofstream f(filename);
if (! f) {
cout << "File " << filename << " could not be opened.";
return -1;
}
cout << "File " << filename << " was opened.";
f << "I am Blaxxon," << endl;
f << "the cosmic computer." << endl;
f << "Fear me.";
f.close();
return 0;
}
//SA SE scrie trei fraze pe verticala intr-un fisier
// acei cale se da de la tastatura

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;

int main() {
char filename[81];
char path[81];

cout << "Enter directory path: "; // Prompt for path


cin.getline(path, 80);

cout << "Enter a file name and press ENTER: ";


cin.getline(filename, 80);

strncat(path, filename, strlen(path) - 80); // concatenate

ofstream file_out(path); // Use path string to open


if (! file_out) {
cout << "File " << filename << " could not be opened.";
return -1;
}
cout << "File " << filename << " was opened.";
file_out << "I am Blaxxon," << endl;
file_out << "the cosmic computer." << endl;
file_out << "Fear me.";
file_out.close();
return 0;
}

//SA SE scrie intr-un fisier fraze pana cand la un moment dat se dau
trei caractere adica @@@

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;

int main() {
char filename[81];
char input_line[81]; // Input line for text entry
cout << "Enter a file name and press ENTER: ";
cin.getline(filename, 80);

ofstream file_out(filename);
if (! file_out) {
cout << "File " << filename << " could not be opened.";
return -1;
}
cout << "File " << filename << " was opened." << endl;
while (1) {
cout << "Enter line (@@@ to quit)>>";
cin.getline(input_line, 80);
if (strcmp(input_line, "@@@") == 0)
break;
file_out << input_line << endl;
}
file_out.close();
return 0;
}

//SA SE citeasca dintr-un fisier fraze pana cand la un moment dat se


da Q sau q

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;

int main() {
int c; // input character
int i; // loop counter
char filename[81];
char input_line[81];

cout << "Enter a file name and press ENTER: ";


cin.getline(filename, 80);

ifstream file_in(filename);

if (! file_in) {
cout << "File " << filename << " could not be opened.";
return -1;
}

while (1) {
for (i = 1; i <= 24 && ! file_in.eof(); i++) {
file_in.getline(input_line, 80);
cout << input_line << endl;
}
if (file_in.eof())
break;
cout << "More? (Press 'Q' and ENTER to quit.)";
cin.getline(input_line, 80);
c = input_line[0];
if (c == 'Q' || c == 'q')
break;
}
return 0;
}

// Exercitiul 8.2.1.txt
// Acest program afiseaza N linii din fisierul de text la un anumit
moment de timp ales;
// utilizatorul poate renunta sau poate specifica o noua valoare
pentru N.

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;

int main() {
int c; // input character
int i; // loop counter
char filename[81];
char input_line[81];

cout << "Enter a file name and press ENTER: ";


cin.getline(filename, 80);

ifstream file_in(filename);

if (! file_in) {
cout << "File " << filename << " could not be opened.";
return -1;
}

int lines_to_read = 20; // Number of lines to read; default =


20

while (1) {
for (i = 1; i <= lines_to_read && ! file_in.eof(); i++) {
file_in.getline(input_line, 80);
cout << input_line << endl;
}
if (file_in.eof())
break;
cout << "More? (Press 'Q' and ENTER to quit, or # lines to
print.)>";
cin.getline(input_line, 80);
c = input_line[0];
if (c == 'Q' || c == 'q')
break;
else if (strlen(input_line) > 0) // If user input
something
lines_to_read = atoi(input_line); // set new value of
lines_to_read
}
return 0;
}

// Exercitiul 8.2.1.txt
//listarea unui fisier

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;

#include <iostream>
#include <fstream>
#include <string.h>
using namespace std;

int main(int argc, char *argv[]) {


int c; // input character
int i; // loop counter
char filename[81];
char input_line[81];

if (argc > 1)
strncpy(filename, argv[1], 80);
else {
cout << "Enter a file name and press ENTER: ";
cin.getline(filename, 80);
}

ifstream file_in(filename);

if (! file_in) {
cout << "File " << filename << " could not be opened.";
return -1;
}

while (1) {
for (i = 1; i <= 24 && ! file_in.eof(); i++) {
file_in.getline(input_line, 80);
cout << input_line;
}
if (file_in.eof())
break;
cout << endl << "More? (Press 'Q' and ENTER to quit.)";
cin.getline(input_line, 80);
c = input_line[0];
if (c == 'Q' || c == 'q')
break;
}
return 0;
}
// nu sunt sarite caracterele albe citite de la tastatura.
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis.txt",ios::out);
char ch;
while (cin>>resetiosflags(ios::skipws)>>ch) f<<ch;
f.close( );
}

// Exercitiul 8.2.1.txt
//scrierea intr-un fisier dar fara spatii in fraza

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis.txt",ios::out);
char ch;
while (cin>>ch) f<<ch;
f.close( );
}

//listarea unui fisier fara spatiile dintre cuvinte

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis.txt",ios::in);
char ch;
while (f>>ch) cout<<ch;
f.close( );
}

//listarea unui fisier fara spatii dintre cuvinate

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis.txt",ios::in);
char ch;
while (f>>resetiosflags(ios::skipws)>>ch) cout<<ch;
f.close( );

//copierea dintr-un fisier in altul

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis.txt",ios::in),g("c:\\fis1.txt",ios::out);
char ch;
while (f>>resetiosflags(ios::skipws)>>ch) g<<ch;
f.close( );
}

//scrierea intr-un fisier a numerelor in baza 16 dar care nu depasesc


5 cifre

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis2.txt",ios::out);
int i;
for (i=1;i<=100;i++)
f<<setw(5)<<hex<<i<<endl;
f.close( );
}

//scrierea dintr-un fisier a numerelor in baza 16 dar care se


afisesaza sunt in baza 10

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis2.txt",ios::in);
int i;
while (f>>hex>>i)cout<<dec<<i<<endl;
f.close( );
}

//scrierea intr-un fisier a a primelor 4 caractere

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis.txt",ios::in | ios::out);
char cuvant[10];
f>>cuvant;
cout<<cuvant;
f.seekp(0,ios::beg);//ma plasez fata de inceputul fisierului
la pozitia zero
strcpy(cuvant, "tata");
f<<cuvant;
f.close( );
}

//afisarea dintr-un fisier

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis.txt",ios::in);
char linie [100];
while (f.get(linie,100))
{
cout<<linie<<endl;
f.get( );
}
}

//crearea unui buffer si listarea lui


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

int main()
{
char fileName[80];
char buffer[255]; // for user input
cout << "File name: ";
cin >> fileName;

ofstream fout(fileName); // open for writing


fout << "This line written directly to the file...\n";
cout << "Enter text for the file: ";
cin.ignore(1,'\n'); // eat the newline after the file name
cin.getline(buffer,255); // get the user's input
fout << buffer << "\n"; // and write it to the file
fout.close(); // close the file, ready for reopen

ifstream fin(fileName); // reopen for reading


cout << "Here's the contents of the file:\n";
char ch;
while (fin.get(ch))
cout << ch;

cout << "\n***End of file contents.***\n";

fin.close(); // always pays to be tidy


return 0;
}
//adaugarea intr-un buffer si listarea lui
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

int main() // returns 1 on error


{
char fileName[80];
char buffer[255];
cout << "Please re-enter the file name: ";
cin >> fileName;

ifstream fin(fileName);
if (fin) // already exists?
{
cout << "Current file contents:\n";
char ch;
while (fin.get(ch))
cout << ch;
cout << "\n***End of file contents.***\n";
}
fin.close();

cout << "\nOpening " << fileName << " in append mode...\n";

ofstream fout(fileName,ios::app);
if (!fout)
{
cout << "Unable to open " << fileName << " for appending.\
n";
return(1);
}

cout << "\nEnter text for the file: ";


cin.ignore(1,'\n');
cin.getline(buffer,255);
fout << buffer << "\n";
fout.close();

fin.open(fileName); // reassign existing fin object!


if (!fin)
{
cout << "Unable to open " << fileName << " for reading.\n";
return(1);
}
cout << "\nHere's the contents of the file:\n";
char ch;
while (fin.get(ch))
cout << ch;
cout << "\n***End of file contents.***\n";
fin.close();
return 0;
}

//afisarea dintr-un fisier a numerelor dintr-un interval dat

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis2.txt",ios::in);
int i,j;
char ch;
cout<<"i=";cin>>i;
cout<<"j=";cin>>j;
// pozitionez pointerul direct pe octetul i
f.seekp(i,ios::beg);
// atat timp cat pointerul este mai mic sau egal cu j
while (f.tellp( )<=j)
{
f>>ch;
cout<<ch;
}
f.close( );
}

Fisiere binare
Caracteristicile fisierelor binare sunt:

 Fisierele binare sunt alcatuite din mai multe inregistrari de acelasi tip.
Din acest motiv, aceste fisiere se mai numesc si cu tip.
Exemple:
 inregistrarile sunt de tip int;
 inregistrarile sunt de un tip descris cu struct.
 Datele sunt memorate in format intern.De exemplu, daca inregistrarea este de tip int, datele sunt
memorate in cod complementar.
 Fisierele binare se termina cu EOF, ca si cele text.

Observatie:Tot ce s-a studiat la fisierele text ramane valabil si pentru fisierele binare!
Observatii:

 Intrucat lucram cu un fisier binar, il deschidem cu parametrul respectiv, binary.


 Dupa citirea variabilei p urmeaza scrierea acesteia in fisier.Pentru aceasta, se foloseste functia
write, care scrie n caractere ale unui sir si nu insereaza caracterul nul.Ea are forma:
write (char*nume,int n);
 “Pacalim” calculatorul sa scrie, de fapt, continutul varabilei p.Adresa de inceput a variabilei p o
convertim catre un sir de caractere prin utilizarea operatorului de conversie explicita.Numarul de
caractere care trebuie scrise este dat de lungimea variabilei p.In acest moment, calculatorul “crede”
ca scrie un sir de caractere.Daca e sir de caractere, nu este cazul sa faca conversiile necesare, dar
el preia informatia in format intern si o scrie asa!
In prelucrarea fisierelor binare se folosesc urmatorii termeni:

 Creare – initial fisierul nu exista, dar dupa executia programului, acesta se va gasi pe
suport.Intrarile sunt de la tastatura sau din alte fisiere.
 Exploatare – utilizarea fisierului pentru a extrage informatii din el.In urma exploatarii, fisierul
ramane nemodificat.
 Actualizare – aducerea la zi a fisierului.Aceasta se face in trei feluri:

1) stergere – se sterg anumite inregistrari ale sale.In C++ nu exisat functii care permit ca
aceasta operatiune sa se faca direct.Din acest motiv, in practica sunt folosite doua
metode:

a)
stergere fizica – se creeaza alt fisier cu inregistrarile din primul fisier care nu se
sterg.Apoi primul fisier se sterge, iar cel proaspat creat este “rebotezat” cu
numele celui care a fost sters.
b) stergere logica – fiecare inregistrare are un camp care precizeaza daca ea a
fost stearsa logic sau nu.Toate programele de prelucrare tin cont de ea, in sensul
ca daca a fost stearsa logic, inregistrarea nu mai intra in prelucrare.Pentru a nu
retine date inutile, din cand in cand, inregistrarile sterse logic sunt sterse fizic.
2) modificare – in urma prelucrarii unei inregistrari (sau mai multor inregistrari), se modifica
anumite campuri.
3) adaugare – se adauga la sfarsitul fisierului alte inregistrari.
//Sa se creeze si listeze un fisier binary care ia date dintr-o clasa
//adaugarea intr-un buffer si listarea lui
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

class Animal
{
public:
Animal(int weight, long
days):itsWeight(weight),itsNumberDaysAlive(days){}
~Animal(){}

int GetWeight()const { return itsWeight; }


void SetWeight(int weight) { itsWeight = weight; }

long GetDaysAlive()const { return itsNumberDaysAlive; }


void SetDaysAlive(long days) { itsNumberDaysAlive = days; }

private:
int itsWeight;
long itsNumberDaysAlive;
};

int main() // returns 1 on error


{
char fileName[80];
char buffer[255];

cout << "Please enter the file name: ";


cin >> fileName;
ofstream fout(fileName,ios::binary);
if (!fout)
{
cout << "Unable to open " << fileName << " for writing.\n";
return(1);
}

Animal Bear(50,100);
fout.write((char*) &Bear,sizeof Bear);

fout.close();

ifstream fin(fileName,ios::binary);
if (!fin)
{
cout << "Unable to open " << fileName << " for reading.\n";
return(1);
}

Animal BearTwo(1,1);

cout << "BearTwo weight: " << BearTwo.GetWeight() << endl;


cout << "BearTwo days: " << BearTwo.GetDaysAlive() << endl;

fin.read((char*) &BearTwo, sizeof BearTwo);

cout << "BearTwo weight: " << BearTwo.GetWeight() << endl;


cout << "BearTwo days: " << BearTwo.GetDaysAlive() << endl;
fin.close();
return 0;

//punerea datelor dintr-o structura intr-un fisier binar


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

struct persoana
{
char nume[30];
int varsta;
};
main( )
{
fstream f("pers.dat",ios::out | ios::binary);
persoana p,*adr_p=&p;
char x;
int n,i;
cout<<"Care este numarul de persoane ";cin>>n;
cin.get( );
for(i=0;i<n;i++)
{
cout<<"Numele ";cin.get(p.nume,30);cin.get(x);
cout<<"Varsta ";cin>>p.varsta;cin.get(x);
f.write((char*)adr_p,sizeof p);
}
f.close( );
}
//citirea datelor dintr-un fisier binar
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

struct persoana
{
char nume[30];
int varsta;
};
main( )
{
persoana p, *adr_p=&p;
fstream g("pers.dat",ios::in | ios::binary);
while (g.read((char*)adr_p,sizeof(p)))
cout<<p.nume<<" "<<p.varsta<<endl;
g.close( );
}
//adaugari intr-un fisier binary
//citirea datelor dintr-un fisier binar
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

struct persoana
{
char nume[30];
int varsta;
};
main( )
{
fstream f("pers.dat",ios::app | ios::binary);
persoana p,*adr_p=&p;
char x;
int n,i;
cout<<"Care este numarul de persoane ";cin>>n;
cin.get( );
for(i=0;i<n;i++)
{
cout<<"Numele ";cin.get(p.nume,30);cin.get(x);
cout<<"Varsta ";cin>>p.varsta;cin.get(x);
f.write((char*)adr_p,sizeof p);
}
f.close( );
}
//modidficarea datelor dintr-un fisier binar
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

struct persoana
{
char nume[30];
int varsta;
};
main( )
{
int i;
cout<<"care inregistrare o modific (1..n) ?";cin>>i;
persoana p,*adr_p=&p;
fstream g("pers.dat",ios::in | ios::out | ios::binary);
g.seekp((i-1)*sizeof(p),ios::beg);
g.read((char*)adr_p,sizeof(p));
cout<<"varsta ";cin>>p.varsta;
g.seekp((i-1)*sizeof(p),ios::beg);
g.write((char*)adr_p,sizeof(p));
g.close( );
}
FUNCTII SI PROCEDURI

O functie este alcatuita din:


-antet_tip nume(lista parametrii formali);
-o instructiune compusa_aceasta cuprinde declaratiile variabilelor locale,
si instructiunile propriu zise.
 Parametrii care se găsesc în antetul funcţiei se numesc parametrii formali.
Atunci când scriem o funcţie nu cunoaştem valoarea propriu-zisă a parametrilor. Funcţia
trebuie să întoarcă rezultatul corect, oricare ar fi valoarea lor. Din acest punct de vedere
ei se numesc formali.

 Parametrii care se utilizează la apel se numesc parametrii efectivi.

La apel, lucrurile stau altfel: valorile acestora sunt cunoscute. Prin urmare aceştia se
cunosc parametrii efectivi.
 Vizibilitatea – precizează liniile textului sursă din care variabila respectivă poate
fi accesată. Astfel avem:

a. Vizibilitate la nivel de bloc (instrucţiune compusă);


b. Vizibilitatea la nivel de fişier – în cazul în care programul ocupă un singur
fişier sursă, singurul caz pe care îl tratăm acum.
c. Vizibilitatea la nivel de clasă – este în legătură cu programarea pe obiecte.
 Durata de viaţă – reprezintă timpul în care variabila respectivă are alocat spaţiu
în memoria internă. Astfel avem:

a. Durata statică – variabila are alocat spaţiu în tot timpul execuţiei


programului.
b. Durata locală - variabila are alocat spaţiu în timpul în care se execută
instrucţiunile blocului respectiv.
c. Durata dinamică – alocarea şi dezalocarea spaţiului necesar variabilei
respective se face de către programator prin operatori sau funcţii speciale.
Variabile globale se declară în afara corpului oricărei funcţii.
La declarare, variabilele globale sunt iniţializate cu 0.
Variabile locale sunt declarate în corpul funcţiilor. Mai precis, pot fi declarate în orice
bloc (instrucţiune compusă) al acestora.

// Se citeste n ,nr natural.sa se scrie programele care


//tiparesc valoarea calculata a expresiilor:
//E1=1+1/2+1/3+…+1/n;

#include "stdafx.h"
#include<iostream>
using namespace std;
double subp(int n)
{
double s=0.0;int I;
for (I=1;I<=n;I++) s+=1.0/I;
return s;
}
main()
{
int n;
cout<<"n=";cin>>n;
cout<<subp(n);
}
// Se citeste n ,nr natural.sa se scrie programele care
//tiparesc valoarea calculata a expresiilor:
//E1=1+1/2+1/3+…+1/n;

// Se citeste n ,nr natural.sa se scrie programele


//care tiparesc valoarea calculata a expresiilor:
//E1=1+1/2+1/3+…+1/n si
// E2=(1+1/2+1/3+…+1/n) la puterea n

#include "stdafx.h"
#include<iostream>
using namespace std;

double subp(int n)
{
double s=0.0;
int I;
for (I=1;I<=n;I++) s+=1.0/I;// sau s=s+1/I
return s;
}
main()
{
int n,I;
double rez,prod=1;
cout<<"n=";cin>>n;
rez=subp(n);
for (I=1;I<=n;I++) prod*=rez;
cout<<prod;
}
//sa se sorteze un vector

#include "stdafx.h"
#include<iostream>
using namespace std;

void citesc(int vt[10],int n)


{
int I;
for(I=0;I<n;I++)
{
cout<<"vt["<<I+1<<"]=";cin>>vt[I];
}
}
void sortez(int vt[10],int n)
{
int gasit,I,man;
do
{
gasit=0;
for (I=0;I<=n-1;I++)
if (vt[I]>vt[I+1])
{
man=vt[I];vt[I]=vt[I+1];
vt[I+1]=man;
gasit=1;
}
} while(gasit);
}
void scriu(int vt[10],int n)
{
int I;
for (I=0;I<n;I++)
cout<<vt[I]<<endl;
}
main()
{
int vt[10],n;
cout<<"n=";cin>>n;
citesc(vt,n);
sortez(vt,n);
scriu(vt,n);
}
//sa se INTRODUCA CU AJUTORUL UNOR STRUCTURI O MATRICE CU FUNCTII

#include "stdafx.h"
#include<iostream>
using namespace std;

struct mat
{
float matrice[6][8];
};
mat cit(int m,int n)
{
mat a;
int I,j;
for (I=0;I<m;I++)
for (j=0;j<n;j++) cin>>a.matrice[I][j];
return a;
};
main()
{
int I,j;
mat mtr=cit(3,2);
for (I=0;I<3;I++)
for (j=0;j<2;j++) cout<<mtr.matrice[I][j]<<" ";

Nu este obligatoriu ca numele parametriilor formali sa coincida cu


numele parametriilor efectivi.
Exista doua mecanisme de transmitere a parametrilor: prin valoare si
prin referinta.
Se pot transmite prin valoare:
1)valorile retinute de variabile
2)expresii
3)Parametri efectivi trebuie sa fie numele variabilelor
}
//sa se dea un exemplu prin care sa se transmita
//parametrii prin valoare si ca in cazul in care
//parametrii actuali sunt reali si ei erau intregi ca
//parametrii formali se ia partea intreaga a lor

#include "stdafx.h"
#include<iostream>
using namespace std;
int suma(int a,int b)
{ return a+b;
}
main()
{ int c=4,d=3;
cout<<suma(2,3)<<endl;
cout<<suma(2+7,3-1*2)<<endl;
cout<<suma(c,d)<<endl;
cout<<suma(1.9,3.3)<<endl;
}
//sa se dea un exemplu prin care sa se transmita
//parametrii prin valoare adica in programul principal
//variabila nu a fost schimbata

#include "stdafx.h"
#include<iostream>
using namespace std;

void test(int n)
{ n+=1;
cout<<n<<endl;
}
main()
{ int n=1;
test(n);
cout<<n<<endl;
}
//parametrii actuali pot fi expresii care mai intai se evalueaza

#include "stdafx.h"
#include<iostream>
using namespace std;

void test( int n)


{ cout<<n<<endl;
}
main()
{ test(3);
test(3+4*5);
}
A defini un subprogram inseamna a-l scrie efectiv,problema fiind locul unde se defineste
subprogramul.
A declara un subprogram inseamna a-l anunta.Definitia unui subprogram tine loc si de
declaratie.
//sa se scrie o functie care aduna doua numere
#include "stdafx.h"
#include<iostream>
using namespace std;
int Add (int x, int y)
{

cout << "In Add(), received " << x << " and " << y << "\n";
return (x+y);
} int main()
{
cout << "I'm in main()!\n";
int a, b, c;
cout << "Enter two numbers: ";
cin >> a;
cin >> b;
cout << "\nCalling Add()\n";
c=Add(a,b);
cout << "\nBack in main().\n";
cout << "c was set to " << c;
cout << "\nExiting...\n\n";
return 0;
}
//imbricarea subprogramelor unul in altul

#include "stdafx.h"
#include<iostream>
using namespace std;

void s1()
{ cout<<"eu sunt s1"<<endl;
}
void s2()
{ s1();
cout<<"eu sunt s2"<<endl;
}
main()
{ s1();s2();
}
//imbricarea subprogramelor unul in altul dar primul
//sa fie declarat in prealabil

#include "stdafx.h"
#include<iostream>
using namespace std;
void s2();
void s1()
{
s2();
cout<<"eu sunt s1"<<endl;
}
void s2()
{ cout<<"eu sunt s2"<<endl;
}
main()
{ s1();
}
//sa se determine cel mai mare divizor comun si cel
//mai mic multiplu comun

#include "stdafx.h"
#include<iostream>
using namespace std;
int cmmdc(int m,int n)
{ while( m!=n)
if (m>n) m-=n;
else n-=m;
return m;
}
main()
{ int cm,m,n;
cout<<"m=";cin>>m;
cout<"n=";cin>>n;
cm=cmmdc(m,n);
cout<<cm<<"cel mai mare multiplu comun este "<<m*n/cm;
}
//sa se determine cel mai mare divizor comun a n numere

#include "stdafx.h"
#include<iostream>
using namespace std;
int v[9],n;
int cmmdc(int m,int n)
{ while (m!=n)
if (m>n) m-=n;
else n-=m;
return m;
}
main()
{ int I,cm;
cout<<"n=";cin>>n;
for (I=0;I<=n;I++) cin>>v[I];
cm=cmmdc(v[0],v[1]);
for (I=2;I<n;I++) cm=cmmdc(cm,v[I]);
cout<<cm;
}
//sa se determine toate polindroamele dintr-un interval

#include "stdafx.h"
#include<iostream>
using namespace std;

int palin( int I)


{int isalv=I,iinv=0;
while(I)
{iinv=iinv*10+I%10;
I=I/10;
}
return isalv==iinv;
}
main()
{ int m,n,I;
cout<<"m=";cin>>m;
cout<<"n=";cin>>n;
for (I=m;I<n;I++)
if (palin(I)) cout<<I<<endl;
}
//sa se determine toate polindroamele dintr-un interval
//care au si patratele tot polindromice

#include "stdafx.h"
#include<iostream>
using namespace std;

long palin( long I)


{ long isalv=I,iinv=0;
while(I)
{ iinv=iinv*10+I%10;
I=I/10;
}
return isalv==iinv;
}
main()
{ long m,n,I;
cout<<"m=";cin>>m;
cout<<"n=";cin>>n ;
for (I=m;I<n;I++)
if (palin(I)) cout<<I<<" "<<I*I<<endl;
}

//Suma cuburilor cifrelor.

#include "stdafx.h"
#include<iostream>
using namespace std;

int seria[1000],n,ind,I,gasit;
int suma(int n)
{ int s=0,c;
while (n)
{ c=n%10;
s+=c*c*c;
n/=10;
}
return s;
}
main()
{
cout<<"n=";cin>>n;
ind=1;seria[ind]=n;
do
{ seria[++ind]=suma(seria[ind-1]);
for (I=1;I<ind;I++)
if (seria[I]==seria[ind]) gasit=1;
}
while (!gasit);
cout<<"lungimea este "<<ind<<endl;
for (I=1;I<=ind;I++) cout<<seria[I]<<endl;
}
//sa se afiseze
// 1
// 23
// 456

#include "stdafx.h"
#include<iostream>
using namespace std;

int succ(int k)
{ if (k==9) return 1;
else return k+1;
}
void tipar(int m,int n)
{int I,j,s=n;
for(I=1;I<=m;I++)
{for (j=1;j<=I;j++)
{cout<<s;
s=succ(s);
}
cout<<endl;
}
}
main()
{int m,n;
cout <<"m=";cin>>m;
cout <<"n=";cin>>n;
tipar (m,n);
}

//sa se afiseze numerele care au numar egal de zerouri cu unu-ri in


// baza 2

#include "stdafx.h"
#include<iostream>
using namespace std;

int valabil (int nr)


{int zero=0,unu=1;
while(nr)
{if (nr%2)unu ++;
else zero++;
nr=nr/2;
}
return zero==unu;
}
main()
{int n,I,s=0;
cout<<"n=";cin>>n;
for (I=1;I<=n;I++)
if(valabil(I)) s++;
cout<<s;
}
//sa se supraincarce o functie
#include "stdafx.h"
#include<iostream>
using namespace std;

void functia(int n)
{ cout<<"eu sunt functia cu un parametru de tip int"<<endl;
}
void functia(int n,int m)
{cout<<"eu sunt functia cu doi parametrii de tip int"<<endl;
}
void functia (int * n)
{cout <<"eu sunt functia cu un parametru de tip int*"<<endl;
}
main()
{functia(2);functia(3,5);
int n;
functia(&n);
}
//SA SE DETERMINE O FUNCTIE CARE RETURNEAZA PRODUSUL A DOUA NUMERE
#include "stdafx.h"
#include<iostream>
using namespace std;
typedef unsigned short USHORT;

USHORT FindArea(USHORT length, USHORT width); //function prototype

int main()
{
USHORT lengthOfYard;
USHORT widthOfYard;
USHORT areaOfYard;

cout << "\nHow wide is your yard? ";


cin >> widthOfYard;
cout << "\nHow long is your yard? ";
cin >> lengthOfYard;

areaOfYard= FindArea(lengthOfYard,widthOfYard);

cout << "\nYour yard is ";


cout << areaOfYard;
cout << " square feet\n\n";
return 0;
}

USHORT FindArea(USHORT l, USHORT w)


{
return l * w;
}
//SA SE DETERMINE O FUNCTIE CARE RETURNEAZA CONVERSIA DIN GRADE
CELSIUS IN Fahrenheit
#include "stdafx.h"
#include<iostream>
using namespace std;
float Convert(float);
int main()
{
float TempFer;
float TempCel;

cout << "Please enter the temperature in Fahrenheit: ";


cin >> TempFer;
TempCel = Convert(TempFer);
cout << "\nHere's the temperature in Celsius: ";
cout << TempCel << endl;
return 0;
}
float Convert(float TempFer)
{
float TempCel;
TempCel = ((TempFer - 32) * 5) / 9;
return TempCel;
}

//SA SE DETERMINE O FUNCTIE CARE RETURNEAZA CONVERSIA DIN GRADE


CELSIUS IN Fahrenheit
#include "stdafx.h"
#include<iostream>
using namespace std;
float Convert(float);
int main()
{
float TempFer;
float TempCel;

cout << "Please enter the temperature in Fahrenheit: ";


cin >> TempFer;
TempCel = Convert(TempFer);
cout << "\nHere's the temperature in Celsius: ";
cout << TempCel << endl;
}

float Convert(float Fer)


{
float Cel;
Cel = ((Fer - 32) * 5) / 9;
return Cel;
}

//SA SE DETERMINE O procedura prin care se pun in evidenta


variabilele locale si globale
#include "stdafx.h"
#include<iostream>
using namespace std;
void myFunction(); // prototype

int x = 5, y = 7; // global variables


int main()
{

cout << "x from main: " << x << "\n";


cout << "y from main: " << y << "\n\n";
myFunction();
cout << "Back from myFunction!\n\n";
cout << "x from main: " << x << "\n";
cout << "y from main: " << y << "\n";
return 0;
}

void myFunction()
{
int y = 10;
//Y VARIABILA LOCALA
cout << "x from myFunction: " << x << "\n";
cout << "y from myFunction: " << y << "\n\n";
}
//SA SE DETERMINE O procedura prin care se pun in evidenta
variabilele locale si globale
#include "stdafx.h"
#include<iostream>
using namespace std;
void myFunc();

int main()
{
int x = 5;
cout << "\nIn main x is: " << x;

myFunc();

cout << "\nBack in main, x is: " << x;


return 0;
}

void myFunc()
{

int x = 8;
cout << "\nIn myFunc, local x: " << x << endl;

{
cout << "\nIn block in myFunc, x is: " << x;

int x = 9;

cout << "\nVery local x: " << x;


}

cout << "\nOut of block, in myFunc, x: " << x << endl;


}

//SA SE DETERMINE O procedura prin care se pun in evidenta


transmiterea prin valoare
#include "stdafx.h"
#include<iostream>
using namespace std;
void swap(int x, int y);

int main()
{
int x = 5, y = 10;

cout << "Main. Before swap, x: " << x << " y: " << y << "\n";
swap(x,y);
cout << "Main. After swap, x: " << x << " y: " << y << "\n";
return 0;
}

void swap (int x, int y)


{
int temp;

cout << "Swap. Before swap, x: " << x << " y: " << y << "\n";

temp = x;
x = y;
y = temp;

cout << "Swap. After swap, x: " << x << " y: " << y << "\n";

//SA SE DETERMINE O functie prin care se pun in evidenta


//returnarea a doua rezultate in functie de datele de intrare
#include "stdafx.h"
#include<iostream>
using namespace std;
int Doubler(int AmountToDouble);

int main()
{

int result = 0;
int input;

cout << "Enter a number between 0 and 10,000 to double: ";


cin >> input;

cout << "\nBefore doubler is called... ";


cout << "\ninput: " << input << " doubled: " << result << "\
n";

result = Doubler(input);

cout << "\nBack from Doubler...\n";


cout << "\ninput: " << input << " doubled: " << result <<
"\n";

return 0;
}

int Doubler(int original)


{
if (original <= 10000)
return original * 2;
else
return -1;
cout << "You can't get here!\n";
}
//SA SE DETERMINE O functie prin care se pun in evidenta
//faptul ca desi se fac intializari in atetul functiei se preiau
//valorile din programul principal al parametrilor
//si nu conteaza numarul de parametrii la apel al functiei
#include "stdafx.h"
#include<iostream>
using namespace std;
int AreaCube(int length, int width = 25, int height = 1);

int main()
{
int length = 100;
int width = 50;
int height = 2;
int area;

area = AreaCube(length, width, height);


cout << "First area equals: " << area << "\n";

area = AreaCube(length, width);


cout << "Second time area equals: " << area << "\n";

area = AreaCube(length);
cout << "Third time area equals: " << area << "\n";
return 0;
}

AreaCube(int length, int width, int height)


{

return (length * width * height);


}
//SA SE DETERMINE O functie prin care se pun in evidenta
//faptul ca functia poate avea parametrii de tipuri diferite la
intrare
#include "stdafx.h"
#include<iostream>
using namespace std;
int Double(int);
long Double(long);
float Double(float);
double Double(double);

int main()
{
int myInt = 6500;
long myLong = 65000;
float myFloat = 6.5F;
double myDouble = 6.5e20;

int doubledInt;
long doubledLong;
float doubledFloat;
double doubledDouble;

cout << "myInt: " << myInt << "\n";


cout << "myLong: " << myLong << "\n";
cout << "myFloat: " << myFloat << "\n";
cout << "myDouble: " << myDouble << "\n";

doubledInt = Double(myInt);
doubledLong = Double(myLong);
doubledFloat = Double(myFloat);
doubledDouble = Double(myDouble);

cout << "doubledInt: " << doubledInt << "\n";


cout << "doubledLong: " << doubledLong << "\n";
cout << "doubledFloat: " << doubledFloat << "\n";
cout << "doubledDouble: " << doubledDouble << "\n";

return 0;
}

int Double(int original)


{
cout << "In Double(int)\n";
return 2 * original;
}
long Double(long original)
{
cout << "In Double(long)\n";
return 2 * original;
}

float Double(float original)


{
cout << "In Double(float)\n";
return 2 * original;
}

double Double(double original)


{
cout << "In Double(double)\n";
return 2 * original;
}
//SA SE DETERMINE O functie prin care se pun in evidenta
//faptul ca functia INLINE poate fi flosita oriunde in program
//si oricand
#include "stdafx.h"
#include<iostream>
using namespace std;
inline int Double(int);

int main()
{
int target;

cout << "Enter a number to work with: ";


cin >> target;
cout << "\n";

target = Double(target);
cout << "Target: " << target << endl;

target = Double(target);
cout << "Target: " << target << endl;

target = Double(target);
cout << "Target: " << target << endl;
return 0;
}

int Double(int target)


{
return 2*target;
}
RECURSIVITATE
.

Recursivitatea este un mecanism general de elaborare a programelor.


Ea consta in posibilitatea ca un subprogram sa se autoapeleze
//SA SE DETERMINE O functie prin care se pun in evidenta
//faptul ca functia FIBONACCI ne da rezultate recursive in fiecare
etapa
#include "stdafx.h"
#include<iostream>
using namespace std;
int fib(int n);

int main()
{

int n, answer;
cout << "Enter number to find: ";
cin >> n;

cout << "\n\n";

answer = fib(n);

cout << answer << " is the " << n << "th Fibonacci number\n";
return 0;
}

int fib (int n)


{
cout << "Processing fib(" << n << ")... ";

if (n < 3 )
{
cout << "Return 1!\n";
return (1);
}
else
{
cout << "Call fib(" << n-2 << ") and fib(" << n-1 << ").\n";
return( fib(n-2) + fib(n-1));
}
}

//sa se determine factorialul cu functii


#include "stdafx.h"
#include<iostream>
using namespace std;

int fact (int n)


{if(!n) return 1;
else return n*fact(n-1);
}
main()
{ int n;
cout<<"n=";cin>>n;
cout<<fact(n);
}
//sa se determine factorialul cu proceduri
#include "stdafx.h"
#include<iostream>
using namespace std;
void fact(int val,int n,int& prod)
{
if(val<=n)
{prod*=val;
fact(val+1,n,prod);
}
}
main()
{
int val,n,p=1;

cout<<"n=";cin>>n;
fact(1,n,p);
cout<<p;
}
//sa se determine functia lui Manna Pnueli

#include "stdafx.h"
#include<iostream>
using namespace std;

int x;
int manna(int x)
{
if(x>=12) return x-1;
else return manna(manna(x+2));
}
main()
{
cout<<"x=";cin>>x;
cout<<manna(x);
}
//sa se determine divizor comun a doua numere prin scaderi succesive
#include "stdafx.h"
#include<iostream>
using namespace std;

int a,b;
int cmmdc(int a,int b)
{if (a==b) return a;
else if (a>b) return cmmdc (a-b,b);
else return cmmdc(a,b-a);
}
main()
{
cout<<"a=";cin>>a;
cout<<"b=";cin>>b;
cout<<cmmdc(a,b);
}
//sa se determine suma cifrelor unui numar
#include "stdafx.h"
#include<iostream>
using namespace std;

int n;
int s(int n)
{
if(!n) return 0;
else return n%10 +s(n/10);
}
main()
{
cout <<"n=";cin>>n;
cout<<s(n);
}
//sa se determine un numar intr-o baza recursiv
#include "stdafx.h"
#include<iostream>
using namespace std;

int n,b;
void transform(int n, int b)
{ int rest=n%b;
if(n>=b) transform(n/b,b );
cout <<rest;
}
main()
{ cout <<"n=";cin>>n;
cout<<"baza=";
cin>>b;
transform(n,b);
}
//sa se determine recursiv An si Bn
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

double a,b;
int n;
double bn(int n);
double an(int n)
{
if (!n) return a;
else return (an(n-1)+bn(n-1))/2;
}
double bn(int n)
{
if (!n) return b;
else return sqrt(an(n-1)*bn(n-1));
}
main()
{ cout <<"a=";cin>>a;
cout<<"b="; cin>>b;
cout<<"n="; cin>>n;
cout<<an(n)<<" "<<bn(n);
}
POINTARI SI ADRESE
Memoria internă poate fi privită ca o succesiune de octeţi. Pentru a-i distinge,
aceştia sunt numerotaţi. Numărul de ordine al unui octet se numeşte adresa lui.

Orice variabilă ocupă un număr succesiv de octeţi. De exemplu, o variabilă de tip


int ocupă doi octeţi (în varianta VISUAL C++ .NET). Adresa primului octet al variabilei se
numeşte adresa variabilei.
Variabilele de tip pointer se caracterizează prin faptul că valorile pe care le pot memora
sunt adresa ale unor variabile.

Limbajul VISUAL C++.NET face distincţie între natura adreselor care pot fi
memorate. Astfel, există adrese ale variabilelor de tip int, adrese ale variabilelor de tip
float, adrese ale variabilelor de tip char, etc
 O astfel de variabilă - capabilă să reţină adrese – se declară astfel:
Tip *nume
 Adresa unei variabile se obţine cu ajutorul operatorului de referinţe “&”,
care trebuie să preceadă numele variabilei:
&Nume_variabilă;
Fie o variabilă a, de tip pointer către tipul x şi n un număr natural. Atunci
au sens operaţiile a+n şi a-n.
 a+n reprezintă adresa care se obţine ca diferenţă între adresa lui
a şi n înmulţit cu numărul de octeţi care sunt ocupaţi de o
variabilă de tipul x.
 a-n reprezintă adresa care se obţine ca diferenţă între adresa lui
a şi n înmulţit cu numărul de octeţi care sunt ocupaţi de variabila
de tipul x.
În VISUAL C++.NET numele unui masiv (tablou) este pointer. Vom
analiza în amănunt acest fapt mai întâi pentru vectori şi apoi pentru
tablouri p-dimensionale.
 Numele vectorului este un pointer constant (nu poate fi modificat) către
tipul de bază al vectorului.
a[n]=*(a+n)=*(n+a)=n[a]
În C++ există un tip special care permite ca o variabilă să fie “botezată” cu
mai multe nume, numit tip referinţă. Aparent, programul lucrează cu mai
multe variabile, dar în fapt se lucrează cu una singură. O astfel de
declaraţie se face ca mai jos:

tip& nume variabilă = valoare de iniţializare

//SA SE DETERMINE un exemplu prin care se pun in evidenta


//faptul ca variabile de tipuri diferite se memoreaza la adrese
diferite
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
unsigned short shortVar=5;
unsigned long longVar=65535;
long sVar = -65535;

cout << "shortVar:\t" << shortVar;


cout << " Address of shortVar:\t";
cout << &shortVar << endl;

cout << "longVar:\t" << longVar;


cout << " Address of longVar:\t" ;
cout << &longVar << endl;

cout << "sVar:\t" << sVar;


cout << " Address of sVar:\t" ;
cout << &sVar << endl;

return 0;
}
//SA SE DETERMINE un exemplu prin care se pun in evidenta
//faptul ca o variabila data rin numele ei si valoarea sa
//dar si pointerul *la numele ei e tot una
#include "stdafx.h"
#include<iostream>
using namespace std;
typedef unsigned short int USHORT;
int main()
{
USHORT myAge; // a variable
USHORT * pAge = 0; // a pointer
myAge = 5;
cout << "myAge: " << myAge << "\n";

pAge = &myAge; // assign address of myAge to pAge

cout << "*pAge: " << *pAge << "\n\n";

cout << "*pAge = 7\n";

*pAge = 7; // sets myAge to 7

cout << "*pAge: " << *pAge << "\n";


cout << "myAge: " << myAge << "\n\n";

cout << "myAge = 9\n";

myAge = 9;

cout << "myAge: " << myAge << "\n";


cout << "*pAge: " << *pAge << "\n";

return 0;
}
//transmiterea prin referinta

#include "stdafx.h"
#include<iostream>
using namespace std;
void intersc(int*x,int*y)
{ int man;
man=*x;*x=*y;*y=man;
}
main()
{ int a=2,b=3;
intersc(&a,&b);
cout<<a<<" "<<b;
}

//SA SE DETERMINE un exemplu prin care se pun in evidenta


//faptul ca o adresa e diferita de valoarea unei variabile
//data pprin pointerul variabilei respective
#include "stdafx.h"
#include<iostream>
typedef unsigned short int USHORT;
int main()
{
unsigned short int myAge = 5, yourAge = 10;
unsigned short int * pAge = &myAge; // a pointer

cout << "myAge:\t" << myAge << "\tyourAge:\t" << yourAge <<
"\n";
cout << "&myAge:\t" << &myAge << "\t&yourAge:\t" << &yourAge
<<"\n";

cout << "pAge:\t" << pAge << "\n";


cout << "*pAge:\t" << *pAge << "\n";

pAge = &yourAge; // reassign the pointer

cout << "myAge:\t" << myAge << "\tyourAge:\t" << yourAge <<
"\n";
cout << "&myAge:\t" << &myAge << "\t&yourAge:\t" << &yourAge
<<"\n";

cout << "pAge:\t" << pAge << "\n";


cout << "*pAge:\t" << *pAge << "\n";

cout << "&pAge:\t" << &pAge << "\n";


return 0;
}

//SA SE DETERMINE un exemplu prin care se pun in evidenta


//faptul ca pot pune valoarea unei variabile la o anumita adresa
//daca accesez variabila de la acea adresa am aceiasi valoare ca la
destinatie
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
int intOne;
int &rSomeRef = intOne;

intOne = 5;
cout << "intOne: " << intOne << endl;
cout << "rSomeRef: " << rSomeRef << endl;

rSomeRef = 7;
cout << "intOne: " << intOne << endl;
cout << "rSomeRef: " << rSomeRef << endl;
return 0;
}
//SA SE DETERMINE un exemplu prin care se pun in evidenta
//faptul ca pot pune valoarea unei variabile la o anumita adresa
//daca accesez variabila de la acea adresa am aceiasi valoare ca la
destinatie
//adresele sursa si destinatie ale variabilelor o sa coincida
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
int intOne;
int &rSomeRef = intOne;

intOne = 5;
cout << "intOne: " << intOne << endl;
cout << "rSomeRef: " << rSomeRef << endl;

cout << "&intOne: " << &intOne << endl;


cout << "&rSomeRef: " << &rSomeRef << endl;

return 0;
}

//SA SE DETERMINE un exemplu prin care se pun in evidenta


//faptul ca pot pune valoarea unei variabile la o anumita adresa
//daca accesez variabila de la acea adresa am aceiasi valoare ca la
destinatie
//adresele sursa si destinatie ale variabilelor o sa coincida
//cand fac initializarea variabilei sursa adresa acesteia se schimba
//dar variabila destinatie ramane la aceiasi adresa
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
int intOne;
int &rSomeRef = intOne;

intOne = 5;
cout << "intOne:\t" << intOne << endl;
cout << "rSomeRef:\t" << rSomeRef << endl;
cout << "&intOne:\t" << &intOne << endl;
cout << "&rSomeRef:\t" << &rSomeRef << endl;

int intTwo = 8;
rSomeRef = intTwo; // not what you think!
cout << "\nintOne:\t" << intOne << endl;
cout << "intTwo:\t" << intTwo << endl;
cout << "rSomeRef:\t" << rSomeRef << endl;
cout << "&intOne:\t" << &intOne << endl;
cout << "&intTwo:\t" << &intTwo << endl;
cout << "&rSomeRef:\t" << &rSomeRef << endl;
return 0;
}
//SA SE DETERMINE un exemplu prin care se pun in evidenta
//faptul ca interschimbarea prin poiteri se face prin referinta
//si la apel procedura sau functia foloseste adresele variabilelor
chiar
//daca in antet avem pointeri
#include "stdafx.h"
#include<iostream>
using namespace std;
void swap(int *x, int *y);

int main()
{
int x = 5, y = 10;

cout << "Main. Before swap, x: " << x << " y: " << y << "\n";
swap(&x,&y);
cout << "Main. After swap, x: " << x << " y: " << y << "\n";
return 0;
}

void swap (int *px, int *py)


{
int temp;

cout << "Swap. Before swap, *px: " << *px << " *py: " << *py
<< "\n";

temp = *px;
*px = *py;
*py = temp;

cout << "Swap. After swap, *px: " << *px << " *py: " << *py <<
"\n";

}
//SA SE DETERMINE un exemplu prin care se pun in evidenta
//faptul ca interschimbarea prin adresa se face prin referinta
//si la apel procedura sau functia foloseste doar numele variabilelor
chiar
//daca in antet avem adrese
#include "stdafx.h"
#include<iostream>
using namespace std;
void swap(int &x, int &y);

int main()
{
int x = 5, y = 10;

cout << "Main. Before swap, x: " << x << " y: " << y <<
"\n";
swap(x,y);
cout << "Main. After swap, x: " << x << " y: " << y <<
"\n";
return 0;
}

void swap (int &rx, int &ry)


{
int temp;

cout << "Swap. Before swap, rx: " << rx << " ry: " <<
ry << "\n";

temp = rx;
rx = ry;
ry = temp;

cout << "Swap. After swap, rx: " << rx << " ry: " <<
ry << "\n";

}
//SA SE DETERMINE un exemplu prin care se pun in evidenta
//faptul ca o functie poate returna mai multe rezultate
//parametrii pot fi unii poiteri dar se apaelaza prin adresa lor
//la afisare parametrii care au in fata semnul adresa sunt de iesire
//si ei pot fi afisati doar prin numele lor
#include "stdafx.h"
#include<iostream>
using namespace std;
typedef unsigned short USHORT;

short Factor(USHORT, USHORT*, USHORT*);

int main()
{
USHORT number, squared, cubed;
short error;

cout << "Enter a number (0 - 20): ";


cin >> number;

error = Factor(number, &squared, &cubed);

if (!error)
{
cout << "number: " << number << "\n";
cout << "square: " << squared << "\n";
cout << "cubed: " << cubed << "\n";
}
else
cout << "Error encountered!!\n";
return 0;
}

short Factor(USHORT n, USHORT *pSquared, USHORT *pCubed)


{
short Value = 0;
if (n > 20)
Value = 1;
else
{
*pSquared = n*n;
*pCubed = n*n*n;
Value = 0;
}
return Value;
}
//SA SE DETERMINE un exemplu prin care se pun in evidenta
//faptul ca o functie poate returna mai multe rezultate
//parametrii pot fi unii poiteri dar se apaelaza prin adresa lor
//la afisare parametrii care au in fata semnul adresa sunt de iesire
//si ei pot fi afisati doar prin numele lor
//transmiterea datelor se face prin referinta
#include "stdafx.h"
#include<iostream>
using namespace std;
typedef unsigned short USHORT;
enum ERR_CODE { SUCCESS, ERROR };

ERR_CODE Factor(USHORT, USHORT&, USHORT&);

int main()
{
USHORT number, squared, cubed;
ERR_CODE result;

cout << "Enter a number (0 - 20): ";


cin >> number;

result = Factor(number, squared, cubed);

if (result == SUCCESS)
{
cout << "number: " << number << "\n";
cout << "square: " << squared << "\n";
cout << "cubed: " << cubed << "\n";
}
else
cout << "Error encountered!!\n";
return 0;
}

ERR_CODE Factor(USHORT n, USHORT &rSquared, USHORT &rCubed)


{
if (n > 20)
return ERROR; // simple error code
else
{
rSquared = n*n;
rCubed = n*n*n;
return SUCCESS;
}
}
//SA SE DETERMINE un exemplu prin care se pun in evidenta
//faptul ca o functie poate returna mai multe rezultate
//parametrii pot fi unii poiteri dar se apaelaza prin adresa lor
//la afisare parametrii care au in fata semnul adresa sunt de iesire
//si ei pot fi afisati doar prin numele lor
//transmiterea datelor se face prin referinta
#include "stdafx.h"
#include<iostream>
using namespace std;
#include <iostream>
using namespace std;

void double_it(int *p);

int main() {
int a = 5, b = 6;

cout << "Value of a before doubling is " << a << endl;


cout << "Value of b before doubling is " << b << endl;

double_it(&a); // Pass address of a.


double_it(&b); // Pass address of b.
cout << "Value of a after doubling is " << a << endl;
cout << "Value of b after doubling is " << b << endl;

return 0;
}

void double_it(int *p) {


*p = *p * 2;
}

// Exercitiul 6.1.1.txt
// Acest program transmite adresa unei variable la o functie,
// care tripleaza valoarea indicata.

#include "stdafx.h"
#include <iostream>
using namespace std;

#include <iostream>
using namespace std;

void triple_it(int *n);

int main() {
int n = 15;

cout << "Value of n before tripling: " << n << endl;

triple_it(&n); // Pass address of temp.

cout << "Value after tripling: " << n << endl;

return 0;
}

void triple_it(int *n) {


*n = *n * 3;
}

// Exercitiul 6.1.2.txt
// Acest program transmite adresa unei variable la o functie,
// care realizeaza o conversie din grade Celsius in grade
Fahrenheit.

#include "stdafx.h"

#include <iostream>
using namespace std;

void convert_temp(double *p);

int main() {
double temp = 10.0;

cout << "Value (Celsius) before conversion: " << temp << endl;
convert_temp(&temp); // Pass address of temp.

cout << "Value after conversion to Fahrenheit: " << temp << endl;

return 0;
}

void convert_temp(double *p) {


*p = (*p * 1.8) + 32;
}

// Exercitiul 6.1.3.txt
// Acest program realizeaza sortarea unui vector prin intermediul
poiterilor

#include "stdafx.h"

#include <iostream>
using namespace std;

void sort(int n);


void swap(int *p1, int *p2);

int a[10];

int main () {
int i;

for (i = 0; i < 10; i++) {


cout << "Enter array element #" << i << ": ";
cin >> a[i];
}
sort(10);

cout << "Here are all the array elements, sorted:" << endl;
for (i = 0; i < 10; i++)
cout << a[i] << " ";

return 0;
}

// Sort array function: sort array named a, having n elements.


//
void sort (int n) {
int i, j, low;

for(i = 0; i < n - 1; i++) {

// This part of the loop finds the lowest


// element in the range i to n-1; the index
// is set to the variable named low.

low = i;
for (j = i + 1; j < n; j++)
if (a[j] < a[low])
low = j;

// This part of the loop performs a swap if


// needed.
if (i != low)
swap(&a[i], &a[low]);
}
}

// Swap function.
// Swap the values pointed to by p1 and p2.
//
void swap(int *p1, int *p2) {
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}

// Exercitiul 6.3.1.txt
// Acest program initializeaza cu zero un vector cu pointeri
#include "stdafx.h"
#include <iostream>
using namespace std;
void zero_out_array(int *arr, int n);

int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

int main() {
int i;

zero_out_array(a, 10);

// Print out all the elements of the array.

for (i = 0; i < 10; i++)


cout << a[i] << " ";

return 0;
}

// Zero-out-array function.
// Assign 0 to all elements of an int array of size n.
//
void zero_out_array(int *p, int n) {
while (n-- > 0) { // Do n times:
*p = 0; // Assign 0 to element pointed
// to by p.
p++; // Point to next element.
}
}

// Exercitiul 6.3.3.txt
// Acest program este similar cu cel din scriptul zero_out.cpp,
// cu diferenta ca utilizeaza o referire directa la un pointer
// de afisare a elementelor.

#include "stdafx.h"

#include <iostream>
using namespace std;

void zero_out_array(int *arr, int n);


int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

int main() {
int *p;

zero_out_array(a, 10);

// Print out all the elements of the array.

for (p = a; p < a + 10; p++)


cout << *p << " ";

return 0;
}

// Zero-out-array function.
// Assign 0 to all elements of an int array of size n.
//
void zero_out_array(int *p, int n) {
while (n-- > 0) { // Do n times:
*p = 0; // Assign 0 to element pointed
// to by p.
p++; // Point to next element.
}
}

// Exercitiul 6.3.2.txt
// Acest program introduce si testeaza o functie care copiaza
// intreg continutul unei matrice in alta.

#include "stdafx.h"

#include <iostream>
using namespace std;

void copy_array(int *arr1, int *arr2, int n);

int a[10];
int b[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

int main() {
int *p;

copy_array(a, b, 10); // Copy a[] <- b[]

// Print out all the elements of the array a.

for (p = a; p < a + 10; p++)


cout << *p << " ";

return 0;
}

// Zero-out-array function.
// Copy contents of second array into first array.
//
void copy_array(int *p1, int *p2, int n) {
while (n-- > 0) { // Do n times:
*p1 = *p2;
p1++;
p2++;
}
}

STIVA
 Stiva este o listă pentru care singurele operaţii permise sunt:
● Adăugarea unui element în stivă;
● Eliminarea, consultarea, sau modificarea ultimului element introdus în stivă.
Stiva funcţionează pe principiul LIFO (Last In First Out) – “ultimul
intrat, primul ieşit”.
Pentru a înţelege modul de lucru cu stiva, ne imaginăm un număr n de farfurii
identice, aşezate una peste alta (o “stivă” de farfurii). Adăugarea sau scoaterea unei
farfurii se face, cu uşurinţă, numai în vârful stivei.

Oricât ar părea de simplu principiul stivei, el are consecinţe uriaşe în programare.

Stivele se pot aloca secvenţial (ca vectori). Fie ST[i] un vector. ST[1], ST[2], … , ST[n] pot reţine numai
litere sau numai cifre. O variabilă k indică în permanenţă vârful stivei, adică ultimul element introdus.

În stivă iniţial vidă se introduce litera A, vârful stivei va fi la nivelul 1,


(k=1);
A
B
A
Introducem în stivă litera B, deci k va lua valoarea 2.

Scoatem din stivă pe B (A nu poate fi scos deocamdată); k=1

Scoatem din stivă pe A; stiva rămâne vidă k=0

Observaţii:

În mod practic, la scoaterea unei variabile din stivă, valoarea variabilei ce indică vârful stivei scade cu 1, iar atunci
când scriem ceva în stivă, o eventuală valoare reziduală se pierde.

Pe un anumit nivel se reţine, de regulă, o singură informaţie (literă sau cifră), însă este posibil, aşa cum va rezulta
din exemplele prezentate în lucrare, să avem mai multe informaţii, caz în care avem stive duble, triple, etc.

În cazul stivei, alocarea secvenţială nu prezintă mari dezavantaje, ca în cazul mai general, al listelor, pentru că nu
se fac operaţii de inserare sau ştergere în interiorul stivei. Singurul dezavantaj, în comparaţie cu alocarea dinamică
înlănţuită este dat de faptul că numărul de noduri care pot fi memorate la un moment dat este mai mic – depinde de
gradul de ocupare al segmentului de date.
În literatura de specialitate veţi întâlni termenul PUSH pentru operaţia de adăugare în stivă a unei înregistrări şi
POP, pentru extragere.

Exemple:

□ Funcţia Manna-Pnueli. Se citeşte xЄZ. Se cere programul pentru calculul funcţiei:

F(x)= x-1, x≥12


F(F(x+2)), x<12

Vom începe prin a studia modul de calcul al funcţiei pentru x=15 şi x=8.

f(15)=14;
f(8)=f(f(10))=f(f(f(12)))=f(f(11))=f(f(f(13)))=f(f(12))=f(11)=f(f(13))= f(12)=11.
Algoritmul va folosi o stivă ST şi o variabilă k, ce indică în permanenţă vârful stivei. Algoritmul se
bazează pe următoarele considerente:
■ la o nouă autoapelare a funcţiei f, se urcă în stivă (k se incrementează cu 1) şi se pune noua valoare.

■ în situaţia în care pentru valoarea aflată pe nivelul k se poate calcula funcţia, se coboară în stivă, punându-se pe
acest nivel noua valoare.

■ algoritmul se încheie când se ajunge în stivă la nivelul 0.

Pentru exemplul dat, prezentăm schematic funcţionarea sa:

12 13

10 10 11
11
8
8 8 8 8

12 13

8 11 11 12
f=11

//sa se determine FUNCTIA MANNA PNUELI CU STIVA


F(x)= x-1, x≥12
F(F(x+2)), x<12
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;
int st[100], n, k;
main( )
{ cout<<"n="; cin>>n;
k=1; st[1]=n;
while (k>0)
if (st[k]<12)
{ k++;
st[k]=st[k-1]+2;
}
else
{ k--;
if (k>0) st[k]=st[k+1]-1;
}
cout<<"n="<<st[1]-1;
}
Funcţia lui Ackermann. Se dă funcţia următoare, definită pe produsul cartezian NXN.. Se citesc
m şi n. Să se calculeze Ack(m, n).

n+1, m=0
Ack(m,n)= Ack(m-1, 1), n=0
Ack(m-1, Ack(m, n-1)), altfel

Pentru a elabora algoritmul, studiem un exemplu numeric:

ack(2,1)=ack(1,ack(2,0))=ack(1, ack(1,1))=ack(1, ack(0, ack(1,0))= ack(1, ack(0, ack(0,1))=ack(1,


ack(0,2))=ack(1,3)=ack(0, ack(1,2))= ack(0, ack(0, ack(1,1))=ack(0, ack(0, ack(0, ack(1,0))))=
ack(0, ack(0, ack(0, ack(0,1))))=ack(0, ack(0, ack(0,2)))=ack(0,,ack(0,3))= ack(0,4)=5.

Pentru calculul acestei funcţii, folosim o stivă dublă, ST. Iniţial, valorile m şi n se reţin la nivelul
1. Pe nivelul k al stivei se reţin valorile curente m şi n. În funcţie de valorile acestora se
procedează astfel:

■ pentru m şi n diferite de 0, este necesar un nou calcul de funcţie, caz în care se urcă în stivă şi
pe noul nivel se pun argumente m şi n-1.

■ pentru cazul n=0, se rămâne pe acelaşi nivel în stivă, punând în locul lui m valoarea m-1, iar în
locul lui n valoarea 1.

■ în situaţia în care m=0, funcţia se poate calcula; se coboară în stivă şi se înlocuieşte valoarea lui
m cu m-1, valoarea lui n cu valoarea calculată anterior.

În continuare, prezentăm grafic modul de funcţionare a algoritmului pentru exemplul ack(2,1):

10 01
20 11 11 11
21 21 21 21 21
10
01 11 11
11
02 02 13 12 12
12
21 12
13 03
12 13 13
13 13 13 04

//sa se determine FUNCTIA lui Ackerman


n+1, m=0
Ack(m,n)= Ack(m-1, 1), n=0
Ack(m-1, Ack(m, n-1)), altfel

#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

int st[10000][2];
main( )
{ int m, n, k;
cout<<"m="; cin>>m;
cout<<"n="; cin>>n;
k=1; st[k][0] =m; st[k][1] =n;
while (k>0)
if (st[k][0] && st[k][1])
{
k++;
st[k][0] =st[k-1][0];
--st[k-1][1];
st[k][1] =st[k-1][1];
}
else
if (!st[k][1])
{
--st[k][0];
st[k][1] = 1;
}

else
{
k--;
if (k>0)
{ --st[k][0] ;
st[k][1] =st[k+1][1] +1;
}
}
cout<<"ac("<<m<<", "<<n<<") = "<<st[1][1] +1;
}

//sa se determine dinamic notiunea de stiva cu operatiile


corespunzatoare
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;
struct Nod
{
int info;
Nod* adr_inap;
};

Nod* v;
int n;

void Push( Nod*& v, int n)


{
Nod* c;
if (!v)
{
v= new Nod; v->info=n; v->adr_inap=0;
}
else
{c= new Nod; c->info=n; c->adr_inap=v;
v=c;
}
}

void Pop(Nod*& v)
{
Nod* c;
if (!v) cout<<"stiva este vida";
else
{
c=v;
cout<<"am scos"<< c->info<<endl;
v=v->adr_inap;
delete c;
}
}

main( )
{ Push(v,1); Push(v,2); Push(v,3);
Pop(v); Pop(v); Pop(v); Pop(v);
}
//sa se determine dinamic cu notiunea de stiva functia Manna Pnueli
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

struct Nod
{ int info;
Nod* adr_inap;
};
Nod* v;
int n;
void Push(Nod*& v, int n)
{ Nod* c;
if (!v)
{ v= new Nod; v->info=n; v->adr_inap=0;}
else
{ c= new Nod; c->info=n; c->adr_inap=v;
v=c;
}
}
void Pop (Nod*& v)
{ Nod* c;
if (!v) cout<< "stiva este vida";
else
{ c=v;
cout<<" am scos"<<c->info<<endl;
v=v->adr_inap;
delete c;
}
}
main( )
{ int Man;
cout<<"n="; cin>>n;
Push(v,n);
while (v)
if (v->info<12)
{
Push(v,v->info+2);
}
else
{ Man=v->info;
Pop(v);
if (v) v->info=Man-1;
}
cout<<"f="<<Man-1;
}
COADA

 O coadă este o listă pentru care toate inserările sunt făcute la unul din capete,
toate ştergerile (consultările, modificările) la celălalt capăt.

Coada funcţionează pe principiul FIFO (First In First Out) – “primul


intrat, primul ieşit”.

Este cu totul nerecomandabilă alocarea secvenţială a cozii, deoarece în această situaţie, are loc
un fenomen de migraţie a datelor către ultimele componente ale vectorului (cele de indice mare).

Să presupunem că simulăm o coadă cu ajutorul unui vector cu zece componente, care reţin
numere întregi. Introducem în coadă, pe rând, numerele 1, 2, 3, 4.

1 2 3 4

Dacă scoatem din coadă pe 1 şi introducem în coadă pe 5, coada va arăta astfel:

2 3 4 5

Scoatem din coadă pe 2 şi introducem pe 6:

3 4 5 6

Se observă acest fenomen de “migraţie”.

Alocarea dinamică înlănţuită a cozii. O variabilă v va reţine adresa elementului care urmează a
fi scos (servit). O alta, numită sf, va reţine adresa elementului introdus în coadă. Figura următoare
prezintă o coadă în care primul element care urmează a fi scos are adresa în v, iar ultimul introdus are
adresa sf.
v sf

7 3 5 2

//sa se determine dinamic cu notiunea de coada


#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

struct Nod
{
int info;
Nod* adr_urm;
};

Nod* v, *sf;
int n;

void Pune( Nod*& v, Nod*& sf, int n)


{
Nod* c;
if (!v)
{ v= new Nod; v->info=n; v->adr_urm=0;
sf=v;
}
else
{ c= new Nod;
sf->adr_urm=c;
c->info=n;
c->adr_urm=0;
sf=c;
}
}

void Scoate(Nod*& v)
{ Nod* c;
if (!v) cout<<"coada este vida"<<endl;
else
{ cout<<"Am scos"<<v->info<<endl;
c=v; v=v->adr_urm;
delete c;
}
}

void Listare(Nod* v)
{ Nod* c=v;
while ( c )
{ cout<<c->info<<" ";
c=c->adr_urm;
}
cout<<endl;
}
main( )
{ Pune(v, sf, 1); Pune(v, sf, 2); Pune(v, sf, 3); Listare(v);
Scoate(v); Listare(v);
Scoate(v); Listare(v);
Scoate(v); Listare(v);
Scoate(v); Listare(v);
}
DIVIDE ET IMPERA

Descrierea metodei

Dându-se o funcţie care lucrează asupra a n date de intrare, tehnica


“DIVIDE ET IMPERA” (Desparte şi stăpâneşte) presupune desfacerea (divizarea)
intrărilor în K submulţimi distincte, , care produc k subprobleme.
Aceste probleme trebuie rezolvate şi apoi trebuie gasită o metodă de combinare
a subsoluţiilor pentru a da soluţia întregii probleme.
Dacă subproblemele sunt încă mari tehnica poate fi reaplicată, dacă ele
sunt de acelaşi tip cu problema generală şi acesta este cazul cel mai frecvent.
Reaplicarea metodei conduce la o procedură recursivă. În acest fel se generează
subprobleme din ce în ce mai mici care în cazurile cele mai simple, se rezolvă
fără a fi redivizate. De obicei problema se împarte în două subprobleme de
acelaşi gen.
Această metodă e una din cele mai larg folosite.
Fie n intrări memorate în tabloul A (1:n) . Procedura generală de tip funcţie, cu
numele DETI este apelată iniţial prin DETI (1,n). Funcţia DETI (p,q), rezolvă o
problemă cu intrările A(p,q).
Descrierea funcţiei este următoarea:

procedure DETI(p,q)
global n,A(1:n);integer p,q,m // //
if MIC(p,q) then return(G(p,q))
else
m:=DIVIDE(p,q);
return(combină (DETI(p,m),DETI(m+1,q)))
endif
end DETI

//sa determine prin divide et impera maximul dintr-un vector


#include "stdafx.h"
#include<iostream>
using namespace std;
int v[10],n;

int max(int i,int j)


{ int a,b;
if (i==j) return v[i];
else
{ a=max(i,(i+j)/2);
b=max((i+j)/2+1,j);
if (a>b) return a;
else return b;
}
}
main ( )
{ cout<<"n=";cin>>n;
for (int i=1;i<=n;i++)
{cout<<"v["<<i<<"]=";cin>>v[i];}
cout<<"max="<<max(1,n);
}
//sa determine prin divide et impera GASIREA UNUI ELEMENT
//dintr-un vector prin cautare binara
#include "stdafx.h"
#include<iostream>
using namespace std;

int v[100],n,nr;

void caut(int i,int j)


{ if (nr==v[(i+j)/2])
cout<<"gasit"<<" "<<"indice"<<(i+j)/2;
else
if(i<j)
if (nr<v[(i+j)/2])
caut(i,(i+j)/2-1);
else caut ((i+j)/2+1,j);
};
main( )
{ cout<<"n=";cin>>n;
for (int i=1;i<=n;i++)
{ cout<<"v["<<i<<"]=";cin>>v[i];}
cout<<"nr=";cin>>nr;
caut(1,n);
}
//sa determine prin divide et impera sortarea elementelor
//dintr-un vector prin interclasare
#include "stdafx.h"
#include<iostream>
using namespace std;

int a[10],n;

void sort(int p,int q,int a[10])


{
int m;
if (a[p]>a[q])
{
m=a[p];
a[p]=a[q];
a[q]=m;}
}
void interc(int p,int q,int m,int a[10])
{
int b[10],i,j,k;
i=p;j=m+1;k=1;
while (i<=m && j<=q)
if (a[i]<=a[j])
{
b[k]=a[i];
i=i+1;
k=k+1;
}
else
{
b[k]=a[j];
j=j+1;
k=k+1;
}
if (i<=m)
for (j=i;j<=m;j++)
{
b[k]=a[j];
k=k+1;
}
else
for (i=j;j<=q;j++)
{
b[k]=a[i];
k=k+1;
}
k=1;
for (i=p;i<=q;i++)
{
a[i]=b[k];
k=k+1;
}
}
void divimp (int p,int q,int a[10])
{
int m;
if ((q-p)<=1) sort(p,q,a);
else
{ m=(p+q)/2;
divimp(p,m,a);
divimp(m+1,q,a);
interc(p,q,m,a);
}
}
main( )
{ int i;
cout<<"n=";cin>>n;
for (i=1;i<=n;i++)
{
cout<<"a["<<i<<"]=";cin>>a[i];}
divimp(1,n,a);
for (i=1;i<=n;i++)
cout<<a[i]<<" ";
}
//sa determine prin divide et impera sortarea elementelor
//dintr-un vector prin sortare rapida
#include "stdafx.h"
#include<iostream>
using namespace std;

int a[100],n,k;

void poz(int li,int ls,int& k,int a[100])


{
int i=li,j=ls,c,i1=0,j1=-1;
while (i<j)
{ if (a[i]>a[j])
{
c=a[j];
a[j]=a[i];
a[i]=c;
c=i1;
i1=-j1;
j1=-c;
}
i=i+i1;
j=j+j1;
k=i;
}
}

void quick (int li,int ls)


{ if (li<ls)
{ poz (li,ls,k,a);
quick(li,k-1);
quick(k+1,ls);
}
}
main( )
{ int i;
cout<<"n=";cin>>n;
for (i=1;i<=n;i++)
{ cout<<"a["<<i<<"]=";cin>>a[i];}
quick(1,n);
for (i=1;i<=n;i++) cout <<a[i]<<endl;
}
//sa determine prin divide et impera mutarea turnurilor din Hanoi
#include "stdafx.h"
#include<iostream>
using namespace std;

char a,b,c;
int n;

void han(int n,char a,char b,char c)


{
if (n==1) cout<<a<<b<<endl;
else
{
han(n-1,a,c,b);
cout<<a<<b<<endl;
han(n-1,c,b,a);
}
}
main ( )
{
cout<<"N=";cin>>n;
a='a';
b='b';
c='c';
han(n,a,b,c);
}
Tehnica backtracking

Aspecte teoretice
Aceasta tehnica se foloseste in reezolvarea problemelor care indeplinesc simultan urmatoarele
conditii:
 solutia lor poate fi pusa sub forma unui vector S=x1,x2,..,xn,cu x1 apartine de de A1,x2
apartine de A2,…,xn apartine de An;
 multimile A1,A2,…,An sunt multimi finite,iar elementele lor se considera ca se afla
intr-o relatie de ordine bine stabilita;
 nu se dispune de o alta metoda de rezolvare,mai rapida.
Observatii:
 nu pentru toate problemele n este cunoscut de la inceput;
 x1,x2,…,xn pot fi la randul lor vectori;
 in multe probleme,multimile A1,A2,…,An coincide.
Observatie: tehnica Backtracking are ca rezultat obtinerea tuturor solutiilor problemei.In cazul
in care se cere o singura solutie,se poate forta oprirea,atunci cand a fost gasita.
 Pentru usurarea intelegerii metodei,vom prezenta o rutina unica(aplicabila oricarei
probleme),rutina care este elaborate folosind structura de stiva.Rutina va apela functii
care au intotdeauna acelasi nume si care,din punct de vedere al metodei,realizeaza
acelasi lucru.Sarcina rezolvitorului este sa scrie explicit,pentru fiecare problema in
parte,functiile apelate de rutina backtracking.
 Evident o astfel de abordare conduce la programe lungi.Nimeni nun e opreste ca,dupa
intelegerea metodei,sa scriem programe scurte,specifice fiecarei probleme in parte(de
exemplu,scurtam substantial textul doar daca renuntam utilizarea unor functii,scriind
instructiunile lor chiar in corpul rutinei).
De exemplu,pentru generarea permutarilor multimii {1,2,3…,n},orice nivel al stivei va lua
valori de la 1 la n.Initializarea unui nivel(oarecare) se face cu valoarea 0.Functia de initializare
se va numi init( ).
→ Gasirea urmatorului element al multimii Ak+1,element netestat,se face cu ajutorul functiei
int Am_Succesor( ).Daca exista successor,acesta este pus in stiva si functia returneaza 1,altfel
functia returneaza 0.
→ Testul daca s-a ajuns sau nu la solutia finala se face cu ajutorul functiei int Solutie( )
→ Solutia se tipareste cu ajutorul functiei Tipar( ).
→Testarea conditiilor de continuare(adica daca avem sansa sau nu ca prin valoarea aflata pe
nivelul k+1 sa ajungem la solutie) se face cu functia int E_Vakid( ) careintoarce 1 daca
conditiile sunt indeplinite,sau 0 in caz contrar.

//sa determine prin backtracking permutarile numerelor de la 1 la n


#include "stdafx.h"
#include<iostream>
using namespace std;

int st[10],n,k;

void Init( )
{ st[k]=0;}

int Am_Succesor( )
{ if (st[k]<n)
{ st[k]++;
return 1;
}
else return 0;
}
int E_Valid( )
{ for (int i=1;i<k;i++)
if (st[i]==st[k]) return 0;
return 1;
}

int Solutie ( )
{ return k==n;}

void Tipar( )
{
for (int i=1;i<=n;i++) cout<<st[i];
cout<<endl;
}

void back( )
{int AS;
k=1; Init( );
while (k>0)
{ do { } while ((AS=Am_Succesor( )) && !E_Valid( ));
if (AS)
{
if (Solutie( )) Tipar( );
else
{
k++; Init( );
}
}
else k--;
}
}

main ( )
{ cout<<"n=";cin>>n;
back( );
}
//Prin Bactracking sa se rezolve problema damelor
//ex:n=4
D

//Adica:2413

#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdio.h>
#include <math.h>
int st[100],n,k;
void Init( )
{ st[k]=0; }

int Am_Succesor ( )
{ if (st[k]<n)
{ st[k]++;
return 1;
}
else return 0;
}
int E_Valid ( )
{ for (int i=1; i<k; i++)
if (st[k]==st[i]) return 0;
else
if (abs(st[k]-st[i])==abs(k-i) ) return 0;
return 1;
}

int Solutie( )
{ return k==n;}

void Tipar( )
{ for (int i=1; i<=n; i++) cout<<st[i];
cout<<endl;
}

void back( )
{int AS;
k=1; Init( );
while (k>0)
{ do { } while ((AS=Am_Succesor( )) && !E_Valid( ));
if (AS)
{
if (Solutie( )) Tipar( );
else
{
k++; Init( );
}
}
else k--;
}
}

main ( )
{ cout<<"n=";cin>>n;
back( );
}
//sa determine prin backtracking aranjamente de n elemente luate cate
// k ,conteaza ordinea adica (1 2) nu e tot una cu (2 1)
#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdio.h>
#include <math.h>

int st[10],n,k,p;

void Init ( )
{ st[k]=0; }

int Am_Succesor( )
{ if (st[k]<n)
{ st[k]++;
return 1;
}
else return 0;
}
int E_Valid( )
{
for (int i=1; i<k; i++)
if (st[k]==st[i]) return 0;
return 1;
}
int Solutie( )
{
return (k==p);}

void Tipar( )
{
for (int i=1; i<=p;i++) cout<<st[i];
cout<<endl;
}

void back( )
{int AS;
k=1; Init( );
while (k>0)
{ do { } while ((AS=Am_Succesor( )) && !E_Valid( ));
if (AS)
{
if (Solutie( )) Tipar( );
else
{
k++; Init( );
}
}
else k--;
}
}

main ( )
{ cout<<"n=";cin>>n;
cout<<"p="; cin>>p;
back( );
}
//sa determine prin backtracking combinari de n elemente luate cate k
//NU conteaza ordinea adica {1 2} e tot una cu {2 1} ca multimi de
elemente
#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdio.h>
#include <math.h>

int st[10],n,k,p;
void Init ( )
{ if (k>1) st[k]=st[k-1];
else st[k]=0;
}

int Am_Succesor ( )
{ if (st[k]<n-p+k)
{ st[k]++;
return 1;
}
else return 0;
}
int E_Valid( )
{
for (int i=1; i<k; i++)
if (st[k]==st[i]) return 0;
return 1;
}

int Solutie ( )
{ return k==p;}

void Tipar ( )
{ for ( int i=1; i<=p;i++) cout <<st[i];
cout<<endl;
}

void back( )
{int AS;
k=1; Init( );
while (k>0)
{ do { } while ((AS=Am_Succesor( )) && !E_Valid( ));
if (AS)
{
if (Solutie( )) Tipar( );
else
{
k++; Init( );
}
}
else k--;
}
}

main ( )
{ cout<<"n=";cin>>n;
cout<<"p="; cin>>p;
back( );
}
//sa determine prin backtracking produsul cartezian a N multimi
#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdio.h>
#include <math.h>

int st[10],a[10],n,k;

void Init( )
{ st[k]=0; }
int Am_Succesor ( )
{ if (st[k]<a[k])
{ st[k]++; return 1;}
else return 0;
}
int E_Valid ( )
{ return 1;}

int Solutie( )
{ return k==n;}

void Tipar( )
{ for (int i=1; i<=n;i++) cout<<st[i];
cout<<endl;
}

void back( )
{int AS;
k=1; Init( );
while (k>0)
{ do { } while ((AS=Am_Succesor( )) && !E_Valid( ));
if (AS)
{
if (Solutie( )) Tipar( );
else
{
k++; Init( );
}
}
else k--;
}
}

main ( )
{ cout<<"n=";cin>>n;
for (int i=1; i<=n; i++)
{ cout<<"a["<<i<<"]="; cin>>a[i];}

back( );
}
//sa determine prin backtracking problema colorarii hartilor
#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdio.h>
#include <math.h>

int st[10],a[20][20],n,k;

void Init( )
{ st[k]=0; }

int Am_Succesor ( )
{ if (st[k]<4)
{st[k]++;
return 11;
}
else return 0;
}

int E_Valid( )
{
for (int i=1; i<=k-1; i++)
if ( st[i]==st[k] && a[i][k]==1) return 0;
return 1;
}
int Solutie( )
{ return k==n;}

void Tipar( )
{ cout<<"varianta"<<endl;
for (int i=1;i<n; i++)
cout<<"tara"<<i<<"culoarea"<<st[i]<<endl;
cout<<endl;
}
void back( )
{int AS;
k=1; Init( );
while (k>0)
{ do { } while ((AS=Am_Succesor( )) && !E_Valid( ));
if (AS)
{
if (Solutie( )) Tipar( );
else
{
k++; Init( );
}
}
else k--;
}
}

main ( )
{ cout<<"n=";cin>>n;
for (int i=1; i<=n; i++)
for (int j=1; j<=i-1;j++)
{ cout<<"a["<<i<<","<<j<<"]="; cin>>a[i][j];
a[j][i]=a[i][j];
}

back( );
}

BACKTRAKING RECURSIV
//sa determine prin backtracking recursiv problema damelor
#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdio.h>
#include <math.h>

#include <math.h>
int t[20],n;
void tipar ( )
{
for (int i=1;i<=n;i++) cout<<t[i];
cout<<endl;
}
void dame(int k)
{int i,j,corect;
if (k==n+1) tipar( );
else
{
for (i=t[k]+1;i<=n;i++)
{
t[k]=i;
corect=1;

for (j=1;j<=k-1;j++)
if (t[j]==t[k]) corect=0;
else
if (abs (t[k]-t[j])==abs(k-j))
corect=0;
if (corect) dame (k+1);
}
}
t[k]=0;
}
main( )
{
cout<<"n=";cin>>n;
dame(1);
}
//sa determine prin backtracking recursiv partitiile unui numar
#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdio.h>
#include <math.h>

int s[20],n;
void tipar (int k)
{ for (int i=1;i<=k;i++) cout<<s[i];
cout<<endl;}
void part (int k,int v)
{int i;
s[k]=v;
tipar(k);
for (i=1;i<=s[k]-1;i++)
{
s[k]=s[k]-i;
part(k+1,i);
s[k]=s[k]+1;
}
}
main( )
{cout<<"n=";cin>>n;
part(1,n);}
//sa determine prin backtracking recursiv problema platii unei
sume //cu
// anumite tipuri de bancnote
#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdio.h>
#include <math.h>
int sol[10],a[10],b[10],n,i,s;

void tipar (int k)


{
cout<<"Solutie"<<endl;
for (i=1;i<=k;i++)
if (sol[i])
cout<<sol[i]<<" bancnote de "<<a[i]<<endl;
}
void plata (int k,int s0)
{
while(sol[k]<b[k]&& s0+a[k]<=s)
{sol[k]=sol[k]+1;
if (sol[k]>0)
s0+=a[k];
if (s0==s) tipar(k);
else if (k<n) plata (k+1,s0);}
sol[k]=-1;
}

void main( )
{
cout<<"cate tipuri de bacnote avem?";cin>>n;
cout<<"suma=";
cin>>s;
for (i=1;i<=n;i++)
{
cout<<"valoarea monedei de tipul"<<i<<" ";
cin>>a[i];
b[i]=s/a[i];
sol[i]=-1;
}
plata (1,0);
}
//sa determine prin algoritmul de umplere a unei suprafete inchise

#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdio.h>
#include <math.h>
int a[10] [10],i,j,m,n,x,y;
void scriu (int x,int y,int a[10][10])
{
if (a[x][y]==0)
{
a[x][y]=1;
scriu(x+1,y,a);
scriu(x,y+1,a);
scriu(x-1,y,a);
scriu(x,y-1,a);
}
}
void main( )
{
cout <<"M=";cin>>m;
cout<<"N=";cin>>n;
for (i=1;i<=m;i++)
for (j=1;j<=n;j++)
{
cout<<"a["<<i<<"."<<j<<"]=";
cin>>a[i][j];
}
for (i=1;i<=n;i++)
{
a[0][i]=1;
a[m+1][i]=1;
}
for (i=1;i<=m;i++);
{
a[i][0]=1;a[i][n+1]=1;
}
cout<<"X=";
cin>>x;
cout<<"Y=";
cin>>y;
for (i=1;i<=m;i++)
{
for (j=1;j<=n;j++)
cout<<a[i][j];
cout<< endl;
}
scriu(x,y,a);
cout<<endl<<endl;
for (i=1;i<=m;i++)
{
for (j=1;j<=n;j++)
cout<<a[i][j];
cout<<endl;
}
}
//sa se determine problema fotografiei recusiv
//ex:n=4
//m=4
1 1 0 0
0 0 0 1
A= 1 1 1 1
1 1 1 1

#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

int a[10][10],i,j,m,n,x,y,gasit;
void compact (int x,int y, int a[10][10])
{
if (a[x][y])
{
a[x][y]=0;
compact (x-1,y,a);
compact (x-1,y+1,a);
compact (x,y+1,a);
compact (x+1,y+1,a);
compact(x+1,y,a);
compact(x+1,y-1,a);
compact(x,y-1,a);
compact(x-1,y-1,a);
}
}
main( )
{
cout <<"M=";cin>>m;
cout<<"N=";cin>>n;
for (i=1;i<=m ;i++)
for(j=1;j<=n;j++)
{
cout<<"a["<<i<<","<<j<<"]=";
cin>>a[i][j];
}
for (i=1;i<n;i++)
{
a[0][i]=0;
a[m+1][i]=0;
}
for (i=1;i<=m;i++)
{
a[i][0]=0;a[i][n+1]=0;
}
x=0;
do
{
x++;
y=0;
do
{
y++;
}
while (y!=n && a[x][y]!=1);
}
while((x!=m)&& a[x][y]!=1);
compact(x,y,a);
gasit=0;
for (i=1;i<=m;i++)
for(j=1;j<=n;j++)
if (a[i][j]==1) gasit=1;
if(gasit) cout<<"mai multe obiecte";else cout<<"un obiect";
}
GREEDY

Descrierea metodei
Metoda Greedy este o metodă generală de elaborare a algoritmilor;
provenienţa numelui o vom explica mai jos. În esenţă, ea se aplică problemelor în
care se dă o mulţime A conţinând n date de intrare cerându-se să se determine o
submulţime B a sa care să îndeplinească anumite condiţii pentru a fi acceptată;
cum în general există mai multe astfel de mulţimi se mai dă şi un criteriu
conform căruia dintre submulţimile acceptabile (numite soluţii posibile) să
alegem una singură (numită soluţie optimă) ca rezultat final. Soluţiile posibile au
următoarea proprietate: dacă B este o soluţie posibilă şi CB, atunci şi C este o
soluţie posibilă; vom presupune că Ø este totdeauna soluţie posibilă.
Metoda Greedy tratează acest tip de probleme în următoarele două
moduri, care urmează aceeşi idee, dar diferă doar prin ordinea de efectuare a
unor operaţii.
Se pleacă de la soluţia vidă. Se alege pe rând într-un anumit fel un
element din A neales la paşii precedenţi. Dacă adăugarea lui la soluţia parţială
anterior construită conduce la o soluţie posibilă, construim noua soluţie posibilă
prin adăugarea elementului ales (vezi procedura GREEDY1).

FORMA 1:

Procedure GREEDY1(A,n,B);
BØ
For i=1,n
Call ALEGE(A,i,x)
Call POSIBIL(B,x,v)
If v=1 then call ADAUG(B,x)
Endif
Repeat
Return
End

FORMA 2:

Procedure GREEDY2(A,n,B);
Call PREL(A); BØ
For i=1,n
Call POSIBIL(B,ai,v)
If v=1 then call ADAUG(B,ai)
Endif
Repeat
End

//sa se determine ordinea de planificare a spectacolelor stiind cand


//incepe si cat dureaza
//ex:2
//n=2
//2
//20
//2
//40
//3
//10
//3
//20
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

int s[2][10],o[10],n,i,h1,m1,h2,m2,ora;
void sortare( )
{
int gata,m,i;
do
{ gata=1;
for (i=1;i<=n-1;i++)
if (s[i][o[i]] >s[1][o[i+1]])
{
m=o[i];
o[i]=o[i+1];
o[i+1]=m;
gata=0;
}
}
while (!gata);
}
main( )
{ cout<<"n=";cin>>n;
for (i=1;i<=n;i++)
{o[i]=i;
cout<<"ora de inceput pentru spectacolul"<<i<<"( h h) m m )=";
cin >>h1>>m1;
s[0][i]=h1*60+m1;
cout <<"oradesfarsit pentru spectacolul "<<i<<"(hh mm)=";
cin>>h2>>m2;
s[1][i]=h2*60+m2;
}
sortare( );
cout<<"ordinea spectacolelor este"<<endl<<o[1]<<endl;
ora=s[1][o[1]];
for (i=2;i<=n;i++)
{ if (s[0][o[i]]>=ora)
{cout<<o[i]<<endl;
ora=s[1][o[i]];}
}
}
//sa se determine alegerea de obiecte pentru umplerea
//unui rucsac cunoscand capacitatea lui,greutatea
obiectelor ,valoarea lor
//Ne intreseaza sa ducem maxim cantitativ si cu valoare maxima
ex:3
// 3
// 2
// 2
// 4
// 1
// 6
// 3
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

double c[9],g[9],ef[9],gv,man,castig;
int n,i,man1,inv,ordine[9];
main( )
{cout<<"Greutatea ce poate fi transportata=";cin>>gv;
cout<<"Numar de obiecte=";cin>>n;
for(i=1;i<=n;i++)
{
cout<<"c["<<i<<"]=";cin>>c[i];
cout<<"g["<<i<<"]";cin>>g[i];
ordine[i]=i; ef[i]=c[i] /g[i];
}
do
{
inv=0;
for(i=1;i<=n-1;i++)
if(ef[i]<ef[i+1])
{
man=ef[i];ef[i]=ef[i+1];ef[i+1]=man;
man=c[i]; c[i]=c[i+1]; c[i+1]=man;
man=g[i];g[i]=g[i+1]=man;
inv=1;
man1=ordine[i];ordine[i]=ordine[i+1];ordine[i+1]=man1;
}
}
while (inv);
i=1;
while(gv>0 && i<=n)
{
if (gv>g[i])
{ cout <<"Obiectul "<<ordine[i]<< " "<<1<<endl;
gv-=g[i];castig+=c[i];
}
else
{cout<<"Obiectul "<<ordine[i]<<" " <<gv /g[i]<<endl;
castig+c[i]*gv /g[i];
gv=0;
}
i++;
}
cout<<"Castig total="<<castig;
}
PROGRAMARE DINAMICA

Alaturi de Greedy,programarea dinamica este o tehnica ce conduce, de cele mai


multe ori, la un timp de calcul polinomial.Mai mult, ea furnizeaza in totdeauna solutia
optima .Din nefericire, programarea dinamica nu se poate aplica tuturor problemelor, ci
numai care indeplinesc anumite conditii.
Se considera o problema in care rezultatul se obtine ca urmare a unui sir de decizii D1,
D2,......Dn. In urma decizei D1 sistemul evolueaza din starea S0 in starea S1,in urma
decizei D2 sistemul evolueaza din starea S1 in starea S2,....,in urma decizei Dn sistemul
evolueaza din starea Sn-1 in stareaSn.
Daca D1, D2,....Dn este un sir de decizii care comduce sistemul in mod optim din S0 in
Sn,atunci trebuie indeplinita una din conditiile urmatoare (principiul de optimalitate):
1)Dk...Dn este un sir de decizii ce conduce optim sistemul din starea Sk-1 in
stareaSn,Ak,1<=k<=n;
2)D1....Dk este un sir de decizii ce conduce optim sistemul din starea S0 in
stareaDk,Ak,1<=K<=;
3)Dk+1...Dn,D1...Dk sunt siruri de decizii care conduc optim sistemul starea Sk in starea
Sn, respectiv din starea D0 in starea Sk,Ak,1<=k<=n.
=>Daca principiulde optimalitate se verifica in forma 1,spunem ca se aplica programarea
dinamica metoda inainte.
=>Daca principul de oplimalitate se verifica in forma 2, spunem ca se aplica programarea
dinamica inapoi.
=>Daca primcipiul de optimalitate se verifica in forma 3, spunem ca se aplica
programarea dinamica metoda mixta.
Programarea dinamica se poate aplica problemelor la care optimul general implica
optimul partial.
Faptulca optimul general determina optimul partial, nu inseamna ca optimul partial
determina optimul general.
cu toate acestea, faptul ca potimul general impune optimul partial ne este de mare
ajutor:cautam optimul general,intre optimele partiale, pe care le retinem la fiecare
pas.Oricum,cautarea se reduce considerabil.

//sa se determine prin programare dinamica suma maxima


//in parcurgerea si sumarea elemntelor
//din matricea triunghiulara ,stiind ca ma pot deplasa numai o
pozitie jos sau dreapta-jos
//ex:2
// 2
// 3
// 5

Exemplu:n=4;
2
3 5
6 3 4
5 6 1 4
Se pot forma mai multe sume:
S1=2+3+6+5=16;
S2=2+5+4+1=12;
Sk=2+3+6+6=17
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

int t[50][50],c[50][50],drum[50][50],n,i,j;
main()
{

cout<<"n=";cin>>n;
for (i=1;i<=n;i++)
for (j=1;j<=i;j++)
{ cout <<"t["<<i<<","<<j<<"]=";
cin>>t[i][j];
}
for (j=1;j<=n;j++) c[n][j]=t[n][j];
for (i=n-1;i>=1;i--)
{
for (j=1;j<=i;j++)
if (c[i+1][j]<c[i+1][j+1])
{
c[i][j]=t[i][j]+c[i+1][j+1];drum[i][j]=j+1;
}
else
{
c[i][j]=t[i][j]+c[i+1][j];
drum[i][j]=j;
}
};

cout<<"suma maxima="<<c[1][1]<<endl;
i=1;
j=1;
while (i<=n)
{
cout<<t[i][j]<<endl;
j=drum[i][j];
i++;
};
}
//sa se determine prin programare dinamica
//un subsir crecator care are maxim de componente dar sa fie
crescator
// ex:5
// 4
// 1
// 7
// 6
// 7
L=(3,3,2,2,1).
Componentele vectorului L au fost calculate astfel:
-cel mai lung subsir care se poate forma cu elementul 7,aflat pe ultima pozitie,are lungimea 1;
-cel mai lung subsir care se poate forma cu elementul 6 aflat pe pozitia 4 are lungimea
(1+L(5)), pentru ca pe pozitia 5se gaseste elementul 7 care este mai mare decat 6;
-cel mai lung subsir care se poate forma cu elementul aflat pe pozitia 3 are lungimea2(1+L(5))
pentru ca 7 este egal cu 7;
-algoritmul continua in acest mod pana se completeazaL(1).

#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

int v[20],l[20],n,i,k,max,t;
main()
{
cout<<"n="; cin>>n;
for(i=1;i<=n;i++)
{cout<<"v["<<i<<"]=";cin>>v[i];
}
l[n]=1;
for(k=n-1;k>=1;k--)
{
int max=0;
for(i=k+1;i<=n;i++)
if ( v[i]>=v[k] && l[i]>max)
max=l[i];
l[k]=1+max;
}
int max=l[1]; t=1;
for(k=1; k<=n;k++)
if (l[k]>max)
{max=l[k]; t=k;}
cout<<"lungimea maxima:"<<max<<endl<<v[t]<<endl;
for(i=t+1;i<=n;i++)
if (v[i]>v[t]&& l[i] ==max-1)
{cout<<v[i] << endl;
max--;
}
}
//sa se determine prin programare dinamica
//imultirea otima a unui sir de matrice
// ex:4
// 10
// 1
// 10
// 1
// 10
Sa consideram produsul de matrice A1xA2x....xAn (A1(d1,d2),A2(d2,d3)...,An(dn,dn+1)).Se
cunoaste ca legea de compozitie produs de matrice nu este comutativa in schimb este
asociativa.De exemplu ,daca avem de inmultit trei m atrice A,B,C produsul se poate face in
doua moduri:(AxB) xC; Ax(BxC).Este interesant de observat ca nu este indiferent modul de
inmultire a celor n matrice.Sa considera ca avem de inmultit patru matrice
A1(10,1),A2(1,10),A3(10,1),A4(1,10).
Pentru inmultirea lui A1 cu A2 se fac 100 de inmultiri si se obtine o matrice cu 10 lini si 10
coloane.Prin inmul
tirea acesteia cu A3 se fac 100 de inmultiri si se obtine o matrice cu 10 linii si o coloana.daca
aceasta matrice se inmulteste cu A4 se fac 100 inmultiri. In concluzie, daca acest produs se
efectueaza in ordine naturala,se efectueaza 300 inmultiri.
SAefectuam acelas produs in ordinea care rezulta din expresia A1x((A2XA3) x A4).Efectuand
produsul A2 cu A3 se efectueaza 10 inmultiri si se obtine o matrice cu o linie si cu o
coloana.aceasta matrice se inmulteste cu A4 se fac 10 inmultiri si se obtine o matrice cu 1 linie
si 10 coloane.Daca o inmultim pe aceasta cu prima, efectuam 100 inmtltiri , obtinand rezultatul
final cu numai 120 de inmultiri.

#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

int i,n,dim[10];
int a[10][10];

void costopt(int n,int dim[10],int a[10][10])


{int k,i,j,l;
long m;
for (i=1;i<=n;i++) a[i][i]=0;
for (k=1;k<=n-1;k++)
for (i=1;i<=n-k;i++)
{ j=i+k;
a[i] [j]=100000;
for(l=i;l<=j;l++)
{m=a[i] [l] +a[l+1] [j]+dim[i]*dim[l+1]*dim[j+1];
if (a[i] [j]>m)
{
a[i] [j]=m;;
a[j] [i]=l;
}
}
}
cout<<"cost optim:"<<a[1][n]<<endl;

}
main()
{cout<<"n=";cin>>n;
for (i=1;i<=n+1;i++)
{ cout<<"d=";cin>>dim[i];}
costopt(n,dim,a);
}
Alocarea dinamica a memoriei

Variabile de tip pointer


Memoria interna poate fi privita ca o succesiune de octeti.Numarul de ordine al unui octet
se numeste adresa lui.Adresa unei variabile nu trebuie confundata cu valoarea pe care
aceasta o memoreaza.
Definitie: Adresa primului octet al variabilei se numeste adresa variabilei.
Adresele variabilelor se memoreaza cu ajutorul variabilelor de tip pointer.
Tipul unei variabile de tip pointer se declara astfel:
tip *nume
Adresa unei variabile se obtine cu ajutorul operatorului ‘ & ‘, care trebuie sa preceada numele
variabilei:
&Nume_variabila;

//sa se puna in evidenta notiunea de pointer si adresa

#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;
void main()
{
int a=7, *adr=&a;
cout<<*adr;
}
//sa se puna in evidenta notiunea de pointer si adresa
//la structuri de date
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

struct elev
{
char nume[20], prenume[20];
};

void main()
{
elev a, *adra=&a;
strcpy(a.nume, "Bojian");
strcpy(a.prenume, "Andronache");
cout<<(*adra).nume<<" "<<(*adra).prenume<<endl;

}
Alocarea dinamica a memoriei

Spatiul necesar memorarii este rezervat in HEAP, in timpul executiei


programului, iar atunci cand variabila nu mai este utila, spatiul din
memorie este eliberat.
In C++, pentru alocarea dinamica se utilizeaza urmatorii operatori:
 Operatorul new aloca spatiu in HEAP pentru o variabila
dinamica.Dupa alocare, adesa variabilei se atribuie lui p, care este o
variabila de tip pointer catre tip:
p=new tip
 Operatorul delete elibereaza spatiul rezervat pentru variabila a
carei adresa este retinuta in p.Dupa eliberare, continutul variabilei p
este nedefinit.
delete p
//sa se puna in evidenta notiunea de alocare dinamica si eliberarea
spatiului
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

void main()
{
int *adr1;
adr1=new int;
*adr1=7;
cout<<*adr1;
delete adr1;

}
//sa se puna in evidenta notiunea de alocare dinamica si eliberarea
spatiului
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

void main()
{
float* adresa;
adresa=new float;
*adresa=7.65;
cout<<adresa<<endl;
cout<<*adresa;
delete adresa;
}
//sa se puna in evidenta notiunea de alocare dinamica si
//eliberarea spatiului la structuri
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;
struct inreg
{ char nume[20], prenume[20];
int varsta;
};

void main()
{ inreg* adr;
adr=new inreg;
cin>>adr->nume>>adr->prenume>>adr->varsta;
cout<<adr->nume<<adr->prenume<<adr->varsta;
delete adr;
}
Alocarea dinamica a masivelor
 Un tablou p-dimensional se declara astfel:
tip nume[n1] [n2] … [np]
 Numele tabloului de tip p-dimensional de mai sus este pointer constant catre un
tablou p-1 dimensional de forma [n2] … [np], care are componentele de baza de
acelasi tip cu cele ale tabloului.
 Un pointer catre un tablou k dimensional cu [l1] [l2] …[lk] componente de un
anumit tip
se declara astfel:
tip (*nume) [l1] [l2] …[lk];
 Intrucat numele unui masiv p dimensional este pointer catre un masiv p-1
dimensional, pentru a aloca dinamic un masiv se va utiliza un pointer catre masive
p-1 dimensionale (ultimele p-1 dimensiuni).

//sa se puna in evidenta notiunea de alocare dinamica si


//eliberarea spatiului la tablouri
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

void main()
{ int *a=new int[4];
a[3]=2;
cout<<a[3];
delete a;
}
//sa se puna in evidenta notiunea de alocare dinamica si
//eliberarea spatiului la tablouri
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

void main()
{ double (*a)[5]=new double [3] [5];
a[1][2]=7.8;
cout<<a[1][2];
delete a;
}
//sa se puna in evidenta notiunea de alocare dinamica si
//eliberarea spatiului la tablouri bidimensionale

#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

main ( )
{
int m,n,i,j,(*adr)[10];
adr=new int[10] [10];
cout<<"m="; cin>>m;
cout<<"n="; cin>>n;
for(i=0;i<m;i++)
for(j=0;j<n;j++)
cin>>adr[i][j];
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
cout<<adr[i][j]<<" ";
cout<<endl;
}
delete adr;
}
//sa se puna in evidenta notiunea de alocare dinamica si
//eliberarea spatiului la tablouri bidimensionale
//sa se sumeze doua maatrice si sa se returneze un pointer catre un
VOID
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

void* Cit_Mat(int m, int n)


{
int i,j,(*adr1)[10]=new int [10] [10];
for(i=0;i<m;i++)
for(j=0;j<n;j++) cin>>adr1[i][j];
return adr1;
}
void Tip_Mat(int m, int n, int(*adr1)[10])
{ int i,j;
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
cout<<adr1[i][j]<<" ";
cout<<endl;
}
}
void* Suma_Mat(int m, int n, int(*adr1)[10],int (*adr2)[10])
{ int i,j,(*adr)[10]=new int[10][10];
for(i=0;i<m;i++)
for(j=0;j<n;j++) adr[i][j]=adr1[i][j]+adr2[i][j];
return adr;
}
main ( )
{ int m,n,i,j,(*adr)[10],(*adr1)[10],(*adr2)[10];
cout<<"m="; cin>>m;
cout<<"n="; cin>>n;
adr1=(int(*)[10]) Cit_Mat(m,n);
adr2=(int(*)[10]) Cit_Mat(m,n);
adr=(int(*)[10]) Suma_Mat(m,n,adr1,adr2);
Tip_Mat(m,n,adr);
}
//• Pentru fiecare dintre cele n materiale aflate intr-o magazie se
cunoaste: denumirea materialului, unitatea de masura si cantitatea
care se gaseste in magazie.Programul de mai jos citeste informatiile
si le organizeaza astfel:
//-segmentul de date contine un vector cu n componente, unde
fiecare componenta
//retine un pointer catre inregistrarea cu datele citite pentru
fiecare material;
//-datele citite pentru fiecare material se organizeaza ca
struct, alocat in HEAP.

#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

struct material
{ char denumire[20], unit_mas[5];
float cantitate;
};
void Cit_Material(int i,material* v[100])
{
v[i]=new material;
cout<<"Denumire "; cin>>v[i]->denumire;
cout<<"Unitate de masura "; cin>>v[i]->unit_mas;
cout<<"Cantitate "; cin>>v[i]->cantitate;
}
void Tip_Material(int i,material* v[100])
{
cout<<v[i]->denumire<<endl<<v[i]->unit_mas<<endl<<v[i]->cantitate;
}
main ( )
{ int n,i;
material* v[100];
cout<<"n="; cin>>n;
for(i=0;i<n;i++) Cit_Material(i,v);
for(i=0;i<n;i++) Tip_Material(i,v);
}
Liste liniare
Definitia listelor

Def.:O lista liniara este o colectie de n>=0 noduri, X1,X2,…,Xn, aflate intr-o relatie de
ordine.Astfel, X1 este primul nod al listei, X2 este al doilea nod al listei,…, Xn este ultimul
nod.Operatiile permise sunt:
 Accesul la oricare nod al listei in scopul citirii sau modificarii informatiei continute de
acesta.
 Adaugarea unui nod, indiferent de pozitia pe care o ocupa in lista.
 Stergerea unui nod,indiferent de pozitia pe care o ocupa in lista.
 Schimbarea pozitiei unui nod in cadrul listei.

Liste liniare alocate simplu inlantuit

Prezentare generala

O lista liniara simplu inlantuita este o structura de forma:


in1 adr1 in2 adr2 inn 0

adr1 adr2 adrn

Dupa cum se observa, fiecare nod, cu exceptia ultimului, retine adresa nodului
urmator.
1. Accesul la un nod al listei se face parcurgand nodurile care il preced.
2. Informatiile ocupa memorie, fiind prezente in cadrul fiecarui nod.
3. Avantajele alocarii inlantuite sunt date de rapiditatea operatiilor de adaugare si
eliminare.
//sa se puna in evidenta notiunea de lista simplu inlantuita
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

struct Nod
{
int info;
Nod* adr_urm;
};

Nod*v;
int nr;

void Adaug(Nod*& v, int nr)


{
Nod* c=new Nod;
c->info=nr;
c->adr_urm=v;
v=c;
}

void Tip(Nod* v)
{
Nod*c=v;
while(c)
{
cout<<c->info<<endl;
c=c->adr_urm;
}
}

main( )
{
cout<<"numar="; cin>>nr;
while(nr)
{
Adaug(v,nr);
cout<<"numar="; cin>>nr;
};
Tip(v);
}
//sa se puna in evidenta notiunea de lista simplu inlantuita
// si operatii cu liste simple
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

#include<iostream>
#include<math.h>
using namespace std;

struct Nod
{
int info;
Nod* adr_urm;
};

Nod* v,*sf;
int i;

void Adaugare(Nod*& v, Nod*& sf, int val)


{
Nod* c;
if(v==0)
{
v=new(Nod); v->info=val; v->adr_urm=0;
sf=v;
}
else
{
c=new(Nod); sf->adr_urm=c;
c->info=val; c->adr_urm=0;
sf=c;
}
}

void Inserare_dupa(Nod* v, Nod*& sf, int val, int val1)


{
Nod* c=v, *d;
while(c->info!=val) c=c->adr_urm;
d=new Nod; d->info=val1;
d->adr_urm=c->adr_urm; c->adr_urm=d;
if(d->adr_urm==0) sf=d;
}
void Inserare_inainte(Nod*& v, int val, int val1)
{
Nod* c,*d;
if(v->info==val)
{
d=new Nod; d->info=val1; d->adr_urm=v; v=d;
}
else
{
c=v;
while(c->adr_urm->info!=val) c=c->adr_urm;
d=new Nod; d->info=val1; d->adr_urm=c->adr_urm; c->adr_urm=d;
}
}

void Sterg(Nod*& v, Nod*& sf, int val)


{
Nod* c,*man;
if(v->info==val)
{
man=v; v=v->adr_urm;
}
else
{
c=v;
while(c->adr_urm->info!=val) c=c->adr_urm;
man=c->adr_urm; c->adr_urm=man->adr_urm;
if(man==sf) sf=c;
}
delete man;
}

void Tip(Nod* v)
{
Nod*c=v;
while(c)
{
cout<<c->info<<endl;
c=c->adr_urm;
}
}

main( )
{
for (i=1;i<=10;i++)
Adaugare(v,sf,i);
Tip(v);
Inserare_dupa(v,sf,7,11);
Inserare_dupa(v,sf,10,12);
Inserare_dupa(v,sf,1,13);
Tip(v);
Inserare_inainte(v,13,14);
Inserare_inainte(v,1,15);
Tip(v);
Sterg(v,sf,15);
Sterg(v,sf,13);
Sterg(v,sf,12);
Tip(v);
}
//sa se puna in evidenta notiunea de lista simplu inlantuita
// si sortarea prin insertie a acesteia
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

const MaxInt=32000;
struct Nod
{
int info;
Nod* adr_urm;
};
int n,i;
Nod *v,*adr,*c,*c1;
main ( )
{
cout<<"n="; cin>>n;
v=new Nod; v->info=MaxInt; v->adr_urm=0;
for(i=1;i<=n;i++)
{
adr=new Nod;
cout<<"numar="; cin>>adr->info;
if(adr->info<=v->info)
{
adr->adr_urm=v;
v=adr;
}
else
{
c=v;
c1=v->adr_urm;
while(c1->info<adr->info)
{
c=c->adr_urm;
c1=c1->adr_urm;
}
c->adr_urm=adr;
adr->adr_urm=c1;
}
}
c=v;
while(c->info!=MaxInt)
{
cout<<c->info<<endl;
c=c->adr_urm;
}
}
Liste alocate dublu inlantuit

O lista alocata dublu inlantuit este o structura de date de forma:

0 in1 adr2 adr1 in2 adr3 adrn-1 inn 0 0


0000adr3
adr1 adr2
adrn

Operatiile posibile asupra unei liste dublu inlantuite sunt:

1) creare;
2) adaugare la dreapta;
3) adaugare la stanga;
4) adaugare in interiorul listei;
5) stergere din interiorul listei;
6) stergere la stanga listei;
7) stergere la dreapta listei;
8) listare de la stanga la dreapta;
9) listare de la dreapta la stanga.

1) Creare

O lista dublu inlantuita se creeaza cu o singura inregistrare.Pentru a ajunge la


numarul de inregistrari dorit, utilizam functii de adaugare la stanga si la
dreapta.Functia creare realizeaza citirea informatiei numerice, alocarea de
spatiu pentru inregistrare, completarea inregistrarii cu informatia si
completarea adreselor la dreapta si la stanga cu 0.

2) Adaugare la dreapta

Functia add citeste informatia numerica, aloca spatiu pentru inregistrare,


completeaza adresele, modifica adresa la dreapta a inregistrarii din s cu adresa
noii inregistrari si ii atribuie
lui s valoarea noii inregistrari.

3) Adaugare la stanga

4) Adaugare in interiorul listei

Functia includ parcurge lista pentru a gasi inregistrarea cu informatia m, in


dreapta careia urmeaza sa introducem noua inregistrare, citeste informatia,
aloca spatiu, completeaza informatia, completeaza adresa stanga a noii
inregistrari cu valoarea adresei inregistrarii de informatie m, si completeaza
adresa dreapta a noii inregistrari cu valoarea adresei dreapta a inregistrarii cu
informatia utila m.
5) Stergere in interiorul listei

Functia Sterg parcurge lista pentru a gasi informatia care va fi stearsa, atribuie
inregistrarii precedente campul de adresa dreapta al inregistrarii care va fi
stearsa, iar inregistrarii care urmeaza celei care va fi stearsa i se atribuie campul
de adresa stanga al inregistrarii pe care o stergem, dupa care se elibereaza
spatiul de memorie rezervat inregistrarii care se sterge.

6)-7) Stergere la stanga si la dreapta listei

8) Listare de la stanga la dreapta

Functia listare porneste din stanga listei si tipareste informatia numerica a


fiecarei inregistrari, atata timp cat nu s-a ajuns la capatul listei.

9) Listare de la dreapta la stanga

//sa se puna in evidenta notiunea de lista dubleu inlantuita


// si operatii cu aceasta
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

struct Nod
{ Nod *as,*ad;
int nr;
};

Nod *b,*s,*c;
int n,m,i;

void Creare(Nod*& b, Nod*& s)


{ cout<<"n="; cin>>n;
b=new Nod; b->nr=n;
b->as=b->ad=0;
s=b;
}
void Addr(Nod*& s)
{ cout<<"n="; cin>>n;
Nod* d=new Nod;
d->nr=n;
d->as=s; d->ad=0;
s->ad=d; s=d;
}

void Listare(Nod*& b)
{ Nod* d=b;
while(d)
{ cout<<d->nr<<endl;
d=d->ad;
}
}

void Includ(int m,Nod* b)


{
Nod *d=b, *e;
while(d->nr!=m) d=d->ad;
cout<<"n="; cin>>n;
e=new Nod;
e->nr=n;
e->as=d;
d->ad->as=e;
e->ad=d->ad;
d->ad=e;
}

void Sterg(int m, Nod *b)


{ Nod* d=b;
while(d->nr!=m) d=d->ad;
d->as->ad=d->ad;
d->ad->as=d->as;
delete d;
}

main ( )
{ cout<<"Creare lista cu o singura inregistrare "<<endl;
Creare(b,s);
cout<<"Cate inregistrari se adauga ?"; cin>>m;
for(i=1;i<=m;i++) Addr(s);
cout<<"Acum listez de la stanga la dreapta"<<endl;
Listare(b);
cout<<"Includem la dreapta o inregistrare"<<endl;
cout<<"Dupa care inregistrare se face includerea?"; cin>>m;
Includ(m,b);
cout<<"Acum listez de la stanga la dreapta"<<endl;
Listare(b);
cout<<"Acum stergem o inregistrare din interior"<<endl;
cout<<"Ce inregistrare se sterge?";
cin>>m;
Sterg(m,b);
cout<<"Acum listez de la stanga la dreapta"<<endl;
Listare(b);
}
Grafuri orientate
Grafuri orientate –notiuni de baza

Grafuri orientate – noţiuni de bază

Noţiunea de graf orientat.


Un exemplu de graf orientat este: reţeaua de străzi a unui oraş. Străzile sunt muchii în graf, iar
intersecţiile reprezintă vârfurile grafului. Întrucât mergând pe jos ne putem deplasa pe orice stradă în
ambele sensuri, vom spune că din punctul de vedere al pietonilor, „graful unui oraş” este neorientat.
Cu totul altfel stau lucrurile în ceea ce priveşte conducătorii auto, pentru că în orice oraş există străzi cu
sens unic. Pentru un şofer străzile trebuie să primească în graf o anumită orientare. Desigur că acele
străzi pe care se poate circula în ambele sensuri vor primi orientare dublă. Am ajuns astfel la noţiunea
de graf orientat.
Numim graf orientat, o pereche ordonată de mulţimi G=(X,U), unde:
X este o mulţime finită şi nevidă numită mulţimea nodurilor (vârfurilor);
U este o mulţime formată din perechi ordonate de elemente ale lui X, numită mulţimea arcelor
(muchiilor)
observaţii:
Prin noţiunea de perechi ordonate nu trebuie să
înţelegem că o muchie este mai mare decât alta, ci pur
U1
şi simplu că facem deosebire între o muchie de forma
(x,z) şi o alta de forma (y,x). Cu alte cuvinte muchiile
1
sunt diferenţiate prin ordinea de scriere a simbolurilor.
Arcul (x,y) nu este tot una cu arcul (y,x).
Exemplu: U2
Pentru graful G=(X,U) din figura 1. avem: X={1, 2, 3, 4}
2
şi U={u1, u2, u3, u4, u5, u6, u7,}= {(1,1), (2,1), (3,2),
(2,3), (2,4), (3,4), (3,4)} U3
arc va fi de forma u= (x,y), unde x se numeşte U5
extremitate iniţială, iar y se numeşte extremitate finală a U4
arcului. Cu alte cuvinte, “arcul iese din nodul x şi intră în
nodul y”. La fel ca la grafurile neorientate, vom spune că 3
nodurile x şi y sunt adiacente, iar arcul u şi nodul x sunt U6
incidente (la fel arcul x şi nodul y). Nodul y se numeşte 4
succesor al lui x, iar nodul x se numeşte predecesor al
U7
lui y. Un arc de forma (x,x), care iese din nodul x şi intră
tot x, se numeşte buclă.
Exemplu: Figura1
În graful din figura 1, avem bucla (1,1).
Într-un graf putem avea două sau mai multe arce identice.
Exemplu:
În graful din figura 1, există două arce identice, u6 = u7 = (3,4)
Definiţie
Se numeşte p-graf, un graf orientat în care numărul arcelor identice este mai mic sau egal cu o valoare
dată p.
În cele ce urmează vom analiza numai 1-grafuri fără bucle.
Graful unui vârf. Mulţimile Γ şi ω
Gradul exterior al unui vârf x, notat d*(x), reprezintă numărul arcelor care ies din nodul x, adică numărul
arcelor de forma (x,z) ε U.
Analog, se defineşte gradul interior al unui vârf x, notat d-(x), ca fiind numărul arcelor care intră în nodul
x (de forma (y,x) ε U).
Exemplu:
În graful reprezentat în figura 1, pentru nodul x=2, avem:
d*(2) =3 → există trei arce care ies din nodul 2, şi anume : u2=(2,1), u4=(2,3) şi u5 = (2,4).
d-(2) =1 → în nodul 2 intră un singur arc, în speţă arcul u3=(3,2).
Se mai definesc următoarele mulţimi:
  x   y  X x, y  U 
→ mulţimea nodurilor ce constituie extremităţi finale ale arcelor care
pleacă din nodul x. Pe scurt, mulţimea succesorilor lui x;
  x   y  X  y, x  U 
→ mulţimea nodurilor ce constituie extremităţi iniţiale ale arcelor care
pleacă din nodul x. Pe scurt, mulţimea predecesorilor lui x;
Exemplu:
În graful din figura 1, pentru nodul x=2, avem:
- Γ+(2) = {1,3,4} → urmare a faptului că muchiile care pleacă din nodul 2 sunt (2,1), (2,3) şi (2,4), putem
spune că mulţimea succesorilor nodului 2 este {1,3,4}.
- Γ-(2) = {3} → în nodul 2 intră doar muchia (3,2), deci mulţimea predecesorilor lui 2 conţine doar nodul
3.
ω+(x) = {u = (x,y)| u ε U} → mulţimea arcelor care ies din nodul x;
ω-(x) = {u = (y,x)| u ε U} → mulţimea arcelor care intră în nodul x;
Exemplu:
În graful din figura 1, pentru nodul 2, avem:
ω+(x) = {(2,1), (2,3), (2,4)}, ω-(x) = {(3,2)}
Graf parţial şi subgraf
Fie graful G = (X,U). Un graf parţial al lui G, este un graf G 1= (X,V), cu V  U . Altfel spus, un graf
parţial G1 al lui G, este chiar G, sau se obţine din G păstrând toate vârfurile şi suprimând nişte muchii.
Fie graful G = (X,U). Un graf parţial al lui G, este un graf G 1= (Y,T), unde V  X şi T  U , iar T va
conţine numai muchiile care au ambele extremităţi în Y. Altfel spus, un graf parţial G 1 al lui G, se obţine
din G eliminând nişte vârfuri şi păstrând doar acele muchii care au ambele extremităţi în mulţimea
vârfurilor rămase.
Exemplu:
Se consideră graful G = (X,U) din figura 2, în care X = {1,2,3,4,5,6} şi U={u1, u2, u3, u4, u5, u6, u7}.
- Construim graful parţial G1 = (X,V), unde X = {1,2,3,4,5,6} şi V = { u2, u3, u4, u6, u7} (figura 3)
din graful G au fost eliminate arcele u1 şi u5.
- Construim subgraful G2 = (Y,T), unde Y = {3,4,5,6} şi T = {u4, u5, u6, u7} (figura 4) din graful G
au fost eliminate nodurile 1 şi 2 precum şi arcele u1, u2 şi u3 care au o extremitate în afara
mulţimii nodurilor rămase.
Reprezentarea grafurilor orientate
Considerăm un graf orientat G= (X,U) cu m arce şi n noduri.
Cele mai cunoscute forme de reprezentare sunt: matricea de adiacenţă, matricea vârfuri – arce,
matricea drumurilor şi listele vecinilor.
Matricea de adiacenţă

u2 u2
1 2 1 2
u1
u3 u3
u4 u5 u4 u4
3 3 3 u5
4 4 4
5 5 5
u7 u6 u7 u7
u6 u6

6 6 6
Figura 2 Figura 3 Figura 4

Are aceeaşi semnificaţie ca în cazul grafurilor neorientate: fiecare element a[i,j], cu i,j ε {1,2,...,n}, este: 1
dacă există arcul (i,j), respectiv 0 în caz contrar.
Datorită orientării, aşa cum am mai spus, arcul (i,j) nu este totuna cu arcul (j,i). Prin urmare, a[i,j] ≠ a[j,i].
Aşadar matricea de adiacenţă nu mai este simetrică faţă de diagonala principală, aşa cum se întâmpla
în cazul grafurilor neorientate.
Exemplu:
Pentru graful G=(X,U) din figura 5, matricea de adiacenţă este:
coloana 1 2 3 4

0 0 0 0 1

1 0 1 1 2
A=
0 0 0 1 3

0 1 0 0 4

2
3

Continuăm cu câteva 1 aplicaţii.


Aplicaţie:
Citirea de la tastatură şi 4 afişarea matricei
de adiacenţă
Figura 5

Prin citirea matricei de adiacenţă de la tastatură, putem memora arcele existente între nodurile
unui graf. În cazul grafurilor neorientate, citeam doar “porţiunea” de deasupra diagonalei
principale în matrice, deoarece matricea este simetrică. Acum trebuie să citim toate elementele
matricei. Avem de-a face cu algoritmii banali de citire şi afişare a unei matrice cu n linii şi n
coloane (unde n este numărul de noduri) în două cicluri for, deci nu considerăm că mai sunt
necesare alte explicaţii.
Matricea vârfuri – arce
Este o matrice b cu n linii şi m coloane, în care fiecare element b[i,j] este:
- 1, dacă nodul i este o extremitate iniţială a arcului u j;
- -1, dacă nodul i este o extremitate finală a arcului u j;
- 0, dacă nodul i nu este o extremitate a arcului uj.
Exemplu:
Pentru graful de mai jos cu n=4 noduri şi m=5 arce, matricea vârfuri – arce este:
1 0 0 0 0

-1 -1 -1 0 0

0 1 0 1 -1

0 0 1 -1 1
2

u1 u3
u2
1
u4
3 4

u5
Figura 6

Pentru a exemplifica construcţia matricei, vom deduce elementele liniei 3:


- a[3,1]= 0 pentru că nodul 3 nu este o extremitate a arcului u1. Analog, a[3,3]= 0 deoarece
nodul 3 nu este extremitate a arcului u3.
- a[3,5]= -1 pentru că nodul 3 este o extremitate finală a arcului u5.
- a[3,2]= 1 şi a[3,4]= 1 întrucât nodul 3 este o extremitate iniţială a arcului u2 respectiv u4.
Observaţii:
Pe fiecare coloană j (aferentă arcului uj), avem exact două elemente nenule: un 1 (linia i pe care se află
reprezintă extremitatea iniţială a arcului uj) şi un -1 (linia i pe care se află reprezintă extremitatea finală a
arcului uj)
Numărul valorilor de 1 de pe linia i, reprezintă gradul exterior al nodului i (numărul arcelor ce au ca
extremitate iniţială pe i), iar numărul valorilor de -1 de pe linia i reprezintă gradul interior al nodului i
(numărul arcelor care au ca extremitate finală pe i).
Listele vecinilor
Pentru fiecare nod x se construiesc două liste ale vecinilor săi:
- L*(x) → lista vecinilor succesori; conţine nodurile ce sunt extremităţi finale ale arcelor care ies
din nodul x.
- L-(x) → lista vecinilor predecesori; conţine nodurile ce sunt extremităţi iniţiale ale arcelor care
intră în nodul x.
Exemplu:
În graful din figura 6 de mai sus, pentru nodul x=4 avem:
- arcele care ies din nodul 4 sunt (4,2) şi (4,3). În consecinţă, lista vecinilor succesori L*(4)
conţine nodurile 2 şi 3;
- în nodul 4 intră un singur arc, şi anume (3,4), motiv pentru care lista vecinilor predecesori L-(4)
conţine doar nodul 3.
Prezentăm în continuare aceste liste ale vecinilor pentru graful din figura 6.

Nodul x L*(x) L-(x)


1 2 vidă
2 vidă 1,3,4
3 2,4 4
4 2,3 3

Matricea drumurilor
Această matrice va fi reprezentată în cadrul capitolului “Drumuri şi circuite în grafuri orientate”.
Reprezentarea grafului ca un vector de muchii
Fiecare arc al grafului poate fi privit ca o înregistrare cu două componente, în speţă cele două noduri
care constituie extremităţile arcului:
- nod_in -> nodul din care iese arcul (“nodul de început” al arcului);
- nod_sf -> nodul în care intră arcul (“nodul de sfârşit” al arcului);
Putem defini tipul de date ARC, astfel:
Drumuri si circuite in grafuri orientate
Se numeşte lanţ intr-un graf orientat, o mulţime de arce L={u 1,u2,...,uk}, cu proprietatea ca oricare doua
arce vecine in mulţime au o extremitate comuna.
Un lanţ este de fapt un traseu care uneşte prin arce doua noduri numite extremităţile lanţului, fără a tine
cont de orientarea arcelor componente.
Se numeşte drum în graful G, un şir de noduri D={z 1, z2, z3, …, zk}, unde z1, z2, z3, …, zk aparţin lui x, cu
proprietatea că oricare două noduri consecutive sunt adiacente, adică există arcele [z 1, z2], [z2, z3], …,
[zk-1,zk] aparţin lui U.
Practic, un drum poate fi privit ca un traseu în care toate arcele au aceeaşi orientare, dată de sensul de
deplasare de la z1 la zk.
Dacă nodurile z1, z2, z3, …, zk sunt distincte două câte două, drumul se numeşte elementar. În caz
contrar, drumul este ne-elementar.
Asemenea uni lanţ într-un graf neorientat, un drum într-un graf orientat este de fapt un traseu pe care l-
am parcurge între două noduri deplasându-ne de-a lungul unor arce şi trecând prin nişte noduri
intermediare. Deosebirea unui drum faţă de un lanţ constă în faptul că de-a lungul unui arc ne putem
deplasa numai în sensul dat de orientarea arcului.
Se numeşte circuit într-un graf, un lanţ L={z 1, z2, z3, …, zk} cu proprietatea că z1=zk şi arcele [z1, z2], [z2,
z3], …, [zk-1,zk] sunt distincte două câte două.
Dacă într-un circuit, toate nodurile cu excepţia primului şi ultimului sunt distincte două câte două, atunci
circuitul se numeşte elementar. În caz contrar, el este ne-elementar.

u2
1 2

u1
u3
u4 u5
3
4
5
u7 u6

6
Figura 8

Matricea drumurilor.
Este o matrice d cu n linii şi n coloane, în care fiecare element d[i,j] este :
- 1, dacă există drum de la nodul i la nodul j în graf;
- 0, în caz contrar.
Algoritmul Roy-Warshall de determinare a matricei drumurilor
Matricea drumurilor se obţine aplicând matricei de adiacenţă transformări succesive. Vom spune că
există drum de la nodul i la nodul j, dacă găsim un nod k (diferit de i, j) cu proprietatea că există drum de
la i la k şi drum de la j la k. Astfel:
 un element a[i, j] care este 0, devine 1, dacă există un nod k astfel încât a[i, k]=1 şi a[k, j]=1.
Pentru a găsi arcele nodului k, trebuie parcurse pe rând în varianta k toate nodurile 1, 2, …, n.

Metode de reprezentare in memorie


a unui graf

Exista mai multe metode de reprezentare in memorie a unui graf orientat:


1-metoda matricei adiacente:
1, pentru[I,j] apartin de g
a[I,j]=

0, pentru[I,j]nu apartinde g
fisierul graf.txt este in calea: C:\Documents and Settings\ticatica\My Documents\Visual Studio
Projects\p2
//sa se puna in evidenta notiunea de matrice de adiacenta si
//sa se listeze dintr-un fisier
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;
#include<fstream>

int A[50][50],n,I,j;
void Citire(char Nume_fis[20],int a[50][50],int& n)
{
fstream f(Nume_fis,ios::in);
int I,j;
f>>n;
while (f>>I>>j) A[I][j]=1;
f.close();
}

main()
{
Citire("Graf.txt",A,n);
for (I=1;I<=n;I++)
{ for (j=1;j<=n;j++) cout <<A[I][j]<<" ";
cout<<endl;
}
}
Parcurgerea grafurilor orientate

Parcurgerea in latime(BF-breadth first)


-parcurgerea in latime se face incepand de la un nod I, pe care il consideram parcurs;
-parcurgem apoi toti descendentii sai – multimea nodurilor j pentru care exista
[I,j]apartin de g;
-parcurgem apoi toti descendentii nodurilor parcurse la pasul anterior.
Parcurgerea BF se efectueaza prin utilizarea structurii numita coada, avand grija ca un
nod sa fie vizitat o singura data. Coada va fi alocata prin utilizarea unui vector.
Fie graf.txt ce contine:
7
1 2
1 6
1 3
3 6
2 5
2 4
3 7
=>1 3 2 6 4 5 7
//sa se puna in evidenta parcurgerea in latime la grafuri
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;
#include<fstream>

int coada[50],s[50],A[50][50],I_c,sf_c,I,j,n;
void bf_r1()
{ int k;
if (I_c<=sf_c)
{ for (k=1;k<=n;k++)
if ( (A[coada[I_c]][k]==1) && (s[k]==0) )
{ sf_c++;
coada[sf_c]=k;
s[k]=1;
}
I_c++;
bf_r1();
}
}
void Citire(char Nume_fis[20],int a[50][50],int& n)
{
fstream f(Nume_fis,ios::in);
int I,j;
f>>n;
while (f>>I>>j) A[I][j]=1;
f.close();
}
main()
{
Citire("Graf.txt",A,n);
for (I=1;I<=n;I++)
{ for (j=1;j<=n;j++) cout <<A[I][j]<<" ";
cout<<endl;
}
I_c=sf_c=1;
coada[I_c]=s[1]=1;
bf_r1();
for(I=1;I<=sf_c;I++)cout<<coada[I]<<" ";
}

Parcurgerea in adancime(DF-depth first)

-se face incapand de la un nod I


-dupa parcurgerea unui nod se parcurge primul dintre descendntii sai
neparcursii inca.

Parcurgerea in latime(BF-breadth first)


-parcurgerea in latime se face incepand de la un nod I, pe care il consideram parcurs;
-parcurgem apoi toti descendentii sai – multimea nodurilor j pentru care exista
[I,j]apartin de g;
-parcurgem apoi toti descendentii nodurilor parcurse la pasul anterior.
Parcurgerea BF se efectueaza prin utilizarea structurii numita coada, avand grija ca un
nod sa fie vizitat o singura data. Coada va fi alocata prin utilizarea unui vector.
Fie graf.txt ce contine:
7
1 2
1 6
1 3
3 6
2 5
2 4
3 7
=>1 2 4 5 3 6 7
//sa se puna in evidenta parcurgerea in adancime la grafuri
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;
#include<fstream>

int s[50],A[50][50],I,j,n;
void df_r(int nod)
{
int k;
cout<<nod<<" ";
s[nod]=1;
for (k=1;k<=n;k++)
if ((A[nod][k]==1) && (s[k]==0))
df_r(k);
}

void Citire(char Nume_fis[20],int a[50][50],int& n)


{
fstream f(Nume_fis,ios::in);
int I,j;
f>>n;
while (f>>I>>j) A[I][j]=1;
f.close();
}
main()
{
Citire("Graf.txt",A,n);
for (I=1;I<=n;I++)
{ for (j=1;j<=n;j++) cout <<A[I][j]<<" ";
cout<<endl;
}
df_r(1);
}

// cu liste de adiacenta sa se implemeteze


//parcurgerea in adancime
// 7
// 1 2
// 1 6
// 1 3
// 3 6
// 2 5
// 2 4
// 3 7
//=>1 3 7 6 2 5 4

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

struct Nod
{
int nd;
Nod* adr_urm;
};

int s[50],n;
Nod *L[50];
void df_r1(int nod)
{
Nod* p;
cout<<nod<<" ";p=L[nod];
s[nod]=1;
while (p)
{
if (s[p->nd]==0)
df_r1(p->nd);
p=p->adr_urm;
}
}

void Citire_1( Nod* L[50], int& n)


{
Nod* p;
int I,j;
fstream f("graf.txt",ios::in);
f>>n;
for (I=1;I<=n;I++) L[I]=0;
while (f>>I>>j)
{ p=new Nod;
p->adr_urm=L[I]; p->nd=j;
L[I]=p;
}
f.close();
}
main()
{
Citire_1(L,n);
df_r1(1);
}
// cu liste de adiacenta sa se implemeteze
//parcurgerea in latime recursiv
// 7
// 1 2
// 1 6
// 1 3
// 3 6
// 2 5
// 2 4
// 3 7
//=>1 3 6 2 7 4 5

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

struct Nod
{
int nd;
Nod* adr_urm;
};
Nod* L[50],*p;
int coada[50],s[50],I_c,sf_c,I,n;
void bf_r1()
{
Nod*p;
if (I_c<=sf_c)
{
p=L[coada[I_c]];
while (p)
{
if (s[p->nd]==0)
{
sf_c++;
coada[sf_c]=p->nd;
s[p->nd]=1;
}
p=p->adr_urm;
}
I_c++;
bf_r1();
}
}

void Citire_1( Nod* L[50], int& n)


{
Nod* p;
int I,j;
fstream f("graf.txt",ios::in);
f>>n;
for (I=1;I<=n;I++) L[I]=0;
while (f>>I>>j)
{ p=new Nod;
p->adr_urm=L[I]; p->nd=j;
L[I]=p;
}
f.close();
}

main()
{ Citire_1(L,n);
I_c=1; sf_c=1; coada[I_c]=1; s[1]=1;
bf_r1();
for (I=1;I<=sf_c;I++) cout<<coada[I]<<" ";
}
// cu liste de adiacenta sa se implemeteze
//parcurgerea in latime iterativ
// 7
// 1 2
// 1 6
// 1 3
// 3 6
// 2 5
// 2 4
// 3 7
//=>1 3 6 2 7 4 5

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

struct Nod
{
int nd;
Nod* adr_urm;
};

Nod* L[50],*p;
int coada[50],s[50],I_c,sf_c,I,n;

void bf_r1()
{
Nod*p;
while (I_c<=sf_c)
{
p=L[coada[I_c]];
while (p)
{
if (s[p->nd]==0)
{
sf_c++;
coada[sf_c]=p->nd;
s[p->nd]=1;
}
p=p->adr_urm;
}
I_c++;
//bf_r1();
}
}

void Citire_1( Nod* L[50], int& n)


{
Nod* p;
int I,j;
fstream f("graf.txt",ios::in);
f>>n;
for (I=1;I<=n;I++) L[I]=0;
while (f>>I>>j)
{ p=new Nod;
p->adr_urm=L[I]; p->nd=j;
L[I]=p;
}
f.close();
}

main()
{ Citire_1(L,n);
I_c=1; sf_c=1; coada[I_c]=1; s[1]=1;
bf_r1();
for (I=1;I<=sf_c;I++) cout<<coada[I]<<" ";
}

MATRICEA DRUMURILOR
m[I,j]= 1, daca exista drum de la I la j,
0, daca nu exista drum de la I la j, sau I=j.
// cu liste de adiacenta sa se implemeteze
//obtinerea matricei drumurilor
// 7
// 1 2
// 1 6
// 1 3
// 3 6
// 2 5
// 2 4
// 3 7
//=>
// 0 1 1 1 1 1 1
// 0 0 0 1 1 0 0
// 0 0 0 0 1 1 1
// 0 0 0 0 1 0 0
// 0 0 0 0 0 0 0
// 0 0 0 0 1 0 0

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

struct Nod
{
int nd;
Nod* adr_urm;
};

int s[50],n,I,j,M_dr[50][50];
Nod* L[50];
void df(int baza,int nod)
{
Nod* p;
if (baza!=nod) M_dr[baza][nod]=1;
p=L[nod]; s[nod]=1;
while(p)
{
if (s[p->nd]==0) df(baza,p->nd);
p=p->adr_urm;
}
}

void Citire_1( Nod* L[50], int& n)


{
Nod* p;
int I,j;
fstream f("graf.txt",ios::in);
f>>n;
for (I=1;I<=n;I++) L[I]=0;
while (f>>I>>j)
{ p=new Nod;
p->adr_urm=L[I]; p->nd=j;
L[I]=p;
}
f.close();
}

main()
{
Citire_1(L,n);
for (I=1;I<=n;I++)
{
for (j=1;j<=n;j++) s[j]=0;
df(I,I);
}
for (I=1;I<=n;I++)
{
for (j=1;j<=n;j++) cout<<M_dr[I][j]," ";
cout<<endl;
}
}
Componente tare conexe

Definitie.G1=(X1g1) este o componenta tare conexa daca:


1)Oricare ar fi x , y din multimea X1, exista drum de la x la y si drum de
la y la x.
2)Nu exista un alt subgraf al lui G care indeplineste conditia 1)
// sa se implemeteze componentele tare conexe
//ale unui graf ca intersectie intre predecesori si succesori la care
adaug nodul
5
1 2
2 3
3 1
1 4
4 5
5 4
=>copmomenta I
1 2 3
comonenta II
4 5

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int suc[50],pred[50],A[50][50],n,nrc,I,j;

void Citire(char Nume_fis[20],int a[50][50],int& n)


{
fstream f(Nume_fis,ios::in);
int I,j;
f>>n;
while (f>>I>>j) A[I][j]=1;
f.close();
}

void df_r1(int nod)


{
int k;
suc[nod]=nrc;
for (k=1;k<=n;k++)
if ( (A[nod][k]==1)&&(suc[k]==0) )
df_r1(k);
}
void df_r2(int nod)
{
int k;
pred[nod]=nrc;
for (k=1;k<=n;k++)
if ( (A[k][nod]==1)&&(pred[k]==0))
df_r2(k);
}

main()
{
Citire("Graf.txt",A,n);
nrc=1;
for (I=1;I<=n;I++)
if (suc[I]==0)
{
suc[I]=nrc;
df_r1(I);df_r2(I);
for (j=1;j<=n;j++)
if (suc[j]!=pred[j]) suc[j]=pred[j]=0;
nrc++;
}
for (I=1;I<=n;I++)
{
cout<<"Componenta "<<I<<endl;
for (j=1;j<=n;j++)
if (suc[j]==I) cout<<j<<" ";
cout<<endl;
}
}
Drumuri in grafuri
Consideram un graf orientat G=(X,U) cu n noduri, in care fiecarui arc ii este asociat un numar intreg numit cost.
Semnificatia
acestui cost poate fi foarte variata , in functie de domeniul pe care il descrie graful .

Matricea costurilor

Pentru evidentierea costurilor tuturor arcelor unui graf cu n noduri se poate defini o matrice a, cu n linii * n
coloane.Exista doua forme ale acestei matrici:
Forma a): Fiecare element a[i,j] poate fi:
c , daca exista un arc de cost c>0 intre nodurile i si j;
0 , daca i=j;
+∞ ,daca nu exista arc intre nodurile i si j .
Forma b): Este absolut similara,cu singura deosebire ca in loc de +∞ avem -∞.
Forma a) se foloseste pentru determinarea drumurilor de cost minim intre doua noduri , iar forma b) este
utilizata in aflarea drumurilor de cost maxim.
Daca dorim sa citim matrice costurilor ,evident ca nu putem introduce de la tastatura “+”! In loc de +
vom da un numar intreg foarte mare.

Algoritmul lui Dijkstra

Se consideră un graf neorientat, conex cu N noduri. Graful este dat prin matricea costurilor A.

c, dacã existã un arc c între nodurile i si j



Aij  0, daca i  j
x, dac nu exista un arc intre nodurile i si j

Se consideră un nod iniţial R. Se cer lungimile drumurilor minime de la R la celelalte noduri ale grafului,
precum şi nodurile prin care trec aceste drumuri.
Problema are numeroase aplicaţii practice. Să presupunem că dispunem de o hartă cu oraşele unei ţări.
Acestea sunt unite prin şosele. Oraşele formează nodurile grafului, iar şoselele – arcele acestuia. Algoritmul
furnizează drumurile optime de la un oraş iniţial la celelalte oraşe. Este interesant de observat faptul că, spre
deosebire de alţi algoritmi, acesta furnizează şi nodurile prin care trec drumurile optime, nu numai
lungimile acestora.

Exemplu: Se consideră graful din figură:

Pentru acest graf matricea costurilor este:


0  13  16 8 
 
 0  6  10 
13  0 14  11 
 
 6 14 0 5 17 
16   5 0 7 

8 10 11 17 7 0 

Întrucât graful este neorientat, matricea este simetrică.


Algoritmul selectează nodurile grafului, unul câte unul, în ordinea crescătoare a costului drumului de la
nodul R la ele, într-o mulţime S, care iniţial conţine numai nodul R. În felul acesta ne încadrăm în strategia
generală GREEDY. În procesul de prelucrare se folosesc trei vectori: D,S şi T.
Vectorul D este vectorul costurilor de la nodul R la celelalte noduri ale grafului. Prin D(I), unde I{1..N},
se înţelege costul drumului găsit la un moment dat, între nodul R şi nodul I.
Vectorul T indică drumurile găsite între nodul R şi celelalte noduri ale grafului.
Vectorul S (vector caracteristic) indică mulţimea S a nodurilor selectate. S(I)=0 dacă nodul I este neselectat
şi S(I)=1 dacă nodul I este selectat.

Prezentarea algoritmului.
P1) Nodul R este adăugat mulţimii S iniţial vidă (S(R)=1);
- costurile drumurilor de la R la fiecare nod al grafului se preiau în vectorul D de pe linia R a matricii
A;
- pentru toate nodurile I având un cost al drumului de la R la ele finit, se pune T(I)=R.
P2) Se execută de n-1 ori secvenţa
- printre nodurile neselectate se caută cel aflat la distanţa minimă faţă de R şi se selectează adăugându-l
mulţimii S;
- pentru fiecare din nodurile neselectate se actualizează în D costul drumurilor de la R la el, utilizând
ca nod intermediar nodul selectat, procedând în felul următor: se compară distanţa existentă în vectorul D
cu suma dintre distanţa existentă în D pentru nodul selectat şi distanţa de la nodul selectat la nodul pentru
care se face actualizarea distanţei (preluată din A), iar în cazul în care suma este mai mică, elementul din D
corespunzător nodului pentru care se face actualizarea capătă ca valoare aceasă sumă şi elementul din T
corespuzător aceluiaşi nod ia valoarea nodului selectat (drumul trece prin acest nod). Presupunând că a
fost selectat nodul K, se actualizează distanţa pentru nodul L şi se compară D(K)+A(K,L) cu D(L).
P3) Pentru fiecare nod al grafului, cu excepţia lui R, se trasează drumul de la R la el.

Pentu acest exemplu se consideră R=1.


Linia 1 a matricei A aste încărcată în vectorul D, vectorii S şi T au iniţial valorile care se observă:
D 0   8
13 16

S 1 0 0 0 0 0

T 0 0 1 0 0
1

Se selectează nodul 6 (costul drumului minim).


Se actualizează conţinutul vectirilor D, S şi T.

D(6)+A(6,2)=8+10=18< D(2)=18 şi T(2)=6


D(6)+A(6,3)=8+11=19>13D(3)=13.
D(6)+A(6,4)=8+17=25< D(4)=25 şi T(4)=6.
D(6)+A(6,5)=8+7=15<16 D(5)=15 şi T(5)=6.

D 0 13 15 8
18 25

S 1 0 0 0 0 1

T 0 6 1 6 6 1

Se selectează nodul 3.
D(3)+A(3,2)=13+>18D(2)=18.
D(3)+A(3,4)=13+14=27>25D(3)=13.
D(3)+A(3,5)=13+>15D(5)=15.

D 0 8
18 13 25 15

S 1 0 1 0 0 1

T 0 6 1 6 6 1

Se selectează nodul 5.
D(5)+A(5,2)=15+>18D(2)=18.
D(5)+A(5,4)=15+5=20D(4)=20 şi T(4)=5.

D 0 8
18 13 20 15

S 1 0 1 0 1 1

T 0 6 1 5 6 1
Se selectează nodul 2.
D(2)+A(2,4)=18+6=24>20D(4)=20.

D 0 18 8
13 20 15

S 1 1 1 0 1 1

T 6 1 5 6 1
0

Se selectează nodul 4.
În continuare, pentru fiecare nod se trasează drumul de la nodul iniţial la el.
Vom considera, ca exemplu, nodul 4. Distanţa de la nodul 1 la el D(4) şi anume 20.
Avem T(4)=5; T(5)=6; T(6)=1; drumul trece prin nodurile 1,6,5.
Avem A(1,6)=8; A(6,5)=7; A(5,4)=5.Rezultă 8+5+7=20.
Întrucât drumul se trasează în ordine inversă faţă de cum este găsit, în program se foloseşte o procedură
recursivă.
În cele ce urmează vom nota nodurile cu Ni1,Ni2,…,Nin. Acestea sunt tot nodurile 1,2,…,R,…,N
cosiderate în altă ordine. Nodului R îi corespunde nodul Ni1.

Demonstrarea algoritmului.

Lema 1. Algoritmul selectează nodurile în ordinea costului drumului de la nodul iniţial la ele.

Demonstraţie:
Utilizăm metoda inducţiei matematice. Prima dată se selectează nodul Ni2 (are costul drumului minim faţă
de Ni1). Aceasta înseamnă că ipoteza de inducţie se verifică pentru prima selecţie. Presupunem că nu au
fost selectate nodurile Ni2,Ni3,…,Nip (p<n) în ordinea costului drumului de la Ni1 la ele. Se selectează
nodul Nip+1. Presupunem, prin absurd, că există un alt nod N1, neselectat, care are un cost al drumului de
la Ni1 la el mai scăzut decât al nodului Nip+1. Atunci, acesta poate fi plasat în şirul nodurilor deja selectate,
aşezate în ordinea distanţei faţă de Ni1, în următoarele două moduri:
1) Ni1,…,N1,…,Nip,Nip+1.
În acest caz, se contrazice ipoteza de inducţie (nodurile Ni1,…,Nip erau aşezate în ordine distanţei faţă de
Ni1).

2) Ni2,…, Nip,N1,Nip+1.
Aici este contrazisă alegerea lui Nip+1. Acesta a fost ales ca nod cu distanţă minimă faţă de Nil dintre toate
nodurile neselectate, iar N1 este un nod neselectat.

Lema 2. Orice drum optim de la nodul iniţial la oricare din nodurile selectate trece numai prin noduri
selectate.

Demonstraţie:
Presupunem prin absurd că există un drum de cost mai mic de la Ni1 la Nik (Nik este un nod deja selectat)
care nu trece numai prin noduri selectate. Fie Nz primul nod prin care trece acest drum şi care nu este
selectat. Aceasta înseamnă că nodul Nz are costul drumului de la Ni1 la el mai mic decât cel de la Ni1 la
Nik (nod care este selectat). Aceasta contrazice LEMA 1.

TEOREMĂ.
Odată selectat un nod, nu există un drum de cost mai mic între Ni1 şi el, decât drumul de cost indicat de
vectorul D.

Demonstraţie:
În demonstrarea acestui fapt utilizăm metoda inducţiei matematice.
Pentru selectarea lui Ni2 afirmaţia este evidentă, întrucât acesta este cel mai apropiat de Ni1.
Presupunem selectate nodurile Ni2,…,Nip. Selectăm Nip+1. Presupunem că de la Ni1 la el există un drum
de cost mai mic decât cel indicat de vectorul D.
Avem două posibilităţi:

1) Drumul de cost mai mic trece numai prin noduri selectate.


Analizăm modul de funcţionare a algoritmului până în acest moment.
La selecţia nodurilor Ni1,…,Nip s-au actualizat distanţele reţinute în vectorul D (pentru fiecare nod
neselectat s-a comparat vechea distanţă reţinută în D cu suma dintre distanţa de la Ni1 la nodul selectat şi
distanţa de la nodul selectat la nodul pentru care se face actualizarea, iar în cazul în care suma din urmă era
mai mică, aceasta era reţinută în vectorul D). În concluzie, nu există un drum mai scurt între Ni1 şi Nip+1
care trece numai prin noduri selectate.

2) Drumul de cost mai mic trece şi prin noduri neselectate.


În acest caz se contrazice LEMA 2.
// sa se implemeteze un program care aplica algoritmul DIJKSTRA
//pentru determinarea drumurilor de lungime minima
//nodul de plecare e 1
5
1 2 1
1 3 9
1 5 3
2 4 3
2 3 7
4 3 2
4 1 1
5 2 4
5 4 2
=>drumul minim de la 1 la 3 e 6 si trece prin nodurile 1 2 4 3
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
const float Pinfinit=1.e20;
float A[50][50],D[50],min;
int S[50],T[50],n,I,j,r,poz;
void Citire_cost (char Nume_fis[20],float A[50][50],int& n)
{
int I,j;
float c;
fstream f("graf.txt",ios::in);
f>>n;
for (I=1;I<=n;I++)
for (j=1;j<=n;j++)
if (I==j) A[I][j]=0;
else A[I][j]=Pinfinit;
while (f>>I>>j>>c) A[I][j]=c;
f.close();
}

void drum(int I)
{
if (T[I]) drum(T[I]);
cout<<I<<" ";
}
main()
{ float min;
Citire_cost("Graf.txt",A,n);
cout<<"Introduceti nodul de pornire "<<endl;
cout<<"r=";cin>>r;S[r]=1;
for (I=1;I<=n;I++)
{
D[I]=A[r][I];
if (I!=r)
if (D[I]<Pinfinit) T[I]=r;}
for (I=1;I<=n;I++)
{
min=Pinfinit;
for(j=1;j<=n;j++)
if (S[j]==0)
if (D[j]<min)
{
min=D[j];
poz=j;
}
S[poz]=1;
for (j=1;j<=n;j++)
if (S[j]==0)
if (D[j]>D[poz]+A[poz][j])
{
D[j]=D[poz]+A[poz][j];
T[j]=poz;
}
}
for (I=1;I<=n;I++)
if (I!=r)
if(T[I])
{
cout<<"distanta de la "<<r<<" la "<<I<<" este "<<D[I]<<endl;
drum(I);
cout<<endl;
}
else
cout<<"nu exista drum de la "<<r<<" la "<<I<<endl;
}

Algoritmul Roy Floyd


Fiind dat un graf prin matricea ponderilor sa se calculeze drumul (lungimea lui adica
suma costurilor) minim de la orice doua noduri din graf.
matricea ponderilor este
0 1 9 ω 3
ω 0 7 3 ω
ω ω 0 ω ω
1 ω 2 0 ω
ω 4 ω 2 0

Etapa 1)Caut drumurile optime intre oricare doua noduri dar drumurile trec prin nodul
intermediar 1
a[4,2]= ω >a[4,1]+a[1,2]=1+1=2 deci a[4,2]=2
a[4,5]=ω>a[4,1]+a[1,5]=1+3=4 deci a[4,5]=4
matricea ponderilor este

0 1 9 ω 3
ω 0 7 3 ω
ω ω 0 ω ω
1 2 2 0 4
ω 4 ω 2 0
Etapa 2)Caut drumurile optime intre oricare doua noduri dar drumurile trec prin nodul
intermediar 2
a[1,3]=9>a[1,2]+a[2,3]=1+7=8 deci a[1,3]=8
a[1,4]=ω>a[1,2]+a[2,4]=1+3=4 deci a[1,4]=4
a[5,3]=ω>a[1,2]+a[2,3]=4+7=11 deci a[5,3]=11
a[5,4]=ω>a[5,2]+a[2,4]=4+3=7 deci neschimbat

matricea ponderilor este


0 1 8 4 3
ω 0 7 3 ω
ω ω 0 ω ω
1 2 2 0 4
ω 4 11 2 0

Etapa 3)Caut drumurile optime intre oricare doua noduri dar drumurile trec prin nodul
intermediar 3 dar nu avem nimic nou.
Etapa 4)Caut drumurile optime intre oricare doua noduri dar drumurile trec prin nodul
intermediar 4
a[1,3]=ω>a[1,4]+a[4,3]=4+2=6 deci a[1,3]=6
a[2,1]=ω>a[2,4]+a[4,1]=3+1=4 deci a[2,1]=4
a[2,3]=ω>a[2,4]+a[4,3]=3+2=5 deci a[2,3]=5
a[2,5]=ω>a[2,4]+a[4,5]=3+4=7 deci a[2,5]=7
a[5,1]=ω>a[5,4]+a[4,1]=2+1=3 deci a[5,1]=3
a[5,3]=ω>a[5,4]+a[4,3]=2+2=4 deci a[5,3]=4

01 6 4 3
4 0 5 3 7
ω ω 0 ω ω
1 2 2 0 4
3 4 4 2 0
// sa se implemeteze un program care aplica algoritmul Roy Floyd
5
1 2 1
1 3 9
1 5 3
2 4 3
2 3 7
4 3 2
4 1 1
5 2 4
5 4 2
=>5 4 1 2
are lungimea 4
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
const float Pinfinit=1.e20;
float minfinit=-1.e20;
float A[50][50];
int n;
void Citire_cost (char Nume_fis[20],float A[50][50],int& n)
{
int I,j;
float c;
fstream f("graf.txt",ios::in);
f>>n;
for (I=1;I<=n;I++)
for (j=1;j<=n;j++)
if (I==j) A[I][j]=0;
else A[I][j]=Pinfinit;
while (f>>I>>j>>c) A[I][j]=c;
f.close();
}

void Drum(int I, int j)


{
int k=1,gasit=0;
while ( (k<=n) && (!gasit ))
{
if ( (I!=k) && (j!=k) && (A[I][j]==A[I][k]+A[k][j]) )
{
Drum(I,k);Drum(k,j);
gasit=1;
}
k++;
}
if (!gasit) cout<<j<<" ";
}

void Scriu_drum(int Nod_Initial, int Nod_Final)


{
if (A[Nod_Initial][Nod_Final]<Pinfinit)
{
cout<<"Drumul de la "<<Nod_Initial<<" la "<<Nod_Final<<" are
lungimea "<<A[Nod_Initial][Nod_Final]<<endl;
cout<<Nod_Initial<<" ";
Drum(Nod_Initial,Nod_Final);
}
else
cout<<"Nu exista drum de la "<<Nod_Initial<<" la "<<Nod_Final;
}
void Lungime_Drumuri()
{
int I,j,k;
for (k=1;k<=n;k++)
for(I=1;I<=n;I++)
for (j=1;j<=n;j++)
if (A[I][j]>A[I][k]+A[k][j])
A[I][j]=A[I][k]+A[k][j];
}
main()
{
Citire_cost("graf.txt",A,n);
Lungime_Drumuri();
Scriu_drum(5,2);
}
// sa se implemeteze un program care aplica algoritmul Roy Floyd
//pentru determinarea drumurilor de lungime maxima
//sa nu avem circuite
5
1 2 1
1 3 9
1 5 3
2 4 3
2 3 7
4 3 2
4 1 1
5 2 4
5 4 2

=>are lungimea 27
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
const float Minfinit=-1.e20;
float A[50][50];
int n;

void Citire_cost1(char Nume_fis[20], float A[50][50], int& n)


{
int I,j;
float c;
fstream f(Nume_fis,ios::in);
f>>n;
for (I=1;I<=n;I++)
for (j=1;j<=n;j++)
if (I==j) A[I][j]=0;
else A[I][j]=Minfinit;
while (f>>I>>j>>c) A[I][j]=c;
f.close();
}

void Drum(int I, int j)


{
int k=1,gasit=0;
while ( (k<=n) && (!gasit ))
{
if ( (I!=k) && (j!=k) && (A[I][j]==A[I][k]+A[k][j]) )
{
Drum(I,k);Drum(k,j);
gasit=1;
}
k++;
}
if (!gasit) cout<<j<<" ";
}

void Scriu_drum(int Nod_Initial, int Nod_Final)


{
if (A[Nod_Initial][Nod_Final]>Minfinit)
{
cout<<"Drumul de la "<<Nod_Initial<<" la "<<Nod_Final<<" are
lungimea "<<A[Nod_Initial][Nod_Final]<<endl;
cout<<Nod_Initial<<" ";
Drum(Nod_Initial,Nod_Final);
}
else
cout<<"Nu exista drum de la "<<Nod_Initial<<" la "<<Nod_Final;
}
void Lungime_Drumuri()
{
int I,j,k;
for (k=1;k<=n;k++)
for(I=1;I<=n;I++)
for (j=1;j<=n;j++)
if (A[I][j]<A[I][k]+A[k][j])
A[I][j]=A[I][k]+A[k][j];
}
main()
{
Citire_cost1("graf.txt",A,n);
Lungime_Drumuri();
Scriu_drum(1,2);
}

Grafuri neorientate
Notiuni introductive
Grafuri neorientate
Definiţie. Se numeşte graf neorientat o pereche ordonată de mulţimi (X, U), X fiind o mulţime
finită şi nevidă de elemente numite noduri sau vârfuri, iar U o mulţime de perechi neordonate
( submulţimi cu două elemente) din X, numite muchii.
Ex.

2 6
1 +8
3
5

7
4
Fig.1

Pentru graful de mai sus avem:


X={1, 2, 3, 4, 5, 6, 7, 8}
U={[1,2], [1,4], [1,5], [2,3], [2,5], [3,4], [6,7]}
Dacă u1 şi u2 sunt două muchii care au o extremitate comună ele se vor numi adiacente.
Definiţie. Un graf parţial al grafului G=(X,U) este un graf G 1=(X,V) astfel încât VU, adică G1
are aceeaşi mulţime de vârfuri ca G iar mulţimea de muchii V este chiar U sau o submulţime a acesteia.
Ex. Mai jos avem un graf parţial al grafului de mai sus (Fig.1)
6
2 +8
1
3
5

7
4
Fig.2

Cu alte cuvinte, un graf parţial al unui graf se obţine păstrând aceeaşi mulţime de vârfuri şi
eliminând o parte din muchii.
Definiţie. Un subgraf al unui graf G=(X,U) este un graf H=(Y,V) astfel încât Y  X iar V conţine
toate muchiile din U care au ambele extremităţi în Y. Vom spune că subgraful H este indus sau generat
de mulţimea de vârfuri Y.
Ex. Mai jos avem un subgraf al grafului din Fig.1 obţinut prin eliminarea nodului 3

2 6
+8
1
5

7
4
Definiţie. Gradul unui vârf x este numărul muchiilor incidente cu x.
Gradul vârfului x se notează cu d(x).
Ex. în Fig.1 d(1)=3, d(4)=2, d(8)=0, d(6)=1
Un vârf care are gradul 0 se numeşte vârf izolat.
Un vârf care are gradul 1 se numeşte vârf terminal.
Propoziţia 1. Dacă un graf G=(X,U) are m muchii şi n vârfuri iar X={x 1,x2,..,xn}, atunci
d(x1)+d(x2)+...+d(xn)=2m.
Corolar. În orice graf G există un număr par de vârfuri de grad impar.
Definiţie. Se numeşte graf complet cu n vârfuri un graf care are proprietatea că orice două
noduri diferite sunt adiacente.
Propoziţia 2. Un graf complet Kn are n(n-1)/2 muchii.
Definiţie. Un graf G=(X,U) se numeşte bipartit dacă există două mulţimi nevide A, B astfel
încât X=A U B, A  B = şi orice muchie u a lui G are o extremitate în A iar cealaltă în B.
Definiţie. Un graf bipartit se numeşte complet dacă pentru orice x din A şi orice y din B, există
în G muchia [x,y].
Definitie.Un graf partial al unui graf neorientat dat G=(X,G) este un graf G1=(X,g1 unde G1 inclus
sau=cu G.
Definitie.Un subgraf al unui graf neorientat G=(X,g) este un graf H=(Y<G1), unde Y inclus in X, iar
muchiile din G1 sunt toate muchiile din G care au ambele extremitati in multimea Y.
Definitie.Lant.Pentru graful neorientat , un lant este o succesiune de varfuri cu proprietatea ca oricare
doua varfuri sunt adiacente.

Graf complet si bipartit

Se numeste graf complet cu n varfuri , notat Kn , un graf G=(X,U) cu proprietatea ca oricare doua
varfuri sunt adiacente adica :
() x,y є x → ca exista muchia [x,y] apartine de U
Teorema:
Un graf complet cu n varfuri , are n(n-1)/2 muchii.
Definitia :
Se numeste graf bipatrat ,un graf G=(X,U) cu propietate ca exista doua multimi A si B incluse in X,
astfel incat :
-A ∩ B=Ø ,A U B=X,
-toate muchiile grafului au o extremitate in A si cealalta in B .
Definitie :
Se numeste graf bipatrat complet, un graf bipatrat cu propietatea ca pentru orice varf x din A si orice
varf y din B,exista muchia (x,y) (unde A si B sunt cele doua submultimi care partitioneaza miltimea
varfurilor X).

Notiunea de lant si ciclu

Definitie :
Se numeste lant in graful G ,o succesiune de varfuri (z1, z2,z3 ,….zk),unde x1,x2,…,xk apartine de X ,
cu propietatea ca oricare doua varfuri consecutive sunt adiacente ,adica exista muchiile [z1, z2],[z2 ,z3],
….,[zk-1,zk] apartine de U.
Varfurile z1 si zk se numesc extremitatile lantului ,iar numarul de muchii care intra in componenta sa
reprezinta lungimea lantului .
Definitie :
Se numeste ciclu intr-un graf ,un lant L=(z1,z2,….zk) cu propietatea ca z1=zk si muchiile [z1,z2 ],
[z2,z3], ….,[zk-1,zk] sunt disticte doua cate doua.
Daca intr-un ciclu , toate varfurile cu exceptia primului si a ultimului sunt disticte doua cate
doua ,atunci
ciclul se numeste elementar .In contrar, el este neelementar.
CONEXITATE

Fie G=(X, U) un graf neorientat, X={x1, x2, ..., x2}.


Definiţie. Se numeşte lanţ în G succesiunea de vârfuri L={x i1, xi2,..., xik} cu proprietatea că orice două
noduri consecutive din L sunt adiacente, adică [xi1, xi2], [xi2, xi3],..., [xik-1, xik]  U.
Dacă vârfurile xi1, xi2,..., xik sunt diferite două câte două atunci lanţul se numeşte elementar. În caz
contrar, lanţul este neelementar.
1 2 5

8
7

3 4 6

Ex. L1=[1,2,4] – lanţ elementar


L2=[1,2,3,1,2,4] – lanţ neelementar
Definiţie. Se numeşte ciclu în G un lanţ L pentru care x i1=xik şi toate muchiile adică [x i1, xi2], [xi2, xi3],...,
[xik-1, xik] sunt diferite două câte două.
Ex. C=[1,2,3,1] este un ciclu.
Definiţie. Se numeşte ciclu elementar un ciclu care are proprietatea că oricare două vârfuri ale sale,
cu excepţia primului şi ultimului, sunt diferite două câte două.
Ex. C1=[1,2,3,1] este ciclu elementar.
C2=[3,1,2,4,8,2,3] este un ciclu neelementar.
Definiţie. Un graf G se numeşte conex dacă pentru orice două vârfuri x şi y diferite ale sale există un
lanţ care le leagă.
Definiţie. Se numeşte componentă conexă a grafului G=(X, U) un subgraf C=(X 1, U1), conex, a lui G
care are proprietatea că nu există nici un lanţ în G care să lege un vârf din X 1 cu un vârf din X-X1.

Un graf G este conex , daca oricare ar fi doua varfuri ale sale ,exista un lant care le leaga.
Definitie:

Se numeste componenta conexa a grafului G=(X,U),un subgraf G1=(X1,U1) a lui G ,conex ,


cu propietatea ca nu exista nici un lant care sa lege un nod din X1 cu un nod din X-X1(pentru orice nod ,
nu exista un lant intre acel nod si nodurile care nu fac parte din subgraf).
Definitie.Daca multimea G are proprietatea de simetrie, graful se numeste neorientat.
Definitie.Un graf partial al unui graf neorientat dat G=(X,g) este un graf G1=(X,g1
unde g1 submultime a lui g.
Definitie.Un subgraf al unui graf neorientat G=(X,g) este un graf H=(Y,g1), unde
Yinclus in X, iar muchiile din g1 sunt toate muchiile din g care au ambele extremitati
in multimea Y.
Definitie.Lant.Pentru graful neorientat , un lant este o succesiune de varfuri cu
proprieatea ca oricare doua varfuri sunt adiacente.

// sa se implemeteze un program care determina componentele conexe


// la un graf neorientat
5
1 2
1 3
4 5
=>componenta 1
1 2 3
coponenta 2
4 5

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int S[50],A[50][50],n,I,k;

void CitireN (char Nume_fis[20],int A[50][50],int& n)


{
int I,j;
fstream f(Nume_fis,ios::in);
f>>n;
while (f>>I>>j)A[I][j]=A[j][I]=1;
f.close();
}

void df_r(int nod)


{
int k;
cout<<nod<<" "; S[nod]=1;
for (k=1;k<=n;k++)
if ( (A[nod][k]==1)&& (S[k]==0) ) df_r(k);
}
main()
{

CitireN("graf.txt",A,n);
k=1;
for (I=1;I<=n;I++)
if (S[I]==0)
{
cout<<"componenta "<<k<<endl;
df_r(I);

191
cout<<endl;
k++;
}
}
Grafuri hamiltoniene
Definitie:
Se numeste ciclu hamiltonian intr-un graf, un ciclu elementar care contine toate varfurile grafului .
Se numeste graf hamiltonian ,un graf care contine un ciclu hamiltonian.
Se numeste lant hamiltonian intr-un graf, un lant elementar care contine toate varfurile grafului.
Teorema:
Daca intr-un graf G=(X,U) cu n>=3 varfuri, gradul fiecarui varf x verifica conditia d(x)>=n/2, atuncigraful este
hamiltonian,

// sa se implemeteze un program care determina un ciclu hamiltonian


intr-un graf si care e
9
1 2
1 4
2 4
2 3
2 5
3 4
3 9
3 8
4 6
5 6
5 7
5 8
7 8
7 5
8 9
=>1 2 3 9 8 7 5 6 4 ca ciclu hamiltonian
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int st[50],a[50][50],n,k;
void CitireN (char Nume_fis[20],int A[50][50],int& n)
{
int I,j;
fstream f(Nume_fis,ios::in);
f>>n;
while (f>>I>>j)A[I][j]=A[j][I]=1;
f.close();
}

void Init()
{ st[k]=1; }
int AmSuccesor ()
{ if (st[k]<n)
{ st[k]++;
return 1;
}
else return 0;

192
}
int E_Valid()
{ if (!a[st[k-1]][st[k]]) return 0;
else
for (int I=1;I<=k-1;I++)
if (st[I]==st[k]) return 0;
if (k==n && !a[1][st[k]]) return 0;
return 1;
}
int Solutie()
{ return k==n;}
void Tipar()
{ for (int I=1;I<=n;I++) cout<<"Nodul "<<st[I]<<endl;
k=0;
}
void back()
{ int AS;
k=2; Init();
while (k>1)
{ do {} while ((AS=AmSuccesor ()) && !E_Valid());
if (AS)
if (Solutie()) Tipar();
else {k++;Init();}
else k--;
}
}
main () { st[1]=1;k=2;st[k]=1;
CitireN("graf.txt",a,n);
back();
}

Grafuri euleriene
Definitie.Un graf care contine un ciclu eulerian se numeste eulerian.
Un lant L al unui graf G care contine fiecare muchie o data si numai o data se numeste lant
eulerian;
Daca x0=xp si lantul e eulerian atunci ciclul se numeste ciclu eulerian;

// sa se implemeteze un program care determina un ciclu eulerian


intr-un graf si care e
9
1 2
1 4
2 4
2 3
2 5
3 4
3 9
3 8
4 6

193
5 6
5 7
5 8
7 8
7 5
8 9
=>1 2 4 6 5 7 8 3 9 8 5 2 3 4 1 ca ciclu eulerian
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
struct Nod
{
int nd;
Nod* adr_urm;
};

int A[50][50],S[50],n;
Nod* Alista, *Indice;

void CitireN (char Nume_fis[20],int A[50][50],int& n)


{
int I,j;
fstream f(Nume_fis,ios::in);
f>>n;
while (f>>I>>j)A[I][j]=A[j][I]=1;
f.close();
}
void ciclu(Nod* v)
{int Nodul;
Nod *ANod_baza,*ANod_gasit,*ANod_urm;
ANod_urm=v->adr_urm;
ANod_baza=v;
do
{
Nodul=1;
while (A[ANod_baza->nd][Nodul]==0) Nodul++;
A[ANod_baza->nd][Nodul]=0;A[Nodul][ANod_baza->nd]=0;
ANod_gasit=new Nod; ANod_gasit->nd=Nodul;
ANod_gasit->adr_urm=0;
ANod_baza->adr_urm=ANod_gasit;ANod_baza=ANod_gasit;
} while (ANod_gasit->nd!=v->nd);
ANod_baza->adr_urm=ANod_urm;
}
int adauga()
{
int I,gasit=0;
Indice=Alista;
while (Indice && !gasit)
{
for (I=1;I<=n;I++)
if (A[Indice->nd][I]==1) gasit=1;
if (!gasit) Indice=Indice->adr_urm;
}
if (Indice)
{
ciclu (Indice);
return 1;
}

194
else return 0;
}
int grade_pare()
{
int I=1,j,s,gasit=0;
while ( (I<=n) && ! gasit)
{
s=0;
for (j=1;j<=n;j++) s+=A[I][j];
if (s%2) gasit=1;
I++;
}
return !gasit;
}
void df(int nod)
{
int k;
S[nod]=1;
for (k=1;k<=n;k++)
if ( (A[nod][k]==1) && (S[k]==0)) df(k);
}
int conex()
{
int gasit=0,I;
df(1);
for (I=1;I<=n;I++)
if (S[I]==0) gasit=1;
return !gasit;
}
main()
{ CitireN("Graf.txt",A,n);
if (conex())
if (grade_pare())
{
Alista=new Nod;
Alista->nd=1;Alista->adr_urm=0;
while (adauga());
Indice=Alista;
while (Indice)
{ cout<<Indice->nd<<" ";
Indice=Indice->adr_urm;
}
}
else cout <<"Graful nu indeplineste conditiile de paritate";
else cout<<"Graful nu este conex";
}

195
Flux intr-o retea de transport

O retea de transport este un graf orientat G=(V,E) care satisface urmatoarele


conditii:
a) exista un unic varf s apartine V in care nu intra nici un
arc(gradul interior 0) numit sursa;
b) exista un unic varf d apartine V in care nu iese nici un
arc(gradul exterior 0);
c) pentru fiecare nod x apartine V-(s,d)exista cel putin un drum de
la sursa la destinatie;cu alte cuvinte graful G este conex;
d) pe multimea arcelor se defineste o functie c:E->R+,numita functie
de capacitate;
Algoritmul se executa intr-un nr finit de pasi.in cadrul surselor prezentate
in continuare determinare drumului de crestere din graful rezidual asociat se
realizeaza printr-o parcurgere BF a acestuia.

// sa se implemeteze un program care determina algoritmul lui


Ford //Furkerson
7
1 7
1 4 6
1 2 1
2 3 8
2 5 4
3 4 3
5 6 5
6 7 8
3 7 1
=>1 2 3 7 dat prin matricea de adiacenta ca fiind de cost minim
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

196
struct Nod
{
int nd;
Nod* adr_urm;
};

void Citire_Cap(char Nume_fis[20],int A[50][50][2],int& n,int&


st,int& fin)
{
int I,j, cost;
fstream f(Nume_fis,ios::in);
f>>n>>st>>fin;
while (f>>I>>j>>cost)A[I][j][0]=cost;
f.close();
}
int A[50][50]
[2],n,st,fin,gasit,coada[50],s[50],f[50],I_c,sf_c,I,j,min;
void refac(int Nod)
{int min;
if (Nod!=st)
if (s[Nod]>0)
{
if (min>(A[s[Nod]][Nod][0]-A[s[Nod]][Nod][1]))
min=A[s[Nod]][Nod][0]-A[s[Nod]][Nod][1];
refac(s[Nod]);
A[s[Nod]][Nod][1]+=min;
}
else
{
if (min>A[Nod][s[abs(Nod)]][1])
min=A[Nod][abs(s[Nod])][1];
refac(abs(s[Nod]));
A[Nod][abs(s[Nod])][1]-=min;
}
}
void drum_in_crestere()
{
gasit=0;
I_c=sf_c=1;coada[I_c]=st;
while( (I_c<=sf_c) && (coada[sf_c]!=fin) )
{
I=1;
while ( (I<=n) && !gasit)
{
if ((A[coada[I_c]][I][0]-A[coada[I_c]][I][1]>0) && (s[I]==0))
{
s[I]=coada[I_c];coada[++sf_c]=I;
}
else
if ((A[I][coada[I_c]][1]>0) && (s[I]==0) && (I!=st) )
{
s[I]=-coada[I_c];coada[++sf_c]=I;
}
I++;
}
I_c++;
}
if (coada[sf_c]==fin) gasit=1;
}
void caut()
{int min;

197
do
{
for (I=1;I<=n;I++)s[I]=0;
drum_in_crestere();
if (s[fin])
{
min=32000;
refac(fin);
}
} while (gasit);
}
main()
{
Citire_Cap("Graf.txt",A,n,st,fin);
caut();
for (I=1;I<=n;I++)
{
for (j=1;j<=n;j++) cout <<A[I][j][1]<<" ";
cout<<endl;
}
}

Arbori
Noţiunea de arbore

Definiţie. Se numeşte arbore un graf orientat care este conex si nu conţine cicluri.

Problema. Se citeşte un graf sa se scrie un program care sa verifice daca este arbore.

1. Mai întâi trebuie văzut daca graful este conex. In cazul grafurilor orientate aceasta problema se rezolva printr-o
simpla parcurgere in adâncime (DF). Dar in cazul grafurilor neorientate? Aici apare o problema. De la nodul i la
nodul j exista doua arce, de la i la j si de la j la i. Aceasta conduce la semnalarea unui ciclu fals. Pentru rezolvarea,
după alegerea unei muchii ,de exemplu de la i la j se elimina muchia de la j la i. In final daca au fost atinse toate
nodurile(adică daca orice componenta a vectorului s retine numai 1) înseamnă ca graful este conex.

2. Trebuie analizat daca graful nu are cicluri. Aceasta problema se rezolva tot cu ajutorul parcurgerii in adâncime.
Parcurgerea asigura selecţia unei muchi o singura data. Daca graful are cel puţin un ciclu, atunci un nod este atins
de doua ori. Cum ne putem da seama ca aceasta are loc? simplu, daca a fost atins un nod i , după care s[i]=1.

//exemplu de determinare averificarii daca un graf este arbore

//4
//1 2
//1 4
//2 3
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

198
int A[50][50],S[50],n,i,suma,gasit;

void CitireN (char Nume_fis[20],int A[50][50],int& n)


{
int I,j;
fstream f(Nume_fis,ios::in);
f>>n;
while (f>>I>>j)A[I][j]=A[j][I]=1;
f.close();
}
void df_r(int nod)
{
int k;
S[nod]=1;
for (k=1;k<=n;k++)
if (A[nod][k]==1)
{
A[k][nod]=0;
if (S[k]==0) df_r(k);
else gasit=1;
}
}
main()
{

CitireN("graf.txt",A,n);
df_r(1);
suma=0;
for (i=1;i<=n;i++)
suma+=S[i];
if (suma!=n) cout<<"e conex"<<endl;
else
if (gasit) cout<<"are un ciclu macar"<<endl;
else cout<<"este arbore";
}
Mai jos este reprezentat grafic acelasi arbore in mai multe feluri. Ultimele 3 reprezentări sunt făcute
considerând pe rând ca vârf al arborelui nodurile 1,3,2. de asemenea ultimele trei reprezentări justifica
si denumirea data grafurilor conexe si fara cicluri, cea de arbori.

199
Teorema. Fie G un graf neorientat cu n noduri. G este arbore daca si numai daca g are n-1 muchii si nu
contine cicluri.

Demonstraţie :

 Vom demonstra prin inducţie. Daca n=1,numarul muchiilor este 0(se verifica). Vom presupune
proprietatea adevărata pentru arbori cu n noduri(vom avea n-1 muchii). Fie un arbore cu n+1 noduri.
Exista cel putin un nod terminal(nod care are o singura muchie incident). Daca nu ar exista un astfel de
nod, arborele va contine cicluri(se contrazice definiţia). Eliminam nodul terminal si muchia care ii este
incident. Obţinem un arbore cu n noduri. Conform ipotezei făcute aceasta va avea n-1 muchii.
Înseamnă ca arborele cu n+1 noduri va avea n muchii(n- 1 +1).

 Fie un graf cu n-1 muchii care nu contine cicluri. Rămâne de dovedit ca G este conex. Vom
demonstra prin reducere la absurd. Presupunem ca G nu este conex. Fie G 1, G2, .. ,Gp componentele
conexe. Fiecare dintre ele indeplineste conditiile:

1) Este conexa(asa a fost aleasa);


2) Nu contine cicluri(pentru ca G nu contine cicluri).

Rezulta ca fiecare dintre ele este arbore. Fie mi numarul muchiilor si ni numarul nodurilor fiecarui arbore
Gi. Avem mi=ni-1. Dar m1+m2+….+mp=n-1. Rezulta: n1-1+n2-1+…..np-1=n-1, deci n1+n2+…..+np=n+p-1.
Dar G are n noduri. Rezulta :n+p-1=n,deci p=1. In concluzie exista o singura componenta conexa care
nu contine cicluri. Deci G este arbore.

 Din demonsratie s-a vazut ca un graf neorientat fara cicluri


dar neconex este alcătuit, din mai mulţi arbori. Din acest
motiv, un astfel de graf se numeşte pădure !
 Tot in aceasta demonstatie, a fost introdus termenul de nod terminal al unui arbore cu
o singura muchie incident.

 Ati reţinut, ca arborele poate fi privit ca avand un anumit varf ! Varf al arborelui poate
fi oricare nod al sau, deci si unul termial !

200
Algoritmul lui Prim

Fie G=(X,) un graf neorientat şi conex. Graful este dat prin matricea costurilor. Se cere să se
determine arborele de cost parţial minim (între oricare două noduri să existe un drum), iar în plus suma
muchiilor să fie minimă.
O problemă concretă, în care intervine problema enunţată, este cea a conectării oraşelor cu
cost minim.
Avem N oraşe precum şi costul conectării anumitor perechi de oraşe. Se cere să se genereze
muchii care asigură existenţa unui drum între oricare două oraşe astfel încât costul cuplării să fie
minim.
Pentru rezolvare se folosesc trei vectori:
-vectorul S, vector caracteristic. Avem S(I)=0 dacă nodul I nu aparţine arborelui construit şi
S(I)=1 în caz contrar;
-vectorul T reţine pentru fiecare nod care se adaugă arborelui nodul părinte al acestuia (cu
ajutorul acestui vector se poate reconstitui arborele);
-vectorul P reţine pentru fiecare nod C costul arcului de la părinte la el.

Prezentarea algoritmului.

P1) Se citeşte N (numărul nodurilor), matricea costurilor A şi nodul de pornire V (S(V)=1);

P2) Se alege muchia de cost minim (L,C) care are o extremitate într-unul din nodurile
arborelui deja construit (S(L)=1), iar cealălaltă într-un nod care nu aparţine arborelui (S(C)=0). Se pune
T(C)=L şi P(C)=A(L,C);

P3) Dacă nu au fost alese N-1 muchii, se reia pasul 2.

Exemplu. Fie graful din figura următoare: (s=(0 1 1 1 1) )

3 2

5 2

201
2 1 5

4 3

4
Se porneşte cu nodul 1(v=1).
Alegem muchia de cost minim (1,2).
S=(0 0 2 2 1)

Pentru nodurile 1 şi 2, ca puncte de plecare, se alege muchia de cost


minim (2,4) si s=(0 0 4 0 1)

1
4

Pentru nodurile 1,2 şi 4 se alege muchia de cost minim (1,5).


S=(0 0 4 0 0)

2 3
5

202

41
2 5
Pentru nodurile 1,2,4 şi 5 se alege muchia de cost minim (4,3) .

1
3
2

4
3

s=(0 0 0 0 0)
Am ales patru muchii şi s-a obţinut muchia de cost minim.
Configuraţiile finale ale vectorilor T şi P sunt:

1 2 3 4 5
T 0 1 4 2 1
P 0 2 4 1 3

Dacă pornim dintr-un alt nod, este posibil să obţinem un alt arbore dar şi el va avea costul
minim.

Demonstrarea algoritmului.

În urma aplicării algoritmului se obţine un arbore (vom avea N noduri şi N-1 muchii).
Rămâne de demonstrat că acest arbore este de cost minim. Notăm cu Gk=(Xk,k) arborele
obţinut după alegerea a k muchii, cu k{1,2,…,N-1}. Fie G1 un arbore de cost minim. Fie M1,M2,
…,Mk primele k muchii găsite în urma aplicării algoritmului pentru arborele Gk+1. Considerăm că
muchia Mk este prima muchie care nu aparţine lui G1. Fie P şi Q cele două noduri unite de muchia Mk.
Este evident că în G1, cele două nu sunt unite direct (în caz contrar muchia Mk ar face parte din arborele
G1). Aceasta înseamnă că în G1, nodurile P şi Q sunt unite printr-un lanţ. Acest lanţ nu aparţine lui G k+1,
pentru că el împreună cu Mk ar forma un ciclu. Înseamnă că acest lanţ uneşte în G1 două noduri, P1 şi
Q1 cu P1Xk şi Q1Xk. În caz contrar dacă ar uni numai noduri din Xk înseamnă că Gkm ar conţine un
lanţ (conţine muchia Mk, care uneşte pe P şi Q, conţine şi restul lanţului din G1 pentru că primele k
noduri în G1 şi Gk sunt legate identic). Presupunem nodurile P1 şi Q1 unite prin muchia M1. Înlocuim
în G1 pe M1 cu Mk. În urma acestei înlocuiri,G1 se transformă într-un alt arbore G2. Dar
A(P,Q)A(P1,Q1) pentru că în caz contrar, prin logica algoritmului, s-ar fi ales muchia M1. Aceasta
înseamnă că arborele parţial G2 rămâne tot de cost minim. În plus G1 şi Gk+1 au k+1 muchii care
coincid. Repetăm procedeul până obţinem coincidenţa a n-1 muchii. Rezultă de aici că l-am
transformat pe G1 în arborele generat de algoritm fără a-i modifica costul. În concluzie arborele generat
de algoritm este de cost minim.

203
//algoritmul lui Prim
5
122
153
142
255
241
237
344
327
454
412
421
434
531
544
525
513
=>cost 10
0 1 4 2 1 e traseul
//
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >
const float Pinfinit=1.e20;
float A[50][50],min,cost;
int s[50],t[50],n,i,j,k,v;

void Citire_cost (char Nume_fis[20],float A[50][50],int& n)


{
int I,j;
float c;
fstream f("graf.txt",ios::in);
f>>n;
for (I=1;I<=n;I++)
for (j=1;j<=n;j++)
if (I==j) A[I][j]=0;
else A[I][j]=Pinfinit;
while (f>>I>>j>>c) A[I][j]=c;
f.close();
}

void main( )
{
cost=0;
Citire_cost("graf.txt",A,n);
cout<<"nodul de pornire";
cin>>v;
for (i=1;i<=n;i++)

204
if (i==v) s[i]=0;
else s[i]=v;
for (k=1;k<=n-1;k++)
{
float min=Pinfinit;
for (i=1;i<=n;i++)
if (s[i])
if (A[s[i]][i]<min)
{
float min=A[s[i]][i];
j=i;
}
t[j]=s[j];
cost+=A[s[j]][j];
s[j]=0;
for (i=1;i<=n;i++)
if (s[i] && A[i][s[i]]>A[i][j]) s[i]=j;
}
cout<<"cost="<<cost<<endl;
for (i=1;i<=n;i++) cout<<t[i]<<" ";
}
Notiunea de arborescenta

Notiunea de arbore poate fii extinsa si pentru grafuri orientate.


Definitie. Fiind date doua noduri i si j ale unui graf orientat, se spune ca exista un lant de la i la j daca
exista o succesiune de arce, indiferent de sensul lor prin care cele doua noduri sunt unite.
 Daca exista un lant de de la i la j, exista si unul de la j la i.

Definitie. Un graf orientat G=(x,) exte conex daca  ijx


exista un lant de la i la j.

 Daca un graf orientat este tare conex, atunci el este conex, dar reciproca nu este
adevarata. Graful de mai sus este conex.
Definitie. Un graf orientat admite un ciclu daca exista un mod i, pentru care exista un lant de la i
la i.

Exemplu. In graful anterior nodurile 4 2 3 sunt unite printr-un ciclu.

Definitie. Un graf orientat este arbore daca nu este conex si nu admite cicluri.

Exemple:

205
1. Graful anterior nu este arbore pentru ca admite un ciclu.
2.

Definitie. Un graf orentat g=(x,) admite o radacina vx daca pentru orice xx-(v) exista un drum
(atnete, nu lant) de la v la x.

Exemple:

1. graful de mai sus nu admite o radacina. De exemplu nu exista drum de la 1 la 3


(1 nu este radacina), nu exista drum de la 3 la 4 (nici 3 nu este radacina) etc.

2. Graful alaturat are radacinile 1, 2, 3,4.

Definitie. Se numeste arborescenta un graf orientat care indeplineste simultant doua conditii :
1.Este arbore;
2.Admite radacina.

 Intr-o arborestenta radacina este unica. Daca de exemplu exista doua radacini v 1 si v2 atunci exista
drum de la v1 la v2 si de la v2 la v1. aceasta presupune existenta unui ciclu, deci nu este arbore.
 De regula, atunci cand se da o arborescenta se preciaza radacina sa.

Alaturat este prezentata o arborescenta de radacina 2.

206
 Se observa ca din radacina pleaca arce, nu intra. Daca ar si intra s-ar obtine un ciclu.

 de asemenea, orice nod are un singur predecesor. Daca, prin absurd, ar avea doi sau mai multi, s-ar
obtine un ciclu care include radacina.

Problema. Se citeste un graf orientat. Acesta este dat prin matricea de adiacenta.se cere ca programul
dv. sa decida daca graful este sau nu oarborescenta. In caz afirmativ, se va tipari radacina acesteia.

207
Rezolvare.

1. Tebuie decis mai intai daca graful orientat este arbore. Acesta se face printr-o singura
parcurgere in adancime,asemanator cu altgoriymul aplicat in cazul grafurilor orienta.
2. In cazul cand graful este arbore , trebuie vazut daca acesta are o radacina. Se testeaza, pe
rand, fiecare nod daca indeplineste conditia de radacina. Fiecare test se face printr-o
parcurgere in adancime pornind de la nodul respectiv.

//exemplu de determinare arborescenta

//4
//1 2
//1 4
//2 3
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

int A[50][50],s[50],b[50][50],ok,radacina,n,i,j,r,suma,gasit;

void Citire(char Nume_fis[20],int a[50][50],int& n)


{
fstream f(Nume_fis,ios::in);
int I,j;
f>>n;
while (f>>I>>j) A[I][j]=1;
f.close();
}
void df_r(int nod)
{
int k;
cout<<nod<<" ";
s[nod]=1;
for (k=1;k<=n;k++)
if ((A[nod][k]==1) && (s[k]==0))
df_r(k);
}

main()
{
Citire("Graf.txt",A,n);
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
b[i][j]=A[i][j];
df_r(1);
for (i=1;i<=n;i++) suma+=s[i];
if (suma!=n) cout<<"NU e conex"<<endl;
else cout<<" e conex"<<endl;
if (gasit) cout<<"are un ciclu"<<endl;
else cout<<" nu are cicluri"<<endl;
if (suma==n && ! gasit)

208
{
cout<<"este arbore"<<endl;
ok=1;
}
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
b[i][j]=A[i][j];
if (ok)
{
r=1;
do
{
suma=0;
for (i=1;i<=n;i++) s[i]=0;
df_r(r);
for (i=1;i<=n;i++) suma+=s[i];
if (suma==n)
{
cout<<"radacina este "<<r<<endl<<"este arborescenta";
radacina=1;
}
else r++;
}
while (!radacina && r<=n);
if (!radacina) cout <<"nu are radacina";
}
}

Metode de memorare a arborilor

1. asa cum am aratat, un arbore este un graf neorientat, cu anumite proprietati.


Aceasta inseamna ca el poate fi reprezentat ca un graf. De aici rezulta ca pentru
reprezentarea unui arbore se pot utilza:

- matricea de adiacenta;
- liste de adiacente.
2. O a doua forma de reprezentare a arborilor este legatura de tip TATA . arborele se
reprezinta sub forma unui vector t cu n componente: daca t[i]=k, atunci nodul i
este descendent al nodului k. Daca nodul i este varf, t[i]=0.

5 3 5 5 0 3 4 1 7--------- k
1 2 3 4 5 6 7 8 9 --------- t[i]

 Legatura de tip TATA se mai numeste si legatura cu referinte ascendente.

209
 In mod evident, legatura de tip TATA este determinata si de nodul ales ca varf ! Daca, de exemplu
pentru acelasi arbor varful este 9, reprezentarea este alta. Este ca si cum „apucam” arborele de un nod
si celelalte cad !

 De fapt prin legatura de tip TATA se reprezinta o padure !

035003 417
123456789

 Aceasta reprezentare a mai fost intalnita. De exemplu, la altgoritmul lui Dijkstra !

3.Codul lui Puffer(facultativ). Pentru a reprezenta un arbore oarecare se pot utiliza doi vectori, pe care-i
vom numi t-de la nodul terminal – si pt – de la parinte nod terminal. Modul in care acestia retin datele
este explicat mai jos:

 Se cauta cel mai mic nod terminal, acesta este retinut in vectorul t iar parintele sau este
memorat in vectorul pt.
 Se obtine un nou arbore renuntand la nodul terminal si la muchia care-l uneste de parinte.
 Procedeul se rea pana cand ramane un arbore cu un singur nod.

Exemplu .

Pentru arborele alaturat cel mai mic nod terminal este doi,iar parintele trei.

In noul arbore ,cel mai mic nod terminal este 6, iar parintele lui 6 este 3.

210
Cel mai mic nod terminal este 3, iar parintele 5.

Cel mai mic nod terminal este 8, iar parintele sau este 1.

Cel mai mic nod terminal este 1, iar parintele sau este 5.

211
 Pana in acest moment am
memorat arborele prin utilizarea a 2 vectori t si pt. Fiecare dintre ei, are n-1 componente!

 Prin logica altgoritmului nodul care ramane este cel mai mare adica nodul n. Acesta este ultimul
memorat in vectorul pt.Prin urmare, daca se cunoaste n sunt suficiente n-2 componente pentru vectorul
pt.

 Foarte important! Vectorul t se poate reconstitui doar daca cunoastem vectorul pt. aceasta inseamna
ca un arbore cu n noduri a fost memorat doar printr-un vector cu n-2 componente!

Pentru reconstituirea vectorului t pornim de la pt,vom incepe prin a memora in pt, numarul n, pentru
componenta n-1. vectorul t se reconstituie prin formula:

i{1,2…n-1}
t[i]=min{kk{t[1]=t[2],…t[i-1],pt[i],pt[i+1]…pt[n-1]}}

Cum s-a dedus formula de mai sus?

- daca numarul se gaseste in pt[i],pt[i+1],…pt[n-1] inseamna ca nodul respectiv nu a fost eliminat pana
la pasul i, pentru ca este parinte.
- daca numarul se gaseste in t[1],t[2],…t[i-1] inseamna ca a fost extras la unul din pasii anteriori.
- dintre nodurile care nu se gasesc ca mai sus , la pasul i a fost extras nodul minim.

Exemplu. Plecam de la n=9,si pt={3 3 5 1 5 4 7 }


Pasul 1
T={}
Pt={3 3 5 1 5 4 7,9}
Cel mai mic numar care nu se gaseste in pt si este intre 1 si 9 este 2.

Pasul 2
T={2}
Pt={3 3 5 1 5 4 7,9}
Se alege 6.

Pasul 3.
T={2 6 }
Pt={3 3 5 1 5 4 7,9}
Se alege 8.

212
//exemplu la codul PUFFER
//n=9
//3 3 5 1 5 4 7 9
//=>2 6 3 8 1 5 4
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

int t[50],pt[50],i,j,k,n,gasit;
main()
{
cout<<"n=";cin>>n;
for (i=1;i<=n-2;i++)
{
cout<<"PT["<<i<<"]";
cin>>pt[i];
}
pt[n-1]=n;k=1;
for (i=1;i<=n-1;i++)
{
k=1;
do
{
gasit=0;
for (j=0;j<=i-1;j++)
if (t[j]==k) gasit=1;
if (!gasit
)
for (j=i;j<=n-1;j++)
if (pt[j]==k) gasit=1;
if (gasit) k++;
} while (gasit);
t[i]=k;
}
for (i=1;i<=n-1;i++)
cout<<t[i]<<" ";
}

Arbori binari

Notiunea de arbore binar

213
Programatorii folosesc de multe ori prin abuz de limbaj, termenul de arbore, in loc de
arborescenta. In astfel de cazuri se specifica radacina care se mai numeste si varf si se considera
ca sensul arcelor este implicit,motiv pentru care nu se mai reprezinta grafic.

In cazul in care arborescenta are cel mult doi descendenti, unul stang si unul drept, spunem ca avem
un arbore binar.

Exemplu. Mai jos vedeti o arborescenta cu radacina 1 care este un arbore binar. Alaturat obs. Modul in
care se reprezinta grafic renuntand la sensurile arcelor, care sunt implicite.

214
 Se presupune ca nodurile sunt asezate pe mai multe niveluri. Radacina este pe
nivelul 0, descenndentii direci directi ai radacini sunt pe nivelul 1, descendentii directi
ai nodurilor de pe nivelul 1 sunt pe nivelul 2 etc.
 Numarul de niveluri mai putin cel al radacinii, ocupate de nodurile grafului,se numeste
adancimea arborelui binar.
 Vom face dinstinctie intre descendentul stang si cel drept. De exemplu, arborii de mai
jos sunt considerati dinstincti.

Modalitati de reprezentare a arborilor binari

Desigur, arborii binari pot fi reprezentati ca orice grf orientat, dar


aceasta forma este deosebit de greoaie in aplicatii. Din acest motiv sunt
cu mult mai convenabile reprezentarile pe care le urmarim in continuare.
1. reprezentarea cu ajutorul vectorilor ( clasica ).

215
Un arbore binar poate fi reprezentat cu ajutorul a doi vectori, pe care ii vom numi st (de la stanga ) si dr
(de la dreapta). Pentru fiecare nod i dintre cele n, st[i] retine nr. de ordine al nodului stang subordonat
de i, iar dr[i] retine nr de ordine al nodului drept subordonat de i. Daca nu exista nod subordonat retine
0.

Exemplu. Arborele binar cu 7 noduri si v=1 de pe pagina anterioara se reprezinta astfel:

st 2 4 5 0 0 0 0

1 2 3 4 5 6 7

dr 3 0 6 0 7 0 0

2. Reprezentarea in HEAP (actuala).

Programul va retine doar adresa radacinii (varfului). In aplicatii veti intalni numeroase exemple in acest
sens, motiv pentru care ne oprim aici cu aceasta reprezentare.

3. Reprezentarea cu ajutorul legaturii TATA.

Aceasta a mai fost prezentata in cazul arborilor neorientati. Mentionam doar faptul ca aceasta
reprezentare este neconvenabila in majoritatea aplicatiilor.

Modalitati de parcurgere a arborilor binari

In scopul prelucrarii,este necesar ca nodurile arborelui binar sa fie vizitate. Axista mai multe

modalitati de parcurgere a arborilor binari carer difera prin ordinea de vizitare a nodurilor.

216
 Putem considera ca fiecare nod al arborelui binar subordoneaza un subarbore
binar stang si unul drept. Pe baza acestei observatii putem scrie usor
subprograme recursive pentru diverse le modalitati de pacurgere.

Principalele modalitati de parcurgere ale unui arbore binar sunt:

A) Parcurgerea in inordine – SVD – se se patrcurge mai


intai subarborele stang, apoi varful apoi subarborele
drept.
B) Parcurgerea in preordine – VSD – se parcurge mai
intai subarborele stang, apoi subarborele drept.
C) Parcurgerea in postordine – SD – se parcurge mai
intai subarborele stang, apoi subarborele drept, apoi
varful.
D) Parcurgerea in adancime – a fost studiata pentru
grafuri, aici se aplica in particular. Se parcurge
radacina, apoi nodurile de pe nivelul 1,apoi cele de pe
nivelul 2 etc.

 De exemplu parcurgerea SDV se face pe urmatoarea idee: varful subordoneaza


doi subarbori: cel stang si cel drept. Se trece la subarborele stang, apoi la varf,
apoi la subarborele drept. Pentru fiecare subarbore se repeta rationamentul.

Ordinea de parcurgere pentru arborele alaturat este: inordine –SDV-:4 2 1 5 7 3 6

preordine –VSD-:1 2 4 3 5 7 6

postordine –SDV-:4 2 7 5 6 3 1

latime:1 2 3 4 5 6 7

217
Programul urmator citeste si parcurge in inordine,postordine si preordine
un arbore binar. Arborele este retinut in HEAP. Pentru a marca faptul ca
descendentul unui anumit nod lipseste se introduce 0.
//sa se testeze parcurgerile de arbori binari
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

struct nod {
int nr ;
struct nod * st ;
struct nod * dr ;
} ;

nod * c;
nod* arb()
{
int n;
nod* c;
cout<<"n=";cin>>n;
if (n)
{
c=new nod;
c->nr=n;
c->st=arb();
c->dr=arb();
return c;
}
else
return 0;
}

void Preordine ( nod *a )


{
if ( a)
{
cout<< a -> nr ;
Preordine ( a -> st ) ;
Preordine ( a->dr ) ;
}
}
void Postordine ( nod *a )
{
if ( a )
{
Postordine (a -> st) ;
Postordine ( a -> dr ) ;
cout<< a -> nr ;

218
}
}
void Inordine ( nod *a )
{
if ( a)
{
Inordine (a -> st ) ;
cout<< a -> nr ;
Inordine ( a -> dr ) ;
}
}
void main( )
{
c=arb();
Inordine (c);cout<<endl;
Postordine (c); cout<<endl;
Preordine (c);cout<<endl;
}
Arbore binar de cautare
Definitie. Se numeste arbore de cautare un arbore binar ale carui noduri
au o cheie de identificare,iar pentru fiecare nod avem proprietatiile
urmatoare:
- orice cheie asociata unui nod al subbarborelui stang este mai mica decat cheia asociata
nodului;
- orice cheie asociata unui nod al subarborelui drept este mai mare decat cheia asociata
nodului.

Cheile de identificare sunt distincte !

Alaturat observati un arbore de cautare.

1. INSERAREA

Crearea arborilor de cautare se face aplicand de un nr de ori operatia de inserare. Regula de inserare
este urmatoarea:

 Se compara cheia asociata unui nod cu cheia inregistrarii care se insereaza. Avem trei posibilitati:

- cheia coincide cu nr – se renunta la inserarea acelui numar;


- cheia este mai mare decat numarul – se incearca inserarea in subarborele stang;
- cheia este mai mica decat numarul – se incearca inserarea in subarborele drept.

 Inserarea propriu-zisa se realizeaza atunci cand subarborele stang,respectiv


drept,este vid,astfel se reia.

Vezi procedura INSERARE.

219
2. CAUTAREA

Se face in mod asemanatorcu inserarea motiv pentru care nu o mai comentam.

3. LISTAREA

Informatia se poate lista utilizand oricare din metodele cunoscute pentru parcurgerea arborilor. Daca
dorim listarea informatiilor in ordinea strict crescatoare a cheilor,se utilizeaza metoda stang-varf-dreapta
(inordine), intrucat pentru orice nod avem urmatoarele:

 cheile nodurilor din subarborele stang sunt mai mici decat cheia asociata
nodului;
 cheile nodurilor din subarborele drept sunt mai mari decat cheia asociata
nodului.

Vezi procedura SVD.

4. STERGEREA

Dupa stergerea unui nod care are o anumita cheie, arborele ramas trebuie sa fie de cautare.

Se disting 4 situatii posibile:

a) nodul care urmeaza sa fie sters este nod terminal – in acest caz se face stergerea
avand grija ca la parintele lui sa inlocuim adresa catre el cu nil;
b) nodul care urmeaza a fi sters subordoneaza un singur subarbor – cel drept – caz in
care parintelui se va inlocui adresa catre el cu adresa subarborelui drept,iar nodul
respectiv se sterge;
c) nodul care urmeaza a fi sters subordoneaza un singur subarbore – cel stang – caz in
care parintelui i se va inlocui adresa catre el cu adresa subarborelui stang, iar nodul
respectiv se sterge;
d) nodul care urmeaza a fi sters( dupa cum vom vedea, acesta se va sterge numai logic)
subordoneaza doi subarbori, caz in care se fac operatiile:

- se indentifica cel mai din dreapta nod al subarborelui stang coorespunzator nodului care
urmeaza a fi sters (acesta va fi sters in mod efectiv, nu inainte de a muta informatiile sale la
nodul care se sterge logic);
- cheia acestuia si alte informatii utile continute de el se muta la nodul care urmeaza a fi sters
- subarborele stang al nodului care se va sterge fizic se leaga:
- in stanga nodului care se sterge logic (daca nodul indentificat ca cel mai din dreapta din
subarborele stang este descendent direct al nodului care se sterge logic)
- in dreapta tatalui nodului care se sterge fizic( in caz contrar);

Exemple de stergere:

1. Arborelui din stanga i se sterge nodul 8. acesta nu subordoneaza nici un alt arbore.

220
2. Arborelui din stanga i se sterge nodul 9. acesta subordoneaza un singur subarbore, cel
drept.

3. Arborelui din stanga i se sterge nodul 3. Cel mai din dreapta nod al subarborelui stang este 1.
se obtine:

4. Arborelui din stanga i se sterge nodul 7. cel mai din dreapta nod al subarborelui stang este 6.
tatal nodului care se sterge fizic este 3. in dreapta sa se leaga subarborele 5 4 . se obtine:

221
Vezi procedura STERG. In situatia in care nodul care urmeaza a fi sters subordoneaza doi arbori,se
apeleaza procedura CMMD.

 Intrebarea la care trebuie sa raspundem in continuare este urmatoarea:de ece daca


se sterge in acest mod un nod,arborele ramane de cautare? Stergerea unui nod se
face in mod dinstinct pentru fiecare din cele 4 cazuriaratate. Datorita simplitati
prelucrarii primele tri cazuri nu necesita comentarii. In cazul 4 se indentifica nodul cel
mai din dreaptadin arborele stang. Cheia acestuia trece in locul cheii nodului care se
sterge. Aceasta este mai mica decat cheia initiala,este in acelasi timp cea mai mare
din subarborele stang,deci este cea mai mare cheie mai mica decat cheia care se
sterge. Iata motivul pentru care aceasta trece in locul cheii sterse logic.
 Transmiterea parametrului c se face prin referinta. Adresa de alocare va fi trimisa
automat parintelui,caadresa de subarbore stang sau drept (duopa caz).
 Altgoritmul are complexitatea in cazul cel mai defavorabil 0(n 2). In cazul in care, de
exemplu cheile inserate sunt in ordine crescatoare, arborele va degenera intr-o lista
liniara –orice nod are numai un descendent drept,iar
 inserarea unui nod inseamna parcurgerea tuturor nodurilor deja inserate in pasul
anterior.

Teoria regasirii informatiei este deosebit de importanta pentru viata practica. Aceasta conduce la o
cautare rapida (putine comparatii).
//
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

struct nod
{
int nr;
nod *as,*ad;
};
nod *v,*man;
char opt;
int k;

void inserare(nod*& c,int k)

222
{
if (c)
if (c->nr==k)
cout<<"este deja";
else
if (c->nr<k) inserare(c->ad,k);
else
inserare(c->as,k);
else
{
c=new nod;c->as=c->ad=0;
c->nr=k;
}
}

void cautare(nod*& c,nod*& adr,int k)

{
if (c)

if (c->nr<k) cautare(c->ad,adr,k);
else
if (c->nr>k)
cautare(c->as,adr,k);
else
adr=c;
else
adr=0;
}

void parcurg (nod* c)


{
if (c)
{
parcurg(c->as);
cout<<c->nr<<endl;
parcurg(c->ad);
}
}

void cmmd(nod*&c,nod*& f)
{
if (f->ad) cmmd(c,f->ad);
else
{
c->nr=f->nr;
man=f;
f-f->as;
delete man;
}
}
void sterg (nod*& c,int k)
{
nod* f;
if (c)
if (c->nr==k)
if (c->as==c && c->ad==0)
{
delete c;
c=0;
}

223
else

if (c->as==0)
{
f=c->ad;
delete c;
c=f;
}
else
if (c->ad==0)
{
f=c->as;
delete c;
c=f;
}
else
cmmd(c,c->as);
else
if (c->nr<k)
sterg (c->ad,k);
else
sterg(c->as,k);
else
cout<<"nu e numarul ";
}
main()
{char opt;
v=0;
do
{
cout<<"tastati t-terminare,i-inserare,l-listare,c-cautare,s-
stergere";cin>>opt;
switch (opt)
{
case 'i':
cout<<"k=";cin>>k;
inserare(v,k);
break;
case 'l':parcurg(v);
break;
case 'c':
cout<<"k=";cin>>k;
cautare(v,man,k);
if (man) cout<<k<<endl;
else
cout <<"nu exista acest nod"<<endl;
break;
case 's':
cout<<"pe cine stergi ";
cin>>k;
sterg(v,k);
break;
}
}while (opt!='t');
}

224
225

S-ar putea să vă placă și