Documente Academic
Documente Profesional
Documente Cultură
APAS PE
ACEASTA
OPTIUNE
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.
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.
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 :
Un stream C++ este deci un obiect aparţinînd uneia din clasele din cele 3 categorii
enumerate mai sus.
Cînd îşi începe execuţia un program scris în C++, se deschid automat patru stream-uri
încorporate. Acestea sînt :
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) :
O secvenţă prea lungă se poate continua pe rîndul următor, ca în exemplul de mai jos
(o reluare a exemplului anterior):
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;
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& flush() - goleşte tamponul, transferînd datele către dispozitivul fizic asociat.
b. Clasa istream
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 :
int get() - citeşte din stream şi întoarce ca rezultat un caracter (EOF la sfîrşitul
fişierului).
Exemplu :
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 peek(); - întoarce caracterul următor fără să-l extragă din stream.
Funcţiile
long tellg();
ostream& seekg(long n);
ostream& seekg(long n, seek_dir);
#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;
return 0;
}
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;
#include "stdafx.h"
#include <iostream>
using namespace std;
int main() {
double ctemp;
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() {
double 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;
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;
return 0;
}
// sa se scrie n la puterea 3
#include "stdafx.h"
#include <iostream>
using namespace std;
int main() {
double n;
return 0;
}
return 0;
}
TIPURI INTREGI
TIPURI REALE
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";
}
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 (YankeesScore == RedSoxScore)
cout << "Wow, it really was a tie!";
}
#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;
}
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;
}
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";
}
#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;
}
#include "stdafx.h"
#include <iostream>
using namespace std;
int main() {
int n, remainder;
remainder = n % 2;
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;
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;
z = (x > y) ? x : y;
int main() {
int 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;
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;
return 0;
}
Instructiunea expresie
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 ;
}
#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
#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
Instructiunea FOR
#include "stdafx.h"
#include <iostream>
using namespace std;
int main() {
int i, n;
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;
}
int main() {
int n; // Number to test for prime-ness
int i; // Loop counter
int is_prime; // Boolean flag
is_prime = true;
// 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
is_prime = true;
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;
}
#include "stdafx.h"
#include <iostream>
using namespace std;
int main() {
int i, n1, n2;
i = n1;
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;
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;
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;
}
#include "stdafx.h"
#include <iostream>
using namespace std;
#include<math.h>
main()
{
double h,x_inf,x_sup,x;
cout<<"introduceti X_inf:"<<endl;
cin>>x_inf;
cout<<"introduceti X_sup:"<<endl;
cin>>x_sup;
cout<<"introduceti H :"<<endl;
cin>>h;
if (x<=0) h=0.1;
if (x_inf<=0 ||x_sup<=0||x_inf>=x_sup)
{
x_inf=1;
x_sup=2;
}
for (x*=x_inf ;x<=x_sup; x+=h)
cout<<x<<exp(x)<<sqrt(x)<<log(x)<<pow(x,2)<<endl;
}
int main() {
int i, n;
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;
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;
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
is_prime = true;
// 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
is_prime = true;
// Print results
if (is_prime)
cout << "Number is prime.";
else
cout << "Number is not prime.";
return 0;
}
Functii matematice
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 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 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:RR*+.
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
VECTORI SI MATRICE
Tablouri in C++
Adresarea unei componente se face prin indice, care se trece intre paranteze drepte, iar
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};
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};
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;
}
#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};
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;
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
#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;
}
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
#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;
}
#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";
}
#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
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];
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];
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;
int main() {
char str[STRMAX + 1];
char name[100];
char addr[200];
char work[200];
return 0;
}
#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);
return 0;
}
#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;
return 0;
}
#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
#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*.
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.
#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;
}
main ( )
{
char a[20]="mama",b[100]="merge";
strcat (a,b);
cout<<a;
}
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 ";
}
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);
}
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";
}
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;
}
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";
}
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;
}
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;
}
main ( )
{
char sir[1000],separator[ ]=", ", *p;
cin.get(sir,1000);
p=strtok(sir,separator);
while (p)
{
cout<<p<<endl;
p=strtok(NULL, separator);
}
}
main ( )
{
char sir[1000],separator[ ]=", ", *p;
cin.get(sir,1000);
p=strtok(sir,separator);
while (p)
{
cout<<p;
p=strtok(NULL, separator);
}
}
main ( )
{ char cuvant[100],cifre[ ]="0123456789";
cout<<"Introduceti cuvantul "; cin>>cuvant;
if (strspn(cuvant,cifre)==strlen(cuvant))
cout<<"numeric";
else cout<<"nenumeric";
}
main ( )
{ char cuvant[100],cifre[ ]="0123456789";
cout<<"Introduceti cuvantul "; cin>>cuvant;
if (strcspn(cifre,cuvant)==10) cout<<"corect";
else cout<<"incorect";
}
main ( )
{
char a[20];
cout<<"Introduceti cuvantul"; cin>>a;
cout<<strupr(a);
}
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);
}
}
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;
}
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;
}
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:
M a r iii n \n 1 H EOF
pointer
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;
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:
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
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.
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 :
Exemplu (reluare) :
Formatarea datelor
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
};
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
Exemplu :
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& nume_manip(parametru)
ostream& nume_manip(parametru)
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 :
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 :
int width() - întoarce valoarea actuală a dimensiunii cîmpului de afişare; este supradefinită
cu:
#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];
#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];
//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
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;
}
#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];
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];
ifstream file_in(filename);
if (! file_in) {
cout << "File " << filename << " could not be opened.";
return -1;
}
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;
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( );
}
#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( );
}
#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( );
#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( );
}
#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( );
}
#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( );
}
#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( );
}
}
int main()
{
char fileName[80];
char buffer[255]; // for user input
cout << "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);
}
#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:
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(){}
private:
int itsWeight;
long itsNumberDaysAlive;
};
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);
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.
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:
#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);
}
// sa se creeze un cap de tabel cu o procedura
#include "stdafx.h"
#include <iostream>
using namespace std;
main()
{
void cap_tabel(void);
cap_tabel();
}
void cap_tabel(void)
{
cout<<"Nr,Cod,Denumire,UM,Cantitate";
}
#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 creeze doua functii care calculeaza suma si suma
patratelor //componentelor unui vector
#include "stdafx.h"
#include <iostream>
using namespace std;
main()
{
static int x[10]={2,13,14,15,16,7,8,9,11,22};
int n=10,i;
for (i=0;i<=n;i++) cout<<x[i];
cout<<suma1(x,n);
cout<<"suma patratelor este:"<<suma2(x,n);
for(i=0;i<n;i++) cout<<x[i];
}
// Sa se scrie o functie care primind pointeri la doua valori flotante, calculeaza suma lor si
returneaza // pointer la rezultat.
#include "stdafx.h"
#include <iostream>
using namespace std;
#include<math.h>
float *suma(float *pa,float *pb)
{
static float sum,*psum;
psum=∑
sum=*pa+*pb;
return psum;
}
main ( )
{
float a=6,b=8, *ps;
ps=suma(&a,&b);
cout<<*ps;
}
// sa se determine minimul a trei numere dar fara sa apara valoarea 3
#include "stdafx.h"
#include <iostream>
using namespace std;
#include<math.h>
#include <stdio.h>
main()
{
int val,minim();
if (minim()==val)
cout<<"a fost gasit";
else cout<<"datele sunt eronate";
}
int minim()
{
int a,b,c,val;
cout<<"introduceti a:";
cin>>a;
val=a;
cout<<"introduceti b:";
cin>>b;
cout<<"introduceti c";
cin>>c;
val+=c;
if(val== 3)
{
cout<<"a fost gasita";
if ((a>b)&&(b>c))
cout<<c;
else
cout<<b;
if (a>c)
cout<<c;
else
cout<<a;
return val;
}
else return c ;
}
#include "stdafx.h"
#include <iostream>
using namespace std;
#include<math.h>
#include <stdio.h>
int f(int x,int y)
{
return x+y;
}
main( )
{
int val;
val=f(3,5);
cout<< val;
}
#include "stdafx.h"
#include <iostream>
using namespace std;
int rotunjire ( double x)
{
int y ; y=(int) x;
if (x-y >=0.5 )
++ y;
else y ;
return y;
}
main ( )
{
double a=4.30 ,b=3.49 ,c=7.7 ,d=0.5;
cout <<rotunjire(a) ;
cout <<rotunjire (b);
cout << rotunjire ( c );
cout << rotunjire (d);
}
#include "stdafx.h"
#include <iostream>
using namespace std;
double f( double x)
{
return(x*x*x+3*x+7);
}
double m=(a+b)/2;
cin>>a;cin>>b;
if (f(x)*f(b)>0)
{
cout<<"\n ";
exit(1);
}
cout<<"\n radacina este %f"<< bisect (a,b,aprox ) ;
}
#include "stdafx.h"
#include <iostream>
using namespace std;
#include<math.h>
#include <stdio.h>
int suma(int a,int b)
{
cout<<"s-a intrat in functia suma";
return a+b;
}
int diferenta(int a,int b)
{
cout<<"s-a intrat in functia diferenta";
return a-b;
}
main ( )
{
int a,b;
char *text[2] ={"suma","diferenta"};
cout <<"introduceti a";cin>>a;
cout<<"introduceti b";cin>>b;
cout<<"suma este:",text[0],suma(a,b);
cout<<"suma este:",text[1],diferenta(a,b);
}
#include "stdafx.h"
#include<iostream>
using namespace std;
#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]<<" ";
#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 interschimbe doua valori prin referinta se face transmitrea
datelor
#include "stdafx.h"
#include <iostream>
using namespace std;
void comuta2 ( int *a ,int *b )
{
int temp ;
temp = *a , *a = *b , *b = temp ;
}
main ( )
{
int a = 7, b = 3 ;
cout << "a = "<<a<<"b = " <<b ;
comuta2 ( &a ,&b ) ;
cout << "a ="<<a<<"b = "<<b ;
}
#include "stdafx.h"
#include <iostream>
using namespace std;
void comuta2 ( int *a ,int *b )
{
int temp ;
temp = *a , *a = *b , *b = temp ;
}
void comuta3 (int a [10], int i,int j )
{
int temp ;
temp = a[i] , a[i] = a[j] , a[j] = temp ;
}
main ( )
{
int a [10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
comuta2( &a[6], &a[2]) ;
comuta3(a,1,3);
for (int i=0;i<10;i++)
cout<<a[i]<<endl;
}
#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;
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.
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;
}
// sa se creeze o functie optimizata care ridica la o putere un numar
#include "stdafx.h"
#include <iostream>
using namespace std;
int optpow(int x, int n)
{
int r=1;
while(n)
if (n&1) r*=x,n--;
else x*=x, n/=2;
return r;
}
main()
{
cout<<optpow(3,4);
}
// Folosind dezvoltarea in scris Taylor pentru sin(x) , elaborati o functie care determina valoarea lui
sin(x) // intr-un ponct dat cu aproximatie inpusa.
#include "stdafx.h"
#include <iostream>
using namespace std;
#include<math.h>
#define PI 3.141592
#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;
}
// cu functii sa se determine diferite operatii cu elemnetele unui
vector
#include "stdafx.h"
#include <iostream>
using namespace std;
#include<math.h>
#include <stdio.h>
main( )
{
char *nume[6]={"sum","min","max","sump","sumc","sabs"};
int sum( ), min ( ),max( ),sumc( ),sump( ),sabs( );
static int (*pf[6])( )={sum,min,max,sump,sumc,sabs};
static int x[10]={1,2,3,4,5,6,7,8,9,10};
int n=10;
cout<<sum()<<endl;
cout<<sump()<<endl;
cout<<sumc()<<endl;
cout<<sabs()<<endl;
cout<<min()<<endl;
cout<<max()<<endl;
cout<<"program terminat";
}
int sum()
{static int x[10]={1,2,3,4,5,6,7,8,9,10};
int n=10;
int s=0,i;
for (i=0;i<n;i++) s+=x[i] ;
return s;
}
int min()
#include "stdafx.h"
#include <iostream>
using namespace std;
#include<math.h>
#include <stdio.h>
main ( )
{
int x,a,b,c;
int min ( ),max( );
cout<<"intoduceti a,b,c,x";
cin>>a>>b>>c>>x;
if (x>0) cout <<"valoarea functiei este:",min();
else
cout<<" valoarea functeiei este:",max();
}
int min ()
{int x,a,b,c;
if (a>b)
if(b>c) return c;
else return b;
else
if (a>c) return c;
else return a;
}
max ()
{int x,a,b,c;
if (a<b)
if (b<c) return c;
else return b;
else
if (a<c) return c;
}
#include "stdafx.h"
#include<iostream>
using namespace std;
#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);
}
#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;
int main()
{
USHORT lengthOfYard;
USHORT widthOfYard;
USHORT areaOfYard;
areaOfYard= FindArea(lengthOfYard,widthOfYard);
void myFunction()
{
int y = 10;
//Y VARIABILA LOCALA
cout << "x from myFunction: " << x << "\n";
cout << "y from myFunction: " << y << "\n\n";
}
int main()
{
int x = 5;
cout << "\nIn main x is: " << x;
myFunc();
void myFunc()
{
int x = 8;
cout << "\nIn myFunc, local x: " << x << endl;
{
cout << "\nIn block in myFunc, x is: " << x;
int x = 9;
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;
}
cout << "Swap. Before swap, x: " << x << " y: " << y << "\n";
temp = x;
x = y;
y = temp;
cout << "Swap. After swap, x: " << x << " y: " << y << "\n";
int main()
{
int result = 0;
int input;
result = Doubler(input);
return 0;
}
int main()
{
int length = 100;
int width = 50;
int height = 2;
int area;
area = AreaCube(length);
cout << "Third time area equals: " << area << "\n";
return 0;
}
int main()
{
int myInt = 6500;
long myLong = 65000;
float myFloat = 6.5F;
double myDouble = 6.5e20;
int doubledInt;
long doubledLong;
float doubledFloat;
double doubledDouble;
doubledInt = Double(myInt);
doubledLong = Double(myLong);
doubledFloat = Double(myFloat);
doubledDouble = Double(myDouble);
return 0;
}
int main()
{
int target;
target = Double(target);
cout << "Target: " << target << endl;
target = Double(target);
cout << "Target: " << target << endl;
target = Double(target);
cout << "Target: " << target << endl;
return 0;
}
int main()
{
int n, answer;
cout << "Enter number to find: ";
cin >> n;
answer = fib(n);
cout << answer << " is the " << n << "th Fibonacci number\n";
return 0;
}
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));
}
}
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.
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:
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";
myAge = 9;
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;
}
cout << "myAge:\t" << myAge << "\tyourAge:\t" << yourAge <<
"\n";
cout << "&myAge:\t" << &myAge << "\t&yourAge:\t" << &yourAge
<<"\n";
cout << "myAge:\t" << myAge << "\tyourAge:\t" << yourAge <<
"\n";
cout << "&myAge:\t" << &myAge << "\t&yourAge:\t" << &yourAge
<<"\n";
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;
return 0;
}
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;
}
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;
}
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;
int main()
{
USHORT number, squared, cubed;
short error;
if (!error)
{
cout << "number: " << number << "\n";
cout << "square: " << squared << "\n";
cout << "cubed: " << cubed << "\n";
}
else
cout << "Error encountered!!\n";
return 0;
}
int main()
{
USHORT number, squared, cubed;
ERR_CODE result;
if (result == SUCCESS)
{
cout << "number: " << number << "\n";
cout << "square: " << squared << "\n";
cout << "cubed: " << cubed << "\n";
}
else
cout << "Error encountered!!\n";
return 0;
}
int main() {
int a = 5, b = 6;
return 0;
}
// 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;
int main() {
int n = 15;
return 0;
}
// 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;
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;
}
// Exercitiul 6.1.3.txt
// Acest program realizeaza sortarea unui vector prin intermediul
poiterilor
#include "stdafx.h"
#include <iostream>
using namespace std;
int a[10];
int main () {
int i;
cout << "Here are all the array elements, sorted:" << endl;
for (i = 0; i < 10; i++)
cout << a[i] << " ";
return 0;
}
low = i;
for (j = i + 1; j < n; j++)
if (a[j] < a[low])
low = j;
// 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 main() {
int i;
zero_out_array(a, 10);
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;
int main() {
int *p;
zero_out_array(a, 10);
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;
int a[10];
int b[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int main() {
int *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.
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.
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:
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.
12 13
10 10 11
11
8
8 8 8 8
12 13
8 11 11 12
f=11
n+1, m=0
Ack(m,n)= Ack(m-1, 1), n=0
Ack(m-1, Ack(m, n-1)), altfel
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.
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
#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;
}
Nod* v;
int n;
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.
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
2 3 4 5
3 4 5 6
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
struct Nod
{
int info;
Nod* adr_urm;
};
Nod* v, *sf;
int n;
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
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
int v[100],n,nr;
int a[10],n;
int a[100],n,k;
char a,b,c;
int n;
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.
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 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 CB, 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
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
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];
}
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
#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
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).
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;
#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.
Prezentare generala
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 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 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
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
2) Adaugare la dreapta
3) Adaugare la stanga
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.
struct Nod
{ Nod *as,*ad;
int nr;
};
Nod *b,*s,*c;
int n,m,i;
void Listare(Nod*& b)
{ Nod* d=b;
while(d)
{ cout<<d->nr<<endl;
d=d->ad;
}
}
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
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
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
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.
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
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]<<" ";
}
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);
}
#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;
}
}
#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();
}
}
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();
}
}
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;
}
}
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
#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;
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.
Se consideră un graf neorientat, conex cu N noduri. Graful este dat prin matricea costurilor A.
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.
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.
S 1 0 0 0 0 0
T 0 0 1 0 0
1
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+>18D(2)=18.
D(3)+A(3,4)=13+14=27>25D(3)=13.
D(3)+A(3,5)=13+>15D(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+>18D(2)=18.
D(5)+A(5,4)=15+5=20D(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>20D(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:
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;
}
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
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();
}
=>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;
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
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.
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).
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
8
7
3 4 6
Un graf G este conex , daca oricare ar fi doua varfuri ale sale ,exista un lant care le leaga.
Definitie:
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
int S[50],A[50][50],n,I,k;
CitireN("graf.txt",A,n);
k=1;
for (I=1;I<=n;I++)
if (S[I]==0)
{
cout<<"componenta "<<k<<endl;
df_r(I);
195
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,
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;
196
}
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;
197
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;
198
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";
}
199
Flux intr-o retea de transport
200
struct Nod
{
int nd;
Nod* adr_urm;
};
201
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.
//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 >
202
int A[50][50],S[50],n,i,suma,gasit;
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.
203
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:
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.
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 !
204
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.
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);
3 2
5 2
205
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)
1
4
2 3
5
206
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 P1Xk şi Q1Xk. Î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.
207
//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 main( )
{
cost=0;
Citire_cost("graf.txt",A,n);
cout<<"nodul de pornire";
cin>>v;
for (i=1;i<=n;i++)
208
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
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.
Definitie. Un graf orientat este arbore daca nu este conex si nu admite cicluri.
Exemple:
209
1. Graful anterior nu este arbore pentru ca admite un ciclu.
2.
Definitie. Un graf orentat g=(x,) admite o radacina vx daca pentru orice xx-(v) exista un drum
(atnete, nu lant) de la v la x.
Exemple:
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.
210
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.
211
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.
//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;
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)
212
{
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";
}
}
- 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]
213
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 !
035003 417
123456789
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.
214
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.
215
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{kk{t[1]=t[2],…t[i-1],pt[i],pt[i+1]…pt[n-1]}}
- 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.
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.
216
//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
217
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.
218
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.
219
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.
st 2 4 5 0 0 0 0
1 2 3 4 5 6 7
dr 3 0 6 0 7 0 0
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.
Aceasta a mai fost prezentata in cazul arborilor neorientati. Mentionam doar faptul ca aceasta
reprezentare este neconvenabila in majoritatea aplicatiilor.
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.
220
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.
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
221
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;
}
222
}
}
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.
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:
223
2. CAUTAREA
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.
4. STERGEREA
Dupa stergerea unui nod care are o anumita cheie, arborele ramas trebuie sa fie de cautare.
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.
224
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:
225
Vezi procedura STERG. In situatia in care nodul care urmeaza a fi sters subordoneaza doi arbori,se
apeleaza procedura CMMD.
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;
226
{
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;
}
}
{
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 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;
}
227
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');
}
228
APLICATII
PROGRAMAREA PE OBIECTE
ASPECTE INTRODUCTIVE
Notiunea de structura
Abordarea orientată pe obiecte (AOO)
căciula studentului
o fereastră deschisă pe un calculator
un triunghi desenat pe hîrtie
Exemple de clase :
căciulă
fereastră
triunghi
229
polimorfism: aceeaşi operaţie (cu acelaşi nume) poate să aibă
comportament diferit în clase diferite
Exemple: a muta
o căciulă
o fereastră
un triunghi
230
Existenţa unor operaţii (metode) diferite, cu acelaşi nume, dar cu
comportament diferit, se numeşte polimorfism. Utilizatorul nu trebuie
să se preocupe care anume operaţie este apelată, întrucît compilatorul
va face această identificare, în funcţie de argumentele metodei apelate.
Astfel, a muta o Căciulă este diferit de a muta o Fereastră pe ecran,
sau de a muta un Triunghi pe hîrtie, de aceea nu poate exista confuzie:
în funcţie de ce anume trebuie mutat, operaţia îşi va cunoaşte clasa,
deci şi implementarea.
C++ a crescut rolul structurii standard din C la acela al unui mod mai subtil, de
specificare a unei clase. De fapt, diferenţa imediat vizibilă dintre o structură şi o clasă este
aceea că implicit toţi membrii unei structuri sînt publici pe cînd cei ai unei clase sînt implicit
privaţi. În celelalte privinţe, structurile şi clasele sînt similare. Aceasta înseamnă că în C++ o
structură defineşte de asemenea un tip special de clasă
Deoarece o structură (declarată cu cuvîntul cheie struct) în C++ defineşte un tip de clasă,
obiectele de acel tip pot fi declarate folosind doar numele generic al structurii, fără a mai folosi
cuvîntul cheie struct, aşa cum trebuie făcut în C (dar nu este o eroare dacă se precedă declaraţia
cu struct).
//Sa se defineasca o structura
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <string.h>
// declararea structurii
struct sir_exemplu{
void face_sir(char *); // implicit va fi sectiune public
void arata_sir();
private: // iar sectiunea privata trebuie declarata explicit
char sir[80];
};
231
// urmeaza definirile functiilor
void sir_exemplu::face_sir(char *s)
{
if (! *s) *sir ='\n'; // initializare sir
else strcat(sir, s);
}
void sir_exemplu::arata_sir()
{
cout << sir << "\n";
}
Notiunea de uniune
Uniuni şi clase
Uniuni anonime
În C++ există un tip special de union numit uniune anonimă. Aceasta nu conţine un nume de
tip şi nici o variabilă nu poate fi declarată ca fiind de acel tip de uniune. În schimb, ea comunică
compilatorului că variabilele membre ale uniunii vor împărţi aceeaşi locaţie. Dar variabilele în
sine pot if utilizate direct, fără sintaxa cu operator punct.
Mai mult, chiar dacă ele sînt definite într-o declaraţie union, ele sînt la acelaşi nivel al
domeniului de existenţă ca şi oricare alte variabile locale din acelaşi bloc. Membrii unei uniuni
anonime nu pot de altfel să aibă acelaşi nume cu al nici unui alt identificator cunoscut în
domeniul curent. Aceasta înseamnă că numele membrilor unei uniuni anonime nu trebuie să
intre în conflict cu alţi identificatori cunoscuţi din domeniul uniunii. Toate restricţiile pentru o
union se aplică şi celor anonime, cu următoarele completări :
elementele care pot fi conţinute într-o uniune anonimă trebuie să fie de tip date (nu
sînt permise funcţii membre)
uniunile anonime nu pot conţine elemente de tip private sau protected
uniunile globale anonime trebuie să fie specificate ca fiind de tip static.
#include "stdafx.h"
#include <iostream>
232
using namespace std;
#include <string.h>
main()
{
// urmeaza definirea uniunii anonime
union {
long l;
double d;
char s[10];
};
// accesul la membrii uniunii anonime este direct
l=150000;
cout << l << endl;
d=123.456;
cout << d <<endl;
strcpy(s, "abcdefghij");
cout << s << endl;
return 0;
}
//sa se creeze o uniune in care sa se puna in evidenta urmatoarele:
//• nu poate mosteni nici un alt tip de clasa
//• nu poate avea functii virtuale membre (vom vedea mai departe ce
înseamna functii virtuale)
//• nu poate avea ca membre variabile de tip static
//• nu poate avea ca membru nici un obiect care are supraîncarcat
operatorul =
//• nu poate avea ca membri obiecte care contin functii constructor
sau destructor
#include "stdafx.h"
#include <iostream>
using namespace std;
// declararea union
union schimbare_octeti {
void schimba();
void pune_octeti(unsigned );
void arata_cuvint();
unsigned u;
unsigned char c[2];
};
233
main()
{
schimbare_octeti sch;
sch.pune_octeti(34567);
sch.schimba();
sch.arata_cuvint();
return 0;
}
Clasele
Clasele sînt create utilizîndu-se cuvîntul cheie class. O declarare a unei clase defineşte
un nou tip care uneşte cod şi date. Acest nou tip este apoi folosit pentru a declara obiecte din
acea clasă. De aceea, o clasă este o abstractizare logică, dar un obiect are o existenţă fizică.
Altfel spus, un obiect este un exemplar (o instanţă) al unei clase.
O declarare de classă este similară sintactic cu cea a unei structuri. În capitolul
precedent a fost prezentată (simplificat) această declarare. Iată forma generală completă
a unei declaraţii de clasă care nu este un descendent al vreunei alte clase :
class nume_clasa {
date si functii particulare (fara specificator de acces, implicit)
specificator_de_acces:
date si functii
specificator_de_acces:
date si functii
...
specificator_de_acces:
date si functii
} lista de obiecte;
234
accesibilă global, pentru a obţine timpi de rulare mai mici sau chiar economie de
memorie). Cînd o variabilă este public, ea poate fi accesată direct de oricare secţiune a
programului. Sintaxa pentru accesul la o variabilă membră de tipul public este aceeaşi
ca pentru apelarea unei funcţii.
În rezumat : în C++ class creează un nou tip de date care pot fi
folosite pentru a construi obiecte de acel tip. De aceea, un obiect este o
instanţiere (un exemplar) a unei clase exact în acelaşi fel în care altă
variabilă este de exemplu un exemplar al tipului de date int. Altfel spus, o
clasă este o abstractizare logică, iar un obiect este real, clasa constituie
modelul după care se generează obiecte concrete (care există în memoria
calculatorului).
class nume_clasa {
date si functii private
public:
date si functii publice
} lista de obiecte;
Functii prietene
Este posibil să permitem unei funcţii care nu este membru să aibă acces la membrii particulari
ai clasei folosind cuvîntul cheie friend (prieten). O funcţie friend are acces la membrii private
şi protected ai clasei căreia îi este prietenă. Pentru a declara o funcţie friend, trebuie inclus
prototipul ei în acea clasă, precedat de cuvîntul cheie friend, există condiţii cînd funcţiile
prietene îşi dovedesc din plin utilitatea :
la supraîncărcarea anumitor tipuri de operatori (se va vedea mai încolo)
la crearea anumitor tipuri de operatori de intrare/ieşire
în unele cazuri, două sau mai multe clase pot conţine membri care sînt corelaţi cu
alte secţiuni ale programului.
Pentru funcţiile friend se aplică următoarele restricţii :
235
O clasă derivată nu poate moşteni funcţii friend;
o funcţie friend nu poate avea un specificator de clasă de memorare, adică nu
poate fi declarată static sau extern.
Clase prietene
Chiar şi clasele pot fi declarate friend una pentru alta. În această situaţie, clasa friend
are acces la numele private definite în cadrul celeilalte. Aceste nume pot cuprinde nume de
tipuri şi enumerări de date. Trebuie reţinut că o clasă friend are acces doar la numele definite în
interiorul celeilalte. Ea nu moşteneşte cealaltă clasă, deci membrii primei clase nu devin
membri ai clasei friend.
main(){
clasa_exemplu c;
c.furniz_ab(1,2);
cout << suma(c);
return 0;
}
// declarari de clase
class C2; // vezi mai jos
class C1 {
int stare; // valorile IN_USE daca este pe ecran,
// IDLE daca nu e
// …
236
public:
void setare_stare(int );
int idle(C2 ); // nu mai este friend ci pur si
// simplu membru al clasei C1 de aceea nu mai
// trebuie C1 in lista de parametri
};
class C2{
int stare; // IN_USE daca e pe ecran, IDLE daca nu e
// …
public:
void setare_stare(int );
friend int C1::idle(C2 ); //diferenta e ca apare C1::
// (deci se marcheaza apartenenta la C1)
};
// programul principal
main()
{
C1 x;
C2 y;
x.setare_stare(IDLE);
y.setare_stare(IDLE); // initial ambele sint IDLE
sir.face_sir(""); // initializare
sir.face_sir("Acesta"); // construim
237
sir.face_sir("este"); // un sir mai lung in etape
sir.face_sir("exemplu.");
sir.arata_sir(); // si il afisam
return 0;
}
gheorghe.pune_nume("Gheorghe Popescu");
gheorghe.pune_salar(860000); // i se adauga salariul pe
// luna curenta
gheorghe.scoate_nume(nume); // in nume va fi transferat
// numele
cout << nume << " are atitia lei ";
cout << gheorghe.furnizeaza_salar() << "pe luna.\n";
238
return 0;
}
//accesul la date publice se face direct in orice sectiune a
programului
#include "stdafx.h"
#include <iostream>
using namespace std;
class clasa_exemplu{
public:
int i,j,k; //acestea vor fi accesibile intregului program
};
main()
{
clasa_exemplu a,b; // se definesc doua obiecte de tipul
// clasa_exemplu
a.i=100;
a.j=4; // se lucreaza la fel ca si cu oricare
a.k=a.i*a.j; // variabila
b.i=a.j;
b.k=11; // a.k si b.k sint evident diferite
cout << a.k << " " <<b.k;
return 0;
}
Functii inline
O importantă caracteristică în C++, posibilitatea de a utiliza funcţii inline, eset
adeseori asociată cu folosirea claselor. În C++ pot fi create funcţii scurte care nu sînt apelate
efectiv ci codul respectivelor funcţii este inserat la fiecare folosire a acestora. Aceasta seamănă
cu utilizarea macro-urilor. Pentru a determina această modalitate de lucru, definirea funcţiei
respective trebuie precedată de cuvîntul-cheie inline.
Funcţiile inline sînt utilizate din motive de eficienţă. Astfel, pentru clase este adeseori necesar
să se solicite executarea frecventă a funcţiilor de interfaţă, care asigură accesul la datele private.
Prin utilizarea funcţiilor inline, eficienţa creşte prin aceea că astfel este înlocuit mecanismul
relativ complex al apelului şi transmiterii parametrilor (prin folosirea stivei şi salvarea
regiştrilor), prin folosirea directă a codului executabil a funcţiilor, fără să se mai folosească acel
mecanism. Bineînţeles prin acest procedeu codul executabil creşte în dimensiuni, de aceea se
recomandă utilizarea funcţiilor inline doar pentru coduri foarte scurte (puţine linii-sursă). Mai
mult decît atît, se recomandă alegerea acelor funcţii care au un impact puternic asupra
îmbunătăţirii performanţelor programului.
Asemenea specificatorului register, inline este pentru compilator o solicitare, nu o
comandă. Acesta poate chiar să o ignore. De asemenea, unele compilatoare nu pot insera inline
orice funcţie. De exemplu nu poate fi inline o funcţie recursivă (uşor de înţeles de ce).
Funcţiile inline pot fi membre ale unei clase.
Este posibilă definirea funcţiilor inline şi direct într-o declarare de clasă. Cînd o funcţie este
definită într-o declarare a unei clase, ea este automat transformată într-o funcţie inline, dacă e
posibil (dacă permite compilatorul). Nu este necesară declararea cu cuvîntul cheie inline (dar
bineînţeles nu constituie o greşeală).
// Sa se foloseasca o functie inline(codul respectivelor funcţii este
inserat la fiecare folosire a acestora)
239
#include "stdafx.h"
#include <iostream>
using namespace std;
main()
{
cout << max(100,200);
cout << " " << max (300, 299);
return 0;
}
class ordine{
public:
int cine;
ordine(int );
~ordine();
} glob_ob1(10), glob_ob2(20); // doua obiecte globale
ordine::ordine(int valinit)
{
cout << "Initializare " << valinit << "\n";
cine=valinit;
}
ordine::~ordine()
{
cout << "Distrugere " << cine << "\n";
}
main()
{
ordine local_ob1(30); // obiect local
return 0;
}
#define IN_BIBLIO 1
#define IMPRUMUTAT 0
class carte{
240
char autor[40];
char titlu[40];
int stare;
public:
carte(char *, char *, int );
int furniz_stare() {return stare;}
void pozit_stare(int s) {stare=s;}
void arata();
};
// constructorul initializeaza autor, titlu, stare
// transmisi ca parametri
carte::carte(char *aut, char *tit, int s)
{
strcpy(autor, aut);
strcpy(titlu, tit);
stare=s;
}
void carte::arata()
{
cout << titlu << " de " << autor <<" este ";
if (stare== IN_BIBLIO) cout << "aici.\n";
else cout << "imprumutata.\n";
}
main()
{
carte carte1("Cartarescu","Orbitor",IMPRUMUTAT);
carte carte2("Dinescu", "Democratia naturii", IN_BIBLIO);
carte1.arata();
carte2.arata();
return 0;
}
Membrii de tip static ai claselor
Membrii de tip static ai claselor
Atît funcţiile membre cît şi datele membre ale unei clase pot fi declarate static. În
continuare, să vedem ce înseamnă aceasta pentru fiecare tip de membru.
O dată care este precedată de cuvîntul static va exista doar într-un singur exemplar (o
singură copie) şi va fi folosită de toate obiectele de acea clasă. Spre deosebire de variabilele
membre obişnuite, nu sînt create copii individuale ale variabilelor membre static, pentru fiecare
obiect. Nu are importanţă cîte obiecte de acea clasă sînt create, va exista doar o singură copie a
membrilor de tip static. Cînd este creat primul obiect de acel tip, toate variabilele de tip static
sînt automat iniţializate cu zero.
În cadrul unei clase, declararea unei variabile static nu alocă memorie pentru aceasta.
Din acest motiv, trebuie dată a definire globală pentru membrii de tip static, în afara clasei,
folosind specificatorul de domeniu, pentru a preciza clasa de apartenenţă. Doar astfel se asigură
existenţa fizică a variabilei, prin alocarea de memorie pentru aceasta (este şi normal, declararea
clasei nu este altceva decît definirea unei structuri abstracte, a unui model după care pot fi
create obiecte; din acest motiv, variabilele statice nu pot fi alocate prin simpla includere într-un
model abstract). O variabilă membră de tip static există înainte de a fi creat orice obiect din
241
acea clasă. Mai mult, dacă respectiva variabilă este public şi întrucît există înainte de crearea
unui obiect din clasa în a cărei declarare apare variabila ca membră, aceasta poate dobîndi
valoare (care nu va fi modificată de crearea vreunui obiect din acea clasă) şi poate fi utilizată în
domeniul său de valabilitate, oricînd. Trebuie reţinut modul de acces la variabilele statice,
atunci cînd sînt accesate independent de obiecte: prin folosirea numelui clasei, urmat de
operatorul de rezoluţie şi apoi numele vaiabilei statice.
Uzual, variabilele membre statice sînt folosite la controlul accesului la unele resurse
comune. Fiecare obiect va putea să controleze valoarea variabilei statice membre pentru a
verifica posibilitatea accesului, deoarece există un singur exemplar al acestei variabile, care
poate fi văzut de toate instanţele clasei şi care va juca rolul unui semafor.
Funcţii membre statice
Şi funcţiile membre pot fi declarate static. Există mai multe restricţii relativ la funcţiile
astfel declarate :
pot să aibă acces doar la alţi membri de tip static ai clasei (şi bineînţeles la funcţiile
şi datele globale);
nu pot avea un pointer de tip this (se va vedea mai departe ce înseamnă acesta);
nu pot coexista versiuni statice şi ne-statice ale aceleiaşi funcţii
De fapt, funcţiile membre de tip static au o arie de aplicatibilitate destul de limitată. O
utilizare potrivită a acestora este iniţializarea datelor private de tip static, înainte de
crearea vreunui obiect al clasei respective.
Operatorul de specificare a domeniului
//Cînd este creat primul obiect de acel tip, toate variabilele de tip
static sînt automat iniţializate cu zero.
//În cadrul unei clase, declararea unei variabile static nu
alocă memorie pentru aceasta. Din acest motiv, trebuie dată a
definire globală pentru membrii de tip static, în afara clasei,
folosind
//specificatorul de domeniu, pentru a preciza clasa de
apartenenţă.
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
class exemplu_static{
static int a; // aici e o variabila membra de tip static
int b; // aceasta nu e de tip static
public:
void seteaza(int i, int j) {a=i; b=j; }
void arata();
};
242
{
cout << "Acesta este a static: " << a;
cout << "\nAcesta este b ne-static: " << b;
cout << "\n";
}
main()
{
exemplu_static ob1, ob2; // doua obiecte de tipul clasei
// exemplu_static
ob1.seteaza(1,2); // a va fi 1, b va fi 2
ob1.arata(); // sa vedem daca e asa
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
class comun{
public:
static int a; // static si public totodata
};
main()
{
// initializam variabila statica inainte de crearea
// vreunui obiect folosind operatorul ::
comun::a=789;
cout << "Valoarea initiala a lui a: " << comun::a <<"\n";
comun c1; // abia acum se creaza un obiect de tip comun
cout << "Valoarea lui a din c1: " << c1.a;
return 0;
}
//Exemplul următor ilustrează cum poate fi controlat accesul la o
astfel de resursă comună (care
//poate fi un fişier, un buffer partajat etc.):
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
243
class semafor{
static int resursa;
public:
int ocupa_resursa();
void elibereaza_resursa() {resursa=0; }
};
main()
{
semafor s1, s2; // doua obiecte de tip semafor
if(s1.ocupa_resursa())
cout << "Obiectul 1 a ocupat resursa.\n";
if(!s2.ocupa_resursa())
cout << "Obiectul 2 nu are acces la resursa.\n";
s1.elibereaza_resursa(); // eliberare resursa
if(s2.ocupa_resursa())
cout << "Obiectul 2 poate acum folosi resursa.\n";
return 0;
}
//Se observă că accesul la funcţia statică ocupa_resursa()
//este permis fie independent de vreun obiect, utilizînd numele
clasei şi operatorul de specificare
//a domeniului (operatorul de rezoluţie) fie în legătură
//cu un obiect (operatorul de apartenenţă cu punct).
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
class semafor{
static int resursa;
public:
static int ocupa_resursa();
void elibereaza_resursa() {resursa=0; }
};
244
main()
{
semafor s1, s2; // doua obiecte de tip semafor
// in plus fata de programul precedent, ocupa_resursa()
// poate fi apelat independent de orice obiect
if(semafor::ocupa_resursa())
cout << "Obiectul 1 a ocupat resursa.\n";
if(!semafor::ocupa_resursa())
cout << "Obiectul 2 nu are acces la resursa.\n";
s1.elibereaza_resursa(); // eliberare resursa
if(s2.ocupa_resursa()) // se poate folosi si apelul
// cu obiect
cout << "Obiectul 2 poate acum folosi resursa.\n";
return 0;
}
Obiectele pot fi pasate către funcţii exact ca oricare alt tip de variabilă (de altfel,
această posibilitate a fost folosită la un exemplu anterior, care folosea o funcţie friend pentru
controlul accesului la o resursă comună). Obiectele sînt pasate funcţiilor prin utilizarea
mecanismului standard de apelare prin valoare, adică prin copiere. Aceasta ar implica de fapt
crearea unui alt obiect. În aceste circumstanţe, se pune întrebarea dacă la crearea acestei copii
mai este apelat constructorul, respectiv, dacă această copie este distrusă apoi cu destructorul
clasei. Răspunsul la această întrebare este interesant şi uşor de justificat : constructorul nu este
apelat la realizarea copiei pentru pasarea către funcţie, deoarece astfel valorile care dau
atributele obiectului (deci valorile variabilelor membre) ar fi iniţializate, iar noi dorim să
transmitem spre funcţia apelantă chiar starea curentă a obiectului. În schimb destructorul este
executat la încheierea funcţiei, întrucît copia folosită nu mai e necesară
Cînd un obiect este returnat de o funcţie, este creat automat un obiect temporar, care conţine
valoarea returnată. Acesta este de fapt obiectul returnat. După ce valoarea a fost returnată, acest
obiect temporar este distrus. Această distrugere poate avea uneori efecte secundare neaşteptate.
245
Astfel, dacă obiectul care este returnat are un destructor care eliberează memorie alocată
dinamic, acea memorie va fi eliberată chiar dacă obiectul care primeşte valoarea returnată încă
o mai foloseşte. Apariţia acestei probleme poate fi prevenită prin supraîncărcarea operatorului
de atribuire şi definirea constructorului de copii, amintit anterior.
Atribuirea obiectelor
Presupunînd că două obiecte sînt de acelaşi tip, se poate realiza operaţia de atribuire
între acestea. Aceasta determină copierea datelor obiectelor din membrul drept în datele
obiectului din membrul stîng al operaţiei de atribuire.
main()
{
f();
// aici inca nu cunoastem clasa clas_local
return 0;
}
void f()
{
// aici definim clasa locala clas_local
class clas_local{
int i;
public:
void setare_i(int val) {i=val; }
int furniz_i() {return i; }
} ob; // si iata si un obiect de clasa respectiva
ob.setare_i(77);
cout << ob.furniz_i();
}
//Obiectele pot fi pasate către funcţii exact ca oricare
//alt tip de variabilă (de altfel, această posibilitate a
//fost folosită la un exemplu anterior, care folosea o
//funcţie friend pentru controlul accesului la o resursă
//comună). Obiectele sînt pasate funcţiilor prin utilizarea
mecanismului standard de apelare prin valoare, adică prin copiere.
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
class ex_apel{
int i;
public:
ex_apel(int );
~ex_apel();
void set_i(int val) {i=val;}
int ret_i() {return i;}
};
246
ex_apel::ex_apel(int init)
{
i=init;
cout << "Construirea pentru " << i << "\n";
}
ex_apel::~ex_apel()
{
cout << "Distrugerea pentru " << i << "\n";
}
void f(ex_apel );
main()
{
ex_apel ex1(1); // un obiect de tip ex_apel
f(ex1); // aici, apel de functie cu parametru obiect
cout << "Valoarea i din main : " << ex1.ret_i() << "\n";
return 0;
}
main()
{
retur_ob o; // se creaza un obiect
retur_ob f()
{
retur_ob interior; // obiect din functie
interior.set_i(1); // setam ca sa ne convingem ca e
// transmis in afara
return interior; // si returnam un obiect
}
//Sa se prezinte atribuirea a doua obiecte
247
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
class atribuire{
int i;
public:
void set_i(int val) {i=val; }
int ret_i() {return i; }
};
main()
{
atribuire a1, a2; // cele doua obiecte
int abs(int );
double abs(double );
long abs(long );
main()
{
cout << abs(-10) << "\n";
cout << abs(-22.5) << "\n";
cout << abs(-5L) << "\n";
return 0;
}
int abs(int i)
{
cout << "ABS pentru intregi\n";
return i<0 ? -i : i ;
}
double abs(double d)
{
cout << "ABS pentru double\n";
return d<0 ? -d : d ;
}
long abs(long l)
{
248
cout << "ABS pentru intregi lungi\n";
return l<0 ? -l : l ;
}
// functia constructor
stiva::stiva(){
virf_stiva=0;
cout << "In regula, stiva este initializata\n";
}
// functia destructor
stiva::~stiva()
{
cout << "In regula, stiva e distrusa\n";
}
int stiva::scoate(){
if (virf_stiva==0) {
cout << "Depasire inferioara\n";
return 0;
}
virf_stiva--;
return stiv[virf_stiva];
}
// Programul principal
main()
{
stiva stiv1, stiv2; // crearea a doua obiecte de tip stiva
249
stiv1.pune(1); // punem ceva in stive
stiv2.pune(2);
stiv1.pune(3);
stiv2.pune(4);
cout << stiv1.scoate() << " "; // acum scoatem din stive
si
cout << stiv1.scoate() << " "; // afisam
cout << stiv2.scoate() << " ";
cout << stiv2.scoate() << "\n ";
return 0; // gata
}
// Exercitiul 11.3.1.txt
// Acest program testeaza clasa Fraction prin initializarea unei
serii de
// fractii si afisarea fiecarei valori.
//
// Nota: Desi eu sugerez sa folositi combinatia copy-si-paste pentru
a genera
// o parte a acestui cod, folosirea unor matrice este probabil cea
mai buna
// modalitate de a economisi timpul. Dar aceasta abordare este
lasata pentru
// dumneavoastra, ca un alt exercitiu.
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den;
public:
void set(int n, int d) {num = n; den = d; normalize();}
int get_num() {return num;}
int get_den() {return den;}
private:
void normalize();
int gcf(int a, int b);
int lcm(int a, int b);
};
int main() {
250
f5.set(100, 25); // 100/25
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
#include "stdafx.h"
#using <mscorlib.dll>
#include <iostream>
using namespace std;
class Point {
private:
251
int x, y;
public:
void set(int new_x, int new_y);
int get_x();
int get_y();
};
int main() {
Point pt1, pt2;
pt1.set(10, 20);
cout << "pt1 is " << pt1.get_x();
cout << ", " << pt1.get_y() << endl;
pt2.set(-5, -25);
cout << "pt2 is " << pt2.get_x();
cout << ", " << pt2.get_y() << endl;
return 0;
}
int Point::get_x() {
return x;
}
int Point::get_y() {
return y;
}
// Exercitiul 11.1.1.txt
// Acest program declara o clasa Point ca in scriptul din point1.cpp,
// dar, in aceasta versiune, este stabilita o limita superioara
pentru
// valorile din membrii x si y.
#include "stdafx.h"
#using <mscorlib.dll>
#include <iostream>
using namespace std;
class Point {
private: // Data members (private)
int x, y;
public: // Member functions
void set(int new_x, int new_y);
int get_x();
int get_y();
};
int main() {
252
Point pt1, pt2;
pt1.set(10, 20);
cout << "pt1 is " << pt1.get_x();
cout << ", " << pt1.get_y() << endl;
pt2.set(-5, -25);
cout << "pt2 is " << pt2.get_x();
cout << ", " << pt2.get_y() << endl;
pt1.set(200, 500);
cout << "pt1 is " << pt1.get_x();
cout << ", " << pt1.get_y() << endl;
return 0;
}
int Point::get_x() {
return x;
}
int Point::get_y() {
return y;
}
//sa se scrie doua functii care seteaza punctul X si Punctul Y
diferite
#include "stdafx.h"
#using <mscorlib.dll>
#include <iostream>
using namespace std;
class Point {
private:
int x, y;
public:
void set(int new_x, int new_y);
int get_x();
int get_y();
void set_x(int new_x);
void set_y(int new_y);
};
int main() {
Point pt1, pt2;
pt1.set(10, 20);
cout << "pt1 is " << pt1.get_x();
253
cout << ", " << pt1.get_y() << endl;
pt2.set(-5, -25);
cout << "pt2 is " << pt2.get_x();
cout << ", " << pt2.get_y() << endl;
pt1.set_x(-50);
pt1.set_y(-10);
cout << "pt1 is " << pt1.get_x();
cout << ", " << pt1.get_y() << endl;
return 0;
}
int Point::get_x() {
return x;
}
int Point::get_y() {
return y;
}
// Sa se adune doua fractii cu POO
#include "stdafx.h"
#using <mscorlib.dll>
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den;
public:
void set(int n, int d)
{num = n; den = d; normalize();}
254
int get_num() {return num;}
int get_den() {return den;}
Fraction add(Fraction other);
Fraction mult(Fraction other);
private:
void normalize();
int gcf(int a, int b);
int lcm(int a, int b);
};
int main() {
Fraction fract1, fract2, fract3;
fract1.set(1, 2);
fract2.set(1, 3);
fract3 = fract1.add(fract2);
cout << "1/2 plus 1/3 = ";
cout << fract3.get_num() << "/" << fract3.get_den();
}
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
255
fract.set(num * quot1 + other.num * quot2, lcd);
return fract;
}
#using <mscorlib.dll>
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den;
public:
void set(int n, int d)
{num = n; den = d; normalize();}
int get_num() {return num;}
int get_den() {return den;}
Fraction add(Fraction other);
Fraction mult(Fraction other);
private:
void normalize();
int gcf(int a, int b);
int lcm(int a, int b);
};
int main() {
Fraction fract1, fract2, fract3;
int n, d;
fract3 = fract1.add(fract2);
void Fraction::normalize(){
256
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
#using <mscorlib.dll>
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den;
public:
void set(int n, int d)
257
{num = n; den = d; normalize();}
int get_num() {return num;}
int get_den() {return den;}
Fraction add(Fraction other);
Fraction mult(Fraction other);
private:
void normalize();
int gcf(int a, int b);
int lcm(int a, int b);
};
int main() {
Fraction fract1, fract2, fract3;
int n, d;
fract3 = fract1.mult(fract2);
cout << "fract1 * fract2 is: ";
cout << fract3.get_num() << "/" << fract3.get_den() << endl;
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
258
//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}
// Exercitiul 11.4.3.txt
// Acest program extinde clasa Point prezentata in capitolul 11
// prin includerea unei functii noi, Point::add.
#include<stdafx.h>
#include <iostream>
using namespace std;
class Point {
private:
int x, y;
public:
void set(int new_x, int new_y);
int get_x();
int get_y();
Point add(Point other);
};
int main() {
Point pt1, pt2, pt3;
pt1.set(10, 20);
cout << "pt1 is " << pt1.get_x();
cout << ", " << pt1.get_y() << endl;
pt2.set(-5, -25);
cout << "pt2 is " << pt2.get_x();
cout << ", " << pt2.get_y() << endl;
pt3 = pt1.add(pt2);
pt2.set(-5, -25);
cout << "pt3 is " << pt3.get_x();
cout << ", " << pt3.get_y() << endl;
return 0;
}
259
if (new_x < 0)
new_x *= -1;
if (new_y < 0)
new_y *= -1;
x = new_x;
y = new_y;
}
int Point::get_x() {
return x;
}
int Point::get_y() {
return y;
}
#include "stdafx.h"
// Exercitiul 11.4.4.txt
// Acest program include functiile sub (scadere) si div (impartire)
// pentru clasa Fraction.
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den;
public:
void set(int n, int d)
{num = n; den = d; normalize();}
int get_num() {return num;}
int get_den() {return den;}
Fraction add(Fraction other);
Fraction mult(Fraction other);
Fraction sub(Fraction other);
Fraction div(Fraction other);
private:
void normalize();
int gcf(int a, int b);
int lcm(int a, int b);
};
int main() {
Fraction fract1, fract2, fract3;
int n, d;
260
cout << "Enter numerator for first fraction: ";
cin >> n;
cout << "Enter denominator for first fraction: ";
cin >> d;
fract1.set(n, d);
cout << "Enter numerator for second fraction: ";
cin >> n;
cout << "Enter denominator for second fraction: ";
cin >> d;
fract2.set(n, d);
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}
261
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
return fract;
}
Se pot transmite parametri către funcţiile constructor. Aceştia sînt folosiţi mai ales
pentru iniţializarea unui obiect la creare. Pentru aceasta, trebuie pur şi simplu adăugaţi
parametri în modul în care acest lucru se realizează pentru orice funcţie. Iar parametrii transmişi
vor fi folosiţi pentru iniţilizarea obiectului.
Funcţiile constructor cu parametri sînt utile deoarece permit evitarea unui aple suplimentar
pentru iniţializarea valorilor unor variabile din obiecte.
Un caz special al funcţiilor constructor cu parametri este constituit de funcţiile
constructor cu un parametru. În acest caz, există o altă cale de a-i pasa acestuia o valoare
iniţială. În cazul cînd constructorul are un singur argument, se poate folosi pur şi simplu forma
de iniţializare "naturală". Compilatorul va atribui automat valoarea din dreapta semnului "=",
parametrului constructorului.
Despre execuţia constructorilor şi destructorilor
262
2. Funcţiile constructor pentru obiecte globale sînt executate înaintea lui main(). Constructorii
globali din acelaşi fişier sînt executaţi în rodinea în care au fost întîlniţi, de la stînga la dreapta
şi de sus în jos. E greu de depistat ordinea execuţiei constructorilor împrăştiaţi în mai multe
fişiere. Destructorii globali se execută în ordine inversă, după încheierea funcţiei main().
#include "stdafx.h"
#include <iostream>
using namespace std;
class Point {
private:
int x, y;
public: // Constructori
Point() {set(0,0);};
Point(int new_x, int new_y) {set(new_x, new_y);}
// functii membre
int main() {
Point pt1, pt2;
Point pt3(5, 10);
int Point::get_x() {
return x;
}
int Point::get_y() {
return y;
}
// Exercitiul 12.1.1.txt
// Aceasta versiune a lui point2.cpp raporteaza ce constructori vor
fi utilizati.
263
//sa se defineasca doi constructori ,unul pentru un mesaj altul cu
parametrii pentru alt mesaj
#include "stdafx.h"
#include <iostream>
using namespace std;
class Point {
private: // Data members (private)
int x, y;
public: // Constructors
Point()
{set(0,0); cout << "Using default constructor" << endl; }
int main() {
Point pt1, pt2;
Point pt3(5, 10);
int Point::get_x() {
return x;
}
int Point::get_y() {
return y;
}
// Exercitiul 12.1.2.txt
// Aceasta versiune a programului Point2 adauga constructorul
Point(int)
// (un constructor care preia un singur argument intreg).
264
#include "stdafx.h"
#include <iostream>
using namespace std;
class Point {
private: // Data members (private)
int x, y;
public: // Constructors
Point() {set(0, 0);}
Point(int new_x, int new_y) {set(new_x, new_y);}
int main() {
Point pt1(6); // THIS TESTS THE NEW CONSTRUCTOR
Point pt2;
Point pt3(5, 10);
int Point::get_x() {
return x;
}
int Point::get_y() {
return y;
}
//sa se defineasca constructori pentru clasa Fractie
#include "stdafx.h"
#include <iostream>
using namespace std;
265
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
int main() {
Fraction f1, f2;
Fraction f3(1, 2);
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
266
else
return gcf(b, a % b);
}
// Exercitiul 12.2.1.txt
// Aceasta versiune a clasei Fraction revizuieste constructorul
prestabilit
// astfel incat sa stabileasca direct valoarea membrilor de date num
si den.
//
// Apelarea functiei normalize nu este strict necesara, dar este
putin mai precaut,
// in particular, daca functia normalize va fi rescrisa de subclase
// (cum se va explca mai tarziu in acest capitol).
//
// Setarea directa a functiilor num si den este putin mai eficienta,
deoarece ocoleste
// ap
#include "stdafx.h"
elarea unei functii; totusi, aceasta este un foarte mica
imbunatatire.
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {num = 0; den = 0; normalize();} // <-- NEW VERSION
267
Fraction add(Fraction other);
Fraction mult(Fraction other);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
int main() {
Fraction f1, f2;
Fraction f3(1, 2);
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
268
Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
fract.normalize();
return fract;
}
// Exercitiul 12.2.2.txt
// Aceasta versiune a clasei Fraction adauga un constructor
Fraction(int),
// care creeaza o fractie de forma n/1.
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);} // NEW CONSTRUCTOR ADDED
int main() {
Fraction f1(6); // THIS TESTS THE NEW CONSTRUCTOR
Fraction f2;
Fraction f3(1, 2);
269
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
#include "stdafx.h"
270
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(Fraction const &src);
int main() {
Fraction f1(3, 4);
Fraction f2(f1);
Fraction f3 = f1.add(f2);
// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
271
// Factor out GCF from numerator and denominator.
// Exercitiul 12.3.1.txt
// Aceasta versiune a programului fract4.cpp rescrie un constructor
de copiere
// sub forma unei functii in linie.
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
272
Fraction(Fraction const &src) {num = src.num; den = src.den;}
int main() {
Fraction f1(3, 4);
Fraction f2(f1);
Fraction f3 = f1.add(f2);
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
273
}
// Exercitiul 12.3.2.txt
// Aceasta versiune a programului fract4.cpp revizuieste
constructorul de copiere
// astfel incat sa faca apel la functia set in loc sa stabileasca
direct valoarea
// membrilor de date num si den.
//
// Aceasta abordare isi pierde putin din eficienta fata de situatia
cand constructorul
// este setat ca o functie in linie. Cu toate acestea, el apeleaza
functia normalize,
// lucru care nu este neaparat necesar. (Cand copiati o fractie
existenta, puteti
// presupune ca valoarea sa a fost deja normalizata.)
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(Fraction const &src);
int main() {
274
Fraction f1(3, 4);
Fraction f2(f1);
Fraction f3 = f1.add(f2);
// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
275
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
fract.normalize();
return fract;
}
SUPRAINCARCAREA(DEFINIREA NOUA) A
OPERATORILOR
#include "stdafx.h"
#include <iostream>
using namespace std;
class Point {
private: // Data members (private)
int x, y;
public: // Constructors
Point() {};
Point(int new_x, int new_y) {set(new_x, new_y);}
Point(const Point &src) {set(src.x, src.y);}
// Operations
int main() {
276
return 0;
}
// Exercitiul 13.1.1.txt
// Aceasta versiune a programului point3.cpp indica de cate ori sunt
apelati
// constructorul predefinit si constructorul de copiere.
#include "stdafx.h"
#include <iostream>
using namespace std;
class Point {
private: // Data members (private)
int x, y;
public: // Constructors
Point()
{set(0, 0); cout << "Inside default constructor" << endl; } //
ALTERED CODE
// Operations
277
void set(int new_x, int new_y);
int get_x() const {return x;}
int get_y() const {return y;}
};
int main() {
return 0;
}
// Exercitiul 13.1.2.txt
// Acest program creeaza si testeaza operatii de inmultire (*) intre
// clasa Point si tipul de date int.
#include "stdafx.h"
#include <iostream>
using namespace std;
class Point {
private: // Data members (private)
int x, y;
public: // Constructors
Point() {};
Point(int new_x, int new_y) {set(new_x, new_y);}
Point(const Point &src) {set(src.x, src.y);}
// Operations
278
Point add(const Point &pt);
Point sub(const Point &pt);
Point operator+(const Point &pt) {return add(pt);}
Point operator-(const Point &pt) {return sub(pt);}
int main() {
return 0;
}
279
Point operator*(const int &n, const Point &pt) {
Point new_pt;
new_pt.set(pt.x * n, pt.y * n);
return new_pt;
}
//sa se defineasca operatori personalizati pentru
//lucrul cu fractiile
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(const Fraction &src);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
int main() {
Fraction f1(1, 2);
Fraction f2(1, 3);
Fraction f3 = f1 + f2;
// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS
280
// Handle cases involving 0
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
#include "stdafx.h"
281
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(const Fraction &src);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
int main() {
Fraction fraction_sum(0, 0);
Fraction fraction_new;
int numerator, denominator;
return 0;
}
// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS
282
// Handle cases involving 0
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
class Fraction {
private:
283
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
int main() {
Fraction f1(1, 2);
Fraction f2(1, 3);
Fraction f3 = f1 + f2 + 1;
// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
284
// Factor out GCF from numerator and denominator.
// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION
// Exercitiul 13.3.1.txt
// Acest exemplu revizuieste programul din exemplul 13.3 astfel incat
afiseaza
// iesirea din clasa Fraction in format (num, den).
#include "stdafx.h"
#include <iostream>
285
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
int main() {
Fraction f1(1, 2);
Fraction f2(1, 3);
Fraction f3 = f1 + f2 + 1;
// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
286
if (den < 0) {
num *= -1;
den *= -1;
}
// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION -- THIS IS THE REVISED FUNCTION
CODE
287
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
int main() {
Fraction f1(1, 2);
Fraction f2(1, 3);
return 0;
}
// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS
288
// Normalize: put fraction into a standard form, unique
// for each mathematically different value.
//
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
289
}
// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION
FUNCTII PRIETEN
// Exercitiul 13.3.3.txt
// Acest program adauga functia operator<< la clasa Point.
// Functia este declarata ca prieten al clasei.
#include "stdafx.h"
#include <iostream>
using namespace std;
class Point {
private: // Data members (private)
int x, y;
public: // Constructors
Point() {};
Point(int new_x, int new_y) {set(new_x, new_y);}
Point(const Point &src) {set(src.x, src.y);}
// Operations
int main() {
290
Point point3(-10, 25);
Point point4 = point1 + point2 + point3;
cout << "The point is " << point4 << endl; // TEST OPERATOR<<
FUNCT.
return 0;
}
Exact aşa cum pot fi definiţi pointeri către alte tipuri de variabile, pot exista şi
pointeri către obiecte. Când se doreşte acces la membrii unei clase cu ajutorul unui
pointer către un obiect, se foloseşte operatorul săgeată ( -> ) în locul operatorului
punct. Se poate atribui unui pointer adresa unui membru public al unui obiect şi apoi
să aveţi acces la acel membru folosind pointerul.
Se poate elimina orice nepotrivire folosind un modelator (adică o conversie de tip) dar
astfel se trece peste mecanismul de verificare a tipului din C++. În C++, se realizează
o verificare mai strictă a tipurilor decît în C (unde se poate atribui orice tip de valoare
oricărui pointer), atunci cînd sînt implicaţi pointeri.
Pointerul this
Cînd este apelată o funcţie membru, i se pasează automat un argument implicit
(care nu apare în lista de parametri), care este un pointer către obiectul care a generat
apelul (adică obiectul care a invocat funcţia : obiect.functie(...) ). Acest pointer este
numit this.
La membrii unei clase se poate dobîndi acces direct din cadrul unei funcţii membru,
fără nici un specificator de obiect sau de clasă.
291
Există două restricţii legate de this :
Funcţiile friend nu sînt membri ai clasei, deci nu le sînt pasaţi pointeri this.
Funcţiile membre de tip static nu au nici ele un pointer this.
C++ permite generarea unui tip special de pointeri care indică generic spre un
membru al unei clase, nu către un anumit exemplar al acelui membru dintr-un obiect.
Acest tip de pointer este numit pointer către un membru al clasei sau pe scurt pointer
la membru. Acesta nu e acelaşi lucru cu un pointer normal. Un astfel de pointer
asigură doar o poziţionare (un offset) într-un obiect din clasa membrului, unde poate
fi găsit acel membru. Deoarece pointerii la membri nu sînt chiar pointeri în înţelesul
pe care îl cunoaştem, nu li se pot aplica operatorii obişnuiţi în operarea cu pointeri
normali: . şi -> . Pentru a avea acces la membrul unei clase prin intremediul unui
pointer de acest tip, vor trebui folosiţi operatorii speciali pentru pointeri la membri: .*
şi ->* .
Referinţe
S-a văzut în precedentul capitol că atunci cînd un obiect este transmis unei funcţii ca
argument, se face automat o copie a acelui obiect, ba mai mult, cînd este realizată
acea copie, nici nu e apelat constructorul obişnuit al clasei (fiind realizată doar o copie
exactă, fără iniţializările şi celelalte operaţii conţinute în constructor). În schimb, la
terminarea funcţiei, este apelat destructorul copiei. Dacă nu se doreşte apelarea
292
destructorului, se poate realiza transmiterea obiectului prin referinţă. La acest gen de
apel, aşa cum ne şi aşteptăm, nu se face o copie a obiectului ci manipularea datelor are
loc chiar în obiectul transmis ca referinţă. Deci destructorul nu mai este apelat la
terminarea funcţiei.
Referinţe independente
Cea mai obişnuită utilizare pentru referinţe este pasarea argumentelor prin
referinţă şi obţinerea valorii returnate de funcţie. Totuşi, pot fi declarate şi referinţe ca
simple variabile. Acest tip de referinţă se numeşte referinţă independentă.
La crearea unei referinţe independente, tot ceea ce se creează este de fapt un al
doilea nume pentru o variabilă. Toate variabilele de tip referinţă independentă trebuie
iniţializate la creare.
Restricţii
O referinţă nu se poate referi la altă referinţă (adică nu poate fi obţinută adresa unei
referinţe).
Nu pot fi create matrice de referinţe.
Nu se poate crea un pointer spre o referinţă.
O referinţă nu se poate defini pentru un cîmp de biţi.
O variabilă de tip referinţă trebuie iniţializată la declarare, dar nu trebuie
iniţializată dacă este membru al unei clase, parametru de funcţie sau valoare
returnată.
Referinţele nule nu sînt permise.
Observaţie
cele două declaraţii sînt echivalente funcţional dar asocierea cu numele tipului reflectă
dorinţa programatorilor ca limbajul C++ să pună la dispoziţie un pointer distinct
pentru tip (tipul întreg, în cazul nostru). Dar sintaxa din C++nu presupune
distributivitatea operatorilor într-o listă de parametri. De aceea se pot uşor formula
declaraţii greşite. Astfel :
int* a,b;
creează un pointer de tip întreg, nu doi, aşa cum am fi dorit. Într-adevăr, în C++ ,
operatorii * sau & se referă doar la următoarea variabilă şi nu la tipul variabilelor,
deşi văzînd linia-sursă am fi tentaţi să credem că atît a cît şi b ar fi pointeri. Această
confuzie este frecventă chiar şi la programatorii buni, cînd nu sînt atenţi.
Din punctul de vedere al compilatorului, este indiferentă forma de scriere de
mai sus. Pentru evitarea confuziilor, se recomandă asocierea operatorilor de mai sus
totuşi cu variabilele.
293
Operatorii de alocare dinamică din C++
p_var=new tip;
...
delete p_var;
Aici, p_var este o variabilă de tip pointer care primeşte un pointer spre
memoria care este suficient de mare pentru a păstra un element de tipul tip.
Operatorul delete trebuie să fie folosit doar cu un pointer valid, alocat deja prin new.
Folosirea oricărui alt tip de pointer cu delete duce la un rezultat imprevizibil şi
aproape sigur determină probleme, chiar căderea sistemului.
Deşi new şi delete efectuează funcţii similare cu malloc() şi free(), ele
prezintă mai multe avantaje:
294
semnala eroare (deoarece ar trebui să iniţializeze un obiect care nu permite
iniţializarea). Prin folosirea delete [], funcţia destructor va fi apelată pentru fiecare
obiect al clasei.
#include "stdafx.h"
#include <iostream>
using namespace std;
int main() {
int sum = 0;
int n;
int *p;
return 0;
}
// Exercitiul 14.1.1.txt
// Acest program modifica scriptul new1.cpp pentru a utiliza un tip
double
// ca tip de baza pentru o matrice in loc de tipul int.
//se aloca memorie pentru elementele unei matrice cu elemete reale
#include "stdafx.h"
#include <iostream>
using namespace std;
int main() {
double sum = 0.0; // TYPE ALTERED TO DOUBLE HERE.
int n;
double *p; // TYPE OF *p ALTERED TO DOUBLE.
295
for (int i = 0; i < n; i++) {
cout << "Enter item #" << i << ": ";
cin >> p[i];
sum += p[i];
}
cout << "Here are the items: ";
for (int i = 0; i < n; i++)
cout << p[i] << ", ";
cout << endl;
cout << "The total is: " << sum << endl;
cout << "The average is: " << sum / n << endl;
return 0;
}
//sa se creeze un analizator lexical adica un program care
//sa imparta in cuvinte o fraza dandu-se un delimitator
//ex:3/4/5 =>
// 3
// 4
// 5
#include "stdafx.h"
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
class StringParser {
private:
int pos;
char *input_str;
char *delimiters;
public:
StringParser(char *inp, char *delim)
{input_str = inp; delimiters = delim; pos = 0; }
StringParser(char *inp)
{input_str = inp; delimiters = ","; pos = 0; }
char *get();
int get_int();
int more() {return input_str[pos] != '\0'; }
void reset() {pos = 0;}
};
int main() {
char input_str[100];
char *p;
while (parser.more()) {
p = parser.get(); // Get ptr to newly allocated string
cout << p << endl; // Print it
296
delete [] p; // Release string memory
}
return 0;
}
// ----------------------------------------------
// STRINGPARSER CLASS FUNCTIONS
char *StringParser::get() {
int j = 0;
char *new_str;
new_str = new char[100];
new_str[j++] = input_str[pos++];
new_str[j] = '\0';
return new_str;
}
int StringParser::get_int() {
char *p = get();
return atoi(p);
delete [] p;
}
// Exercitiul 14.2.1.txt
// Acest program modifica scrptul din exemplul 14.2 astfel incat sa
utilizeze
// functia membru get_int() (limitind intrarile la valori intregi)
in locul
// functiei get().
#include "stdafx.h"
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
class StringParser {
private:
int pos;
char *input_str;
char *delimiters;
public:
StringParser(char *inp, char *delim)
297
{input_str = inp; delimiters = delim; pos = 0; }
StringParser(char *inp)
{input_str = inp; delimiters = ","; pos = 0; }
char *get();
int get_int();
int more() {return input_str[pos] != '\0'; }
void reset() {pos = 0;}
};
int main() {
char input_str[100];
int n; // USE INTEGER RATHER THAN CHAR* STRING
while (parser.more()) {
n = parser.get_int(); // GET AN INTEGER FROM NEXT SUBSTRING
cout << n << endl; // Print it
}
return 0;
}
// ----------------------------------------------
// STRINGPARSER CLASS FUNCTIONS
char *StringParser::get() {
int j = 0;
char *new_str;
new_str = new char[100];
new_str[j++] = input_str[pos++];
new_str[j] = '\0';
return new_str;
}
int StringParser::get_int() {
char *p = get();
return atoi(p);
delete [] p;
}
// Copierea unui subsir intr-un sir prin alocare dinamica
298
#include "stdafx.h"
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
class StringParser {
private:
int pos;
char *input_str;
char *delimiters;
public:
StringParser(char *inp, char *delim)
{input_str = inp; delimiters = delim; pos = 0; }
StringParser(char *inp)
{input_str = inp; delimiters = ","; pos = 0; }
int main() {
char input_str[100];
char substr[100]; // USES A STATIC STRING -- THIS SHOULD BE
LARGE
// ENOUGH TO CONTAIN ANY POSSIBLE
SUBSTRING.
while (parser.more()) {
parser.get(substr); // GET NEXT SUBSTRING INTO THE STRING
VAR.
cout << substr << endl; // Print it
}
return 0;
}
// ----------------------------------------------
// STRINGPARSER CLASS FUNCTIONS
299
while (input_str[pos] != '\0' &&
! strchr(delimiters, input_str[pos]))
dest[j++] = input_str[pos++];
dest[j] = '\0';
return dest;
}
#include <iostream>
#include <string.h>
using namespace std;
class String {
private:
char *ptr;
public:
String();
String(char *s);
~String();
int main() {
String a("STRING 1");
String b("STRING 2");
cout << "The value of a is: " << endl;
cout << a << endl;
cout << "The value of b is: " << endl;
cout << b << endl;
}
// ----------------------------------
// STRING CLASS FUNCTIONS
String::String() {
ptr = new char[1];
ptr[0] = '\0';
}
String::String(char *s) {
int n = strlen(s);
ptr = new char[n + 1];
300
strcpy(ptr, s);
}
String::~String() {
delete [] ptr;
}
// Exercitiul 15.1.1.txt
// Aceasta versiune a programului string1.cpp testeaza
// constructorul prestabilit String().
#include "stdafx.h"
#include <iostream>
#include <string.h>
using namespace std;
class String {
private:
char *ptr;
public:
String();
String(char *s);
~String();
int main() {
String a("STRING 1");
String b("STRING 2");
String c; // NEW OBJECT DECL.
cout << "The value of a is: " << endl;
cout << a << endl;
cout << "The value of b is: " << endl;
cout << b << endl;
// ----------------------------------
// STRING CLASS FUNCTIONS
String::String() {
ptr = new char[1];
ptr[0] = '\0';
}
String::String(char *s) {
int n = strlen(s);
ptr = new char[n + 1];
strcpy(ptr, s);
301
}
String::~String() {
delete [] ptr;
}
#include "stdafx.h"
#include <iostream>
#include <string.h>
using namespace std;
class String {
private:
char *ptr;
public:
String();
String(char *s);
String(const String &src);
~String();
int main() {
String a, b, c;
a = "I ";
b = "am ";
c = "so ";
String d = a + b + c + "very happy!\n";
cout << d;
return 0;
}
// ----------------------------------
// STRING CLASS FUNCTIONS
String::String() {
ptr = new char[1];
ptr[0] = '\0';
}
String::String(char *s) {
int n = strlen(s);
302
ptr = new char[n + 1];
strcpy(ptr, s);
}
String::~String() {
delete [] ptr;
}
strcpy(p1, ptr);
strcat(p1, s);
delete [] ptr;
ptr = p1;
}
// Exercitiul 15.2.1.txt
// Acest exemplu revizuieste programul string2.cpp astfel incat sa
suporte functia
// operator+ sub forma unei functii prieten globale.
#include "stdafx.h"
303
#include <iostream>
#include <string.h>
using namespace std;
class String {
private:
char *ptr;
public:
String();
String(char *s);
String(const String &src);
~String();
int main() {
String a, b, c;
a = "I ";
b = "am ";
c = "so ";
// ----------------------------------
// STRING CLASS FUNCTIONS
String::String() {
ptr = new char[1];
ptr[0] = '\0';
}
String::String(char *s) {
int n = strlen(s);
ptr = new char[n + 1];
strcpy(ptr, s);
}
304
ptr = new char[n + 1];
strcpy(ptr, src.ptr);
}
String::~String() {
delete [] ptr;
}
strcpy(p1, ptr);
strcat(p1, s);
delete [] ptr;
ptr = p1;
}
305
new_str.cat(str);
return new_str;
}
// Exercitiul 15.2.2.txt
// Acest program modifica declaratiile din string2.cpp
// astfel incat fiecare functie care are un argument de tipul
// char* sa foloseasca un argument de tipul const char*.
#include "stdafx.h"
#include <iostream>
#include <string.h>
using namespace std;
class String {
private:
char *ptr;
public:
String();
String(const char *s); // ALTERED LINE
String(const String &src);
~String();
int main() {
String a, b, c;
a = "I ";
b = "am ";
c = "so ";
String d = a + b + c + "very happy!\n";
cout << d;
return 0;
}
// ----------------------------------
// STRING CLASS FUNCTIONS
String::String() {
ptr = new char[1];
ptr[0] = '\0';
}
306
strcpy(ptr, s);
}
String::~String() {
delete [] ptr;
}
strcpy(p1, ptr);
strcat(p1, s);
delete [] ptr;
ptr = p1;
}
MOSTENIRE-IN PROGRAMAREA PE OBIECT VISUAL
C++.NET
Moştenirea
Moştenirea este una dintre caracteristicile cele mai importante ale unui limbaj
de programare OO. În C++ moştenirea este realizată prin acceptarea ca o clasă să
încorporeze în declararea sa altă clasă. Moştenirea permite construirea unei ierarhii
307
de clase, trecerea de la cele mai generale la cele mai particulare. Procesul acesta
implică pentru început definirea clasei de bază, care stabileşte calităţile comune ale
tuturor obiectelor ce vor deriva de aici. Clasa de bază reprezintă cea mai generală
descriere. Clasele derivate (obţinute prin moştenire) din clasa de bază se numesc chiar
clase derivate. O clasă derivată include toate caracteristicile clasei de bază şi în plus
calităţi proprii acelei clase.
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
int main() {
FloatFraction fract1;
fract1.set(1, 2);
cout << "Value of 1/2 is " << fract1.get_float() << endl;
308
fract1.set(3, 5);
cout << "Value of 3/5 is " << fract1.get_float() << endl;
return 0;
}
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
309
fract.normalize();
return fract;
}
// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
310
public:
double get_float() {
return static_cast<double>(get_num())/get_den();}
};
int main() {
FloatFraction fract1;
fract1.set_float(0.5);
cout << "Value of 0.5 is " << fract1.get_float() << endl;
fract1.set_float(0.6);
cout << "Value of 0.6 is " << fract1.get_float() << endl;
return 0;
}
void FloatFraction::set_float(double x) {
int new_val = static_cast<int>(x * 100.0);
set(new_val, 100);
}
// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
311
num *= -1;
den *= -1;
}
#include "stdafx.h"
#include <iostream>
using namespace std;
312
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
double get_float() {
return static_cast<double>(get_num())/get_den();}
};
int main() {
FloatFraction fract1(0.5), fract2(0.6);
void FloatFraction::set_float(double x) {
int new_val = static_cast<int>(x * 100.0);
set(new_val, 100);
313
}
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
314
Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}
// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION
315
aleg calea spre fisier
open
4)Fisierul de imoprtat trebuie sa nu contina sectiunea main()
deci sa aiba continutul de mai jos:
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
316
// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
317
Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}
// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION
#include "stdafx.h"
#include <iostream>
#include "Fract7.cpp"
using namespace std;
};
int main() {
FloatFraction fract1;
fract1.set_float(0.5);
cout << "Value of 0.5 is " << fract1.get_float() << endl;
fract1.set_float(0.6);
cout << "Value of 0.6 is " << fract1.get_float() << endl;
return 0;
}
void FloatFraction::set_float(double x) {
int new_val = static_cast<int>(x * 100.0);
set(new_val, 100);
}
POLIMORIFISM
Polimorfismul cu functii virtuale
318
Polimorfismul in C++ este admis atit in timpul compilarii cit si in
timpul rularii. polimorfismul din timpul rularii este realizat folosind
mostenirea si functiile virtuale.
Functiile virtuale
319
Datorita restrictiilor si diferentelor dintre functiile supraincarcate si cele virtuale,
pentru descrierea redefinirii functiei virtuale intr-o clasa derivata se foloseste operandul
suprascriere.
O clasa care include o functie virtuala se numeste clasa
polimorfica.
b. Functiile virtuale sint ierarhizate
320
Una dintre caile cele mai indicate pentru a asigura transpunerea in practica a
principiului “o interfata – metode multiple” este folosirea functiilor virtuale, a claselor
abstracte si a polimorfismului in timpul rularii. Folosind aceste caracteristici, se pot
realiza ierarhii care sa faca trecerea de la general la specific (de la clasa de baz aspre
clasele derivate), respectind astfel si unul din principiile ingineriei programarii –
abstractizarea. Conform acestei filosofii, trebuie definite toate caracteristicile si
interfetele comune ale unei clase de baza. De asemenea, se folosesc functii virtuale
pentru a defini interfata care va fi folosita de clasele derivate. In esenta, in clasa de
baza trebuie create si definite toate referirile la cazul general, iar clasele derivate
completeaza detaliile specifice.
O utilizare importantă a claselor abstracte şi a funcţiilor virtuale este cea a bibliotecilor de
clase. Un utilizator poate crea propria bibliotecă de clase generice şi extensibile care vor fi
refolosite de alţi utilizatori. Aceştia vor moşteni clasa generală creată iniţial, care defineşte
interfaţa şi elementele comune şi vor defini doar acele funcţii specifice clasei derivate.
Legat de cele discutate, mai trebuie precizate două noţiuni folosite frecvent :
Legăturile ulterioare (late bindings) se referă la apelările de funcţii care nu sînt rezolvate
pînă în momentul rulării. Pentru realizarea legăturilor ulterioare sînt utilizate funcţiile virtuale.
În acest caz, apelarea efectivă a funcţiei virtuale este determinată de tipul obiectului spre care
indică pointerul prin care îl accesăm. Deoarece în majoritatea cazurilor acesta nu poate fi
determinat în timpul compilării, obiectul şi funcţia nu sînt legate pînă în momentul rulării.
Avantajul legăturilor ulterioare este flexibilitatea : spre deosebire de legăturile iniţiale, cele
ulterioare permit crearea programelor care să răspundă la evenimentele care apar în timpul
rulării fără să fie necesară crearea unui cod suplimentar pentru selectarea situaţiilor şi apelurilor
dorite. Însă, deoarece rezolvarea direcţionării apelurilor este împinsă spre execuţia programului,
acesta va fi mai lent.
// Prin apelul aceleasi functii ca denumire a unui obiect dintr-o
//subclasa a unei functii din clasa de baza si aceleasi functii dar
redefinita
//in subclasa dar ca si continut diferita
//Sa se exemplifice acest lucru
//EX:1
// 2
// 1
// 2
// 1
#include "stdafx.h"
#include <iostream>
321
using namespace std;
class Horse
{
public:
void Gallop(){ cout << "Galloping...\n"; }
virtual void Fly() { cout << "Horses can't fly.\n" ; }
private:
int itsAge;
};
#include "stdafx.h"
#include <iostream>
322
virtual HANDS GetHeight() const { return itsHeight; }
virtual COLOR GetColor() const { return itsColor; }
private:
HANDS itsHeight;
COLOR itsColor;
};
class Bird
{
public:
Bird(COLOR color, BOOL migrates);
virtual ~Bird() {cout << "Bird destructor...\n"; }
virtual void Chirp()const { cout << "Chirp... "; }
virtual void Fly()const
{
cout << "I can fly! I can fly! I can fly! ";
}
virtual COLOR GetColor()const { return itsColor; }
virtual BOOL GetMigration() const { return itsMigration; }
private:
COLOR itsColor;
BOOL itsMigration;
};
private:
long itsNumberBelievers;
};
Pegasus::Pegasus(
COLOR aColor,
HANDS height,
BOOL migrates,
long NumBelieve):
Horse(aColor, height),
Bird(aColor, migrates),
itsNumberBelievers(NumBelieve)
{
323
cout << "Pegasus constructor...\n";
}
int main()
{
Pegasus *pPeg = new Pegasus(Red, 5, TRUE, 10);
pPeg->Fly();
pPeg->Whinny();
cout << "\nYour Pegasus is " << pPeg->GetHeight();
cout << " hands tall and ";
if (pPeg->GetMigration())
cout << "it does migrate.";
else
cout << "it does not migrate.";
cout << "\nA total of " << pPeg->GetNumberBelievers();
cout << " people believe it exists.\n";
delete pPeg;
return 0;
}
#include "stdafx.h"
#include <iostream>
Animal::Animal(int age):
itsAge(age)
{
cout << "Animal constructor...\n";
}
324
};
Pegasus::Pegasus(
COLOR aColor,
HANDS height,
BOOL migrates,
long NumBelieve,
int age):
Horse(aColor, height,age),
Bird(aColor, migrates,age),
itsNumberBelievers(NumBelieve)
{
cout << "Pegasus constructor...\n";
}
int main()
{
Pegasus *pPeg = new Pegasus(Red, 5, TRUE, 10, 2);
325
int age = pPeg->GetAge();
cout << "This pegasus is " << age << " years old.\n";
delete pPeg;
return 0;
}
#include <iostream>
using namespace std;
enum BOOL { FALSE, TRUE };
class Shape
{
public:
Shape(){}
~Shape(){}
virtual long GetArea() { return -1; } // error
virtual long GetPerim() { return -1; }
virtual void Draw() {}
private:
};
void Circle::Draw()
{
cout << "Circle drawing routine here!\n";
}
326
void Rectangle::Draw()
{
for (int i = 0; i<itsLength; i++)
{
for (int j = 0; j<itsWidth; j++)
cout << "x ";
Square::Square(int len):
Rectangle(len,len)
{}
{
if (GetLength() != GetWidth())
cout << "Error, not a square... a Rectangle??\n";
}
int main()
{
int choice;
BOOL fQuit = FALSE;
Shape * sp;
while (1)
{
cout << "(1)Circle (2)Rectangle (3)Square (0)Quit: ";
cin >> choice;
switch (choice)
{
case 1: sp = new Circle(5);
break;
case 2: sp = new Rectangle(4,6);
break;
case 3: sp = new Square(5);
break;
default: fQuit = TRUE;
break;
}
if (fQuit)
break;
sp->Draw();
cout << "\n";
}
return 0;
327
}
#include "stdafx.h"
#include <iostream>
using namespace std;
enum COLOR { Red, Green, Blue, Yellow, White, Black, Brown } ;
enum BOOL { FALSE, TRUE };
Animal::Animal(int age):
itsAge(age)
{
cout << "Animal constructor...\n";
}
328
public:
Horse(int age, COLOR color ):
Mammal(age), itsColor(color)
{ cout << "Horse constructor...\n"; }
virtual ~Horse() { cout << "Horse destructor...\n"; }
virtual void Speak()const { cout << "Whinny!... \n"; }
virtual COLOR GetItsColor() const { return itsColor; }
virtual void Sleep() const
{ cout << "Horse snoring...\n"; }
virtual void Eat() const { cout << "Horse feeding...\n"; }
virtual void Move() const { cout << "Horse running...\n";}
protected:
COLOR itsColor;
};
protected:
COLOR itsColor;
};
int main()
{
Animal *pAnimal=0;
int choice;
BOOL fQuit = FALSE;
while (1)
{
cout << "(1)Dog (2)Horse (3)Fish (0)Quit: ";
cin >> choice;
switch (choice)
{
case 1: pAnimal = new Dog(5,Brown);
break;
case 2: pAnimal = new Horse(4,Black);
break;
case 3: pAnimal = new Fish (5);
break;
default: fQuit = TRUE;
break;
}
if (fQuit)
break;
pAnimal->Speak();
pAnimal->Eat();
329
pAnimal->Reproduce();
pAnimal->Move();
pAnimal->Sleep();
delete pAnimal;
cout << "\n";
}
return 0;
}
SUPRAINCARCAREA FUNCTIILOR
Supraîncărcarea
Supraîncărcarea funcţiilor reprezintă folosirea aceluiaşi nume pentru două sau mai
multe funcţii. Fiecare redefinire a funcţiei trebuie să folosească tipuri diferite de parametri de
apel sau număr diferit de parametri. Compilatorul poate detecta care funcţie trebuie apelată, pe
baza acestor diferenţe.
Trebuie reţinut că nu pot fi supraîncărcate două funcţii care diferă doar prin tipul
returnat.
Ambiguităţi şi anacronisme la supraîncărcarea funcţiilor
În C putem să atribuim adresa unei funcţii, unui pointer şi apoi să aelăm funcţia
folosind pointerul. La fel se poate proceda (s-a văzut în cursurile precedente) şi în C++. O
complicaţie survine la supraîncărcarea funcţiilor, deoarece în această situaţie doar declararea
corespunzătoare a pointerului poate face diferenţierea.
Supraîncărcarea operatorilor
În C++ pot fi supraîncărcaţi aproape toţi operatorii. Supraîncărcarea acestora este strîns
legată de supraîncărcarea funcţiilor. În C++ supraîncărcarea operatorilor poate să determine
efectuarea unor operaţii speciale relativ la clasele create. Astfel, o memorie stivă poate fi
încărcată cu un element, folosind operatorul + supraîncărcat corespunzător, respectiv - pentru
330
extragere. Supraîncărcarea nu afectează vreuna din semnificaţiile originale ale utilizării
operatorului supraîncărcat.
Operatorii se supraîncarcă folosind funcţiile operator. O astfel de funcţie defineşte
operaţiile specifice pe care le va efectua operatorul supraîncărcat relativ la clasa în care este
destinat să lucreze. Funcţiile operator pot sau nu să fie membre ale clasei în care vor opera. De
obicei, cînd funcţiile operator nu sînt membre, sînt măcar funcţii friend. Cele două situaţii
(cînd sînt membre, respectiv cînd sînt friend) trebuie tratate diferit.
tip_returnat nume_clasa::operator#(lista_argumente)
{
... // aici vor fi operatiile care reprezinta redefinirea
// operatorului
}
La operandul -, a trebuit să fim atenţi la ordine : operandul din dreapta semnului trebuie scăzut
din operandul din stînga (ordinea naturală) şi ţinînd cont de operandul care generază apelul
funcţiei operator-() (adică acel operand care va transmite un pointer this), a rezultat
exprimarea aparent curioasă din definirea funcţiei operand respective.
Pe de altă parte, trebuie remarcat că în C++, în lipsa unei supraîncărcări, operatorul =
devine un operator de copiere membru cu membru. În exemplul prezentat, funcţia operator=()
a returnat *this, ceea ce a permis realizarea atribuirilor multiple (de altfel, aceasta este raţiunea
pentru care a fost supraîncărcat acest operator).
Ultimul lucru pe care îl remarcăm este legat de supraîncărcarea operatorului unar.
Evident, acesta nu are parametri, deoarece acţionează asupra unui singur operand, care este deja
transmis prin this.
#include "stdafx.h"
#include <iostream>
using namespace std;
int supra(int ); // prima functie are un parametru intreg
double supra(double ); // iar a doua are parametru double
main()
{
cout << supra(19) << " "; // apelul primei functii
cout << supra(5.4) << "\n"; //apelul celeilalte functii
return 0;
}
331
double supra(double d)
{
return d;
}
// Sa se supraincarce o functie cu numar diferit de paramatrii
#include "stdafx.h"
#include <iostream>
using namespace std;
main()
{
cout << supra1(11) << " "; // apelul primei functii
cout << supra1(5,4) << "\n"; //apelul celeilalte functii
return 0;
}
#include "stdafx.h"
#include <iostream>
#include <stdio.h>
using namespace std;
class data {
int zi, luna, an;
public:
data(char *);
data(int, int, int );
void arata_data();
};
332
{
cout << zi << "/" << luna<< "/"<<an<<"\n";
}
main()
{
data d1(4, 3, 98), d2("10/04/98");
d1.arata_data();
d2.arata_data();
return 0;
}
SUPRAINCARCAREA OPERATORILOR
// Sa se prezinte supraincarcarea operatorului PLUS
#include "stdafx.h"
#include <iostream>
using namespace std;
class loc{
int longit, latit;
public:
loc(){} // necesar pentru constructii de obiecte
// temporare
loc(int lg, int lt) {
longit=lg;
latit=lt;
}
void arata() {
cout << longit << " ";
cout << latit <<"\n";
}
loc operator+(loc ot);
};
main()
{
loc ob1(10,20), ob2(15,25); // se creeaza doua obiecte
// initializate
ob1.arata(); // se va afisa 10 20
ob2.arata(); // se va afisa 15 25
return 0;
}
333
// Sa se supraincarce patru operatori
#include "stdafx.h"
#include <iostream>
using namespace std;
class loc{
int longit, latit;
public:
loc(){} // necesar pentru constructii de obiecte
// temporare
loc(int lg, int lt) {
longit=lg;
latit=lt;
}
void arata() {
cout << longit << " ";
cout << latit <<"\n";
}
loc operator+(loc ot);
loc operator-(loc ot);
loc operator=(loc ot);
loc operator++();
};
334
return *this; // de asemenea este returnat chiar
// obiectul care a generat apelarea, de fapt a operat
// direct asupra obiectului
main()
{
loc ob1(10,20), ob2(15,25), ob3(3,7); // se creeaza
// trei obiecte initializate
ob1.arata(); // se va afisa 10 20
ob2.arata(); // se va afisa 15 25
ob2=++ob1;
ob1.arata(); // afiseaza 12 22
ob2.arata(); // afiseaza tot 12 22
return 0;
}
Matrice, pointeri şi referinţe
//sa se creeze o matrice de obiecte
#include "stdafx.h"
#include <iostream>
using namespace std;
class cl {
int i;
public:
cl(int j){ i = j; }
int da_i() { return i; }
};
main()
{
c1 mo[ 3] = { 1, 2, 3 }; // initializare
int i;
for ( i = 0; i < 3 ; i ++)
cout << mo[ i ] . da_i() << endl;
return 0;
}
335
main()
{
cl ob(23), *p;
p = &ob; // da adresa lui ob
cout << p->da_i(); // foloseste -> pentru a apela da_i()
return 0;
}
// Sa se puna pointer prin deplasarea in matrice
#include<stdafx.h>
#include <iostream>
using namespace std;
class cl {
int i;
public:
cl() { i = 0; }
cl(int j) { i = j; }
int da_i() { return i; }
};
main()
{
cl ob[ 3 ] = { 1, 2, 3 };
cl *p;
int i;
main()
{
acces_p poin(1);
int *p ,i;
336
#include<stdafx.h>
#include <iostream>
using namespace std;
class putere{
double b;
int e;
double rez;
public:
putere(double, int );
double rezultat() {return this->rez; }
};
main()
{
putere x(65.3, 4), y(1.35, 5), z(200.1, 0); // 3 obiecte
return 0;
}
//Sa se puna in evidenta folosirea pointerului THIS
//(adica obiectul care a invocat functia : obiect.functie(...) )
//acici el se subintelege ca e din clasa curenta
#include<stdafx.h>
#include <iostream>
using namespace std;
class putere{
double b;
int e;
double rez;
public:
putere(double, int );
double rezultat() {return rez;}
};
main()
{
putere x(65.3, 4), y(1.35, 5), z(200.1, 0); // 3 obiecte
337
cout << x.rezultat() << endl;
cout << y.rezultat() << endl;
cout << z.rezultat() << endl;
return 0;
}
//Sa se puna in evidenta pointer catre functii si date membru
//ai unei clase
#include<stdafx.h>
#include <iostream>
using namespace std;
class c1{
public:
c1(int i) {val=i; }
int val;
int val_dubla() {return val+val; }
};
main()
{
int c1::*date; // pointer la o data membru
int (c1::*func)(); // pointer la o functie membru
c1 ob1(1), ob2(2); // crearea a doua obiecte
return 0;
}
//cu pointari sa se puna in evidenta
//transmiterea datelor prin referinta
#include<stdafx.h>
#include <iostream>
using namespace std;
void neg(int *);
main()
{
int in;
in=100;
cout << in << " este negat ";
neg(&in); // se transmite adresa explicit
cout << in << endl;
return 0;
}
338
using namespace std;
void neg(int &i); // i este referinta
main()
{
int in;
in=100;
cout << in << " este negat ";
neg(in); // nu e nevoie de &
cout << in << endl;
return 0;
}
main()
{
int a,b;
a=1;
b=2;
cout << " a si b: " << a << " " << b << " ";
schimb(a, b); // aici schimbam ; vedem ca nu trebuie
// scris cu &
cout << " a si b: " << a << " " << b << " "
;
return 0;
}
class nu_distruge{
int k;
public:
int i;
nu_distruge(int );
~nu_distruge();
void neg(nu_distruge &ob) {ob.i = -ob.i; } // nu se va
// crea obiect temporar
339
};
nu_distruge::~nu_distruge() // destructorul
{
cout << "Distruge " << k << "\n";
}
main()
{
nu_distruge ob(1); // un obiect initializat
ob.i=10;
ob.neg(ob); // la apel se transmite obiectul prin
// referinta
return 0;
}
a=1;
cout << a << " " << ref << "\n";
ref=10;
cout << a << " " << ref << "\n";
int b=39;
ref=b; // aici, valoarea lui b trece de fapt in a
cout << a << " " << ref << "\n";
return 0;
}
Operatorii de alocare dinamică din C++
//Sa se aloce dinamic un intreg si sa se elibereze spatiul
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <stdlib.h>
main()
340
{
int *p;
p=new int; // aloca spatiu pentru un intreg
if (!p) {
cout << "Eroare de alocare\n";
exit(1);
}
*p=190;
delete p;
return 0;
}
//sa se supraincarce operatorii de alocare dinamica
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <stdlib.h>
main()
{
int *p;
p=new int(314); // aloca spatiu pentru un intreg
// dar si initializeaza
if (!p) {
cout << "Eroare de alocare\n";
exit(1);
}
*p=190;
delete p;
return 0;
}
//alocarea dintr-o data a memoriei pentru 10 obiecte
//si eliberarea memoriei
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <stdlib.h>
main()
{
int *p, i; // (ati retinut ca doar primul e pointer ?)
341
#include "stdafx.h"
#include <iostream>
using namespace std;
const int* u;
int const* v;
int d = 1;
int* const w = &d;
const int* const x = &d; // (1)
int const* const x2 = &d; // (2)
int main() {} ///:~
342