Documente Academic
Documente Profesional
Documente Cultură
Preprocesorul
Preprocesorul, care nu se gsete n multe dintre limbajele de programare de nivel nalt,
furnizeaz instrumente ce permit programatorului s dezvolte programe ce sunt mai uor de
dezvoltat, mai uor de citit, de modificat i mai uor de transportat pe un sistem de calcul diferit.
Programatorul poate, de asemenea, utiliza preprocesorul pentru a individualiza literal limbajul C
pentru a corespunde unei aplicaii de programare particular sau pentru a satisface stilul de
programare propriu al programatorului.
Preprocesorul este o parte a procesului de compilare C, care recunoate declaraii speciale pe care le
poate conine un program C. Dup cum arat i numele, preprocesorul analizeaz aceste declaraii
nainte de a avea loc analiza propriu-zis a programului.
Declaraiile preprocesor sunt identificate prin prezena semnului #, care trebuie s fie primul
caracter din linie. Orice comand care ncepe cu caracterul # se numete directiv de
preprocesare, adic o comand pentru compilator. La compilare, directivele de preprocesare nu
sunt transformate n cod, ci doar controleaz modul de lucru al compilatorului.
Directivele de preprocesare nu sunt urmate de caracterul ;. Ele sunt scrise, ntotdeauna,
fiecare pe cte o linie separat i deci compilatorul tie c atunci cnd se termin linia se termin i
directiva de preprocesare.
Directiva #define
Una dintre primele utilizri ale acestei declaraii este pentru asignarea de nume simbolice la
constantele programului. De exemplu:
#define TRUE 1
definete numele TRUE i l face echivalent cu valoarea 1. Acest nume poate fi folosit, n
continuare, oriunde n program unde constanta 1 poate fi folosit. Preprocesorul va substitui fiecare
apariie a numelui TRUE cu valoarea asociat. Diferena ntre aceast definire i una de form
TRUE=1,este ca pentru aceast declaraie substituia lui TRUE cu 1 se face n timp ce se execut
programul, iar pentru declaraia anterioara substituia are loc la compilarea programului. Sintaxa
general:
#define NUME valoare
Exist o singur excepie de la aceast regul, i anume, dac numele respectiv este coninut ntr-un
ir de caractere. De exemplu n exemplul urmtor:
char *car_pointer = TRUE;
fixeaz referina lui car_pointer ctre irul TRUE i nu la 1.
Preprocesorul analizeaz fiierul nu nainte ca, compilatorul nsui, s examineze codul.
Iat ce realizeaz preprocesorul:
1. nlocuiete secvenele trigraf (trei semne) cu echivalentele lor.
2. Unete orice linie ce se termin cu caracterul \ (backslash) mpreun cu linia urmtoare
ntr-o singur linie.
3. mparte programul ntr-un flux de semne.
4. Elimin comentariile, nlocuindu-le printr-un singur spaiu.
5. Prelucreaz directivele preprocesor i expandeaz macrodefiniiile.
6. nlocuiete caracterele de evitare (escape) cu constante caracter i constantele ir de
caractere prin reprezentarea lor interna echivalent.
7. Concateneaz irurile de caractere constante adiacente.
Secvena trigraf
Pentru a prelucra seturi de caractere non-ASCII, urmtoarele secvene de trei caractere
(denumite trigraf) sunt recunoscute i tratate special, oriunde ele apar ntr-un program, chiar n
interiorul irurilor de caractere:
Trigraf
Semnificaie
??=
#
??(
[
??)
]
1
??<
??>
??/
??
??!
??-
{
}
\
^
|
~
Directiva #define poate fi utilizat n dou formate; primul format este urmtorul:
#define nume text
nume va fi substituit, n program, cu text, pana la sfritul liniei.
Cel de-al doilea format este:
#define nume (param_1,param_2, . . . ,param_n) text
Aceast form definete o macrodefiniie cu cele n argumente (parametri), fiecare dintre ele fiind un
identificator. Utilizrile urmtoare, n program, ale numelui, cu o list de argumente, determin
substituirea acestuia cu textul definit, argumentele apelului de macro nlocuind toate apariiile
parametrilor corespunztori din text. Operatorul # poate fi utilizat n directivele #define pentru a lua
argumentele. El este urmat de numele unui argument din macro.
Preprocesorul pune ghilimele n jurul valorii actuale (efective) transmise ctre macro, cnd
aceasta este utilizat, adic este transformat ntr-un ir de caractere.
Forma general pentru macrodefiniii este:
#define IdMacro (listaArg) (corpMacro)
unde argumentele se separ prin virgule, iar corpul macrodefiniiei nu conine spaii.
Referirea se face astfel:
IdMacro (lista_Expresii_Arg)
Efectul referii este substituirea prin corpul macrodefiniiei, n care argumentele sunt nlocuite
textual prin expresiile corespunztoare.
n corpMacro argumentele trebuie s fie ncadrate ntre paranteze (), altfel efectul nu este cel
dorit. Fac excepie argumentele ce reprezint identificatori de cmpuri din structuri.
n cazul n care corpul macrodefiniiei nu ncape pe o singur linie, el se va continua pe linia
urmtoare, linia curent fiind terminat cu \.
#define IdMacro (listaArg) (nceput_corp_Macro\
continuare_corp_Macro)
Nu se pot utiliza apeluri de funcii sau macrodefiniii n expresiile argumentelor care se repet n
corpul macrodefiniiei pentru a evita evaluarea acestora de mai multe ori:
#define patrat (x)
- este eronat
#define patrat ((x)*(x)- este corect
#define Max (a, b) ((a)>(b) ? (a) : (b))
pentru a determina maximul dintr-un grup de patru valori de forma:
x = Max (Max(x1, x2), Max(x3, x4));
este ineficient ntruct se substituie prin:
((x1) > (x2) ? (x1) : (x2)) > ((x3) > (x4) ? (x3) : (x4)) ?
((x1) > (x2) ? (x1) : (x2)) : ((x3) > (x4) ? (x3) : (x4))
mult mai eficient este:
t = Max(x1, x2);
x = Max(x3, x4);
x = Max(x, t);
Operatorul ## este, de asemenea, permis n directivele #define pentru a lua argumente. Este
urmat sau precedat de numele unui argument pentru macro. Preprocesorul ia valoarea ce este
transmis cnd se apeleaz macro i creeaz un singur semn (simbol) din argumentul pentru macro
i semnul ce-l urmeaz sau precede.
Exemplu:
2
aplicat definiiilor ce au unul sau mai multe argumente. Spre deosebire de funcii la implementarea
n C a unei MACRO nu este important tipul argumentului, deci nu trebuie precizat. De exemplu, s
considerm un MACRO care determin ptratul unui numr:
#define PATRAT ( x ) x*x
Indiferent de tipul argumentului, int, long sau float acelai MACRO poate fi utilizat, ceea ce n
cazul funciilor nu este valabil: dac funcia a fost definit cu argument de tip int, ea nu poate fi
apelat cu argument de alt tip, de exemplu double.
Deoarece preprocesorul realizeaz o substituie literal a argumentului n definiia unui
macro, aceasta trebuie construit cu grij. De exemplu pentru macro anterior o declaraie de forma:
y = PATRAT ( a + 2 );
va fi evaluat, prin substituie lateral, astfel:
y = a + 2 * a + 2;
care evident nu va calcula (a + 2)2.
Pentru a trata adecvat astfel de situaii este necesar utilizarea de paranteze n definirea unui
macro:
#define PATRAT ( x ) ( x ) * ( x )
i pentru aceast form pot, ns, s mai apar unele probleme. De exemplu dac dorim s
calculm expresia:
100 / PATRAT ( 2 ) se obine:
100 / 2 * 2
al crui rezultat va fi 100 , n loc de 25.
Pentru a rezolva i astfel de situaii vom defini macro astfel:
#define PATRAT ( x ) ( ( x ) * ( x ) )
Din acest exemplu se poate trage concluzia de a utiliza att de multe paranteze ct este necesar
pentru a asigura c toate operaiile i asocierile sunt fcute n ordinea corect.
#include <iostream.h>
#define PATRAT(x) ((x)*(x))
void main(void)
{
for (int i = 1; i <= 10; i++)
cout << i << " la patrat este " << PATRAT(i) << endl;
}
Chiar i cu aceste precauii iat o situaie ce poate s apar:
PATRAT ( ++x )
care va deveni:
++x * ++x
caz n care x este incrementat de dou ori, o dat nainte de nmulire i o dat dup, deci:
++x * ++x = 5 * 6 = 30
Ultimul remediu, pentru aceast din urm problem, este de a evita utilizarea formei ++x ca
argument de macro. n general, nu se recomand utilizarea operatorilor de incrementare /
decrementare cu macr-uri. De remarcat, totui, c ++x poate fi un argument de funcie, deoarece el
este evaluat la valoarea 5 i apoi valoarea 5 este trimis funciei.
Alte exemple de macro-uri:
- determinarea valorii maxime dintre dou valori:
#define MAX ( a , b )
((a)>(b))?(a):(b)
- determinarea tipului unui caracter, dac este liter mic:
#define ESTE_LITERA_MICA (x) ( ( ( x ) >= 'a' ) && ( ( x ) <= 'z' ) )
- utilizarea acestei macrodefiniii, ntr-o alt macrodefiniie, pentru a converti un caracter de
la liter mic la liter mare:
#define LITERA_MARE ( x ) ( ESTE_LITERA_MICA ( x ) ? ( x ) - 'a' +'A' : ( x ) )
care poate fi folosit ntr-un program astfel:
while ( *sir != '\0' )
{
*sir = LITERA_MARE ( *sir );
++sir;
5
}
care va transforma literele mici n litere mari pentru un ir de caractere referit de variabila
sir.
Operatorul #:
Dac se plaseaz semnul # n faa unui parametru ntr-o macrodefiniie, preprocesorul va
crea o constant ir de caractere pentru argumentul macroului, cnd este utilizat macro.
De exemplu, definiia:
#define str ( x ) #x
va determina pentru urmtoarea utilizare:
str ( testare )
s fie expandat n:
testare
sau, de exemplu, funcia:
printf ( str( salut!\n ) );
este echivalenta cu
printf (salut!\n);
Dac n irul de caractere apare semnul el va fi precedat de \, astfel:
str(salut) va furniza
\salut\
Un exemplu tipic de utilizare este urmtoarea definiie de macro:
#define printint ( va r)
printf ( #var=%i\n, var )
pentru care o utilizare de forma:
printf ( numar )
va fi expandat n:
printf ( numar =%i\n, numar );
care dup concatenarea celor dou iruri de caractere va deveni:
printf ( numar=%i\n, numar );
Operatorul ##
Operatorul ## este utilizat n macrodefiniii pentru a lega dou semne mpreun. El este
precedat sau urmat de numele unui parametru de macro. Preprocesorul ia argumentul actual din
macro, care este specificat la apelarea macrodefiniiei, i creeaz un singur semn din acel argument
i orice urmeaz sau precede semnul ##.
De exemplu, s presupunem c avem o lista de variabile x1 pn la x100. Se poate defini o
macrodefiniie care s aib ca argumente valorile de la 1 la 100 i s afieze variabila
corespunztoare, astfel:
#define printx ( n )
printf ( %i\n, x##n )
definiie ce citete x##n i care precizeaz c se iau semnele ce apar nainte i dup ##, litera x i
argumentul n i realizeaz un singur semn.
Astfel apelul:
printx(50);
va fi expandat n:
printf ( %i\n,x50 );
sau, dac se utilizeaz definiia anterioar, putem defini noua macro astfel:
#define printx ( n ) printint ( x##n )
care pentru un apel de forma:
printx(20);
va genera:
printf ( x20=%i\n, x20 );
printf ( x20=%i\n, x20 );
Directiva #include
Dac dorim includerea unui set de macrodefiniii n fiecare program putem, n loc s le
definim la nceputul fiecrui program, s le depunem pe toate ntr-un fiier separat i apoi s-l
includem n orice program care are nevoie de aceste definiii utiliznd directiva #include.
Utilizarea i facilitile acestei directive sunt cel mai bine folosite n dezvoltarea de
programe care au fost mprite n module de subprograme separate.
Dac la elaborarea unui program lucreaz mai muli programatori, atunci includerea de
fiiere furnizeaz un mijloc de standardizare; fiecare programator va utiliza aceleai definiii, care
au aceleai valori; n plus, se elimin o surs de erori i o pierdere de timp pentru introducerea
acestor definiii n fiecare modul care are nevoie de ele.
Mai mult, n momentul n care trebuie fcut o modificare a unei definiii (pentru o anumit
6
structur de date), ea poate fi fcut numai ntr-un singur loc i anume n fiierul de inclus.
Fiierul care va colecta toate aceste definiii va fi definit printr-un nume urmat de un punct i
litera h, astfel:
nume_fisier.h
extensia h este utilizat, de obicei, pentru astfel de fiiere, denumite fiiere antet - header. Fiierele
antet constau din declaraii preprocesor. Includerea definiiilor din acest fiier n programul curent
se face astfel:
#include nume_fisier.h
directiva mai poate avea i forma, de exemplu:
#include <stdio>
Dac se utilizeaz < >, preprocesorul va cuta fiierul ntr-unul sau mai multe directoare de
sistem, standard. De exemplu:
#include bool.h - caut n directorul curent
#include a:\dir1\bool.h - va cuta pe drive-ul a, n directorul dir1.
Exemplu:
definim valorile booleane: TRUE=1 i FALSE=0
/* bool.h - fisierul ce contine aceste declaratii */
#define BOOLEAN int
#define TRUE 1
#define FALSE 0
/*
*/
#include <stdio.h>
#include "bool.h"
main( )
{
int ch, count = 0;
BOOLEAN spatiu_alb( char );
while ( (ch = getchar( ) ) != EOF )
if (spatiu_alb ( ch) ) /* echivalenta cu if ( spatiu_alb (ch) == TRUE ) */
count ++;
printf ( "S-au intalnit %d spatii albe\n", count );
}
BOOLEAN spatiu_alb ( char c )
{
if ( c == ' ' || c == '\n' || c == '\t' )
return ( TRUE );
else
return ( FALSE );
}
n acest exemplu am creat un nou tip BOOLEAN, deoarece BOOLEAN este pur i simplu de
tipul int. Aceast declaraie, pentru funcia logic definit, este de a aminti utilizatorului c funcia
este utilizat pentru calcule logice i nu aritmetice. Se poate utiliza o macrodefiniie n loc de a
defini o funcie pentru a defini spaiul alb.
Deci o variabil definit n exteriorul unei funcii nu este numai o variabil global, dar este
i o variabil extern. n multe situaii dorim ns s definim o variabil global, dar care s nu fie i
8
variabil extern, adic s fie o variabil global, dar local pentru acel modul, astfel ca doar
funciile din acel modul s aib acces la ea, nu i din alte module. Acest deziderat se poate realiza
cu declaraia static, n exteriorul funciilor dintr-un modul; n cest fel vor avea acces la variabil
toate funciile din modulul respectiv, dar nu i din alte module.
O funcie este considerat n cazul implicit de tip extern; ea poate fi declarat i de tip static,
dac dorim ca ea s fie apelat numai n cadrul aceluiai fiier n care apare. n acest caz se plaseaz
declaraia static naintea declaraiei antetului funciei:
static double radacina (double x);
S considerm dou module:
modul1.c
#include <stdio.h>
double x;
static double rezultat;
static void patrat_loc (void)
{
double patrat (void);
x = 4.0;
rezultat = patrat ( );
}
main ( )
{
patrat_loc ( );
printf (%f\n, rezultat);
}
modul2.c
extern double x;
double patrat (void);
{
return (x*x);
}
Funcia main ( ) apeleaz funcia patrat_loc ( ), definit n acelai modul (modul1.c), care la
rndul ei apeleaz funcia patrat ( ) din alt modul (modul2.c).
Funcia patrat_loc(), fiind declarat static, poate fi apelat doar din modul1.c. n acest
modul sunt definite dou variabile globale:
- x, care poate fi apelat de orice modul;
- rezultat de tip static, care poate fi apelat doar din modul1.c.
Variabila x este declarat n modul2.c de tip extern, astfel s poat accesa aceast variabil definit
n modul1.c.
8. Agoritmi de sortare
n acest capitol vom prezenta civa algortimi de sortare (ordonare) dintre cei mai
reprezentativi i mai des utilizai. n capitolele anterioare au mai fost prezentai doi algoritmi de
sortare foarte cunoscui, i anume: algorimul de sortare prin metoda inversiunilor (sau bulelor, cum
este denumit) i algoritmul de ordonare Donald Shell; asupra acestora nu vom mai reveni n acest
capitol.
Sortare prin selecie direct
Aceast metod se bazeaz pe urmtorul principiu, de exemplu pentru ordonare cresctoare:
1. Se selecteaz termenul cu cea mai mic valoare.
2. Se schimb acesta cu primul termen (ai).
Apoi se repet operaiile cu cele n-1 elemente rmase, i aa mai departe pn rmne un singur
termen (cel mai mare). Deci, pentru sortarea cresctoare a unui ir, algoritmul este urmtorul:
for (i = 1; i < n-1; i++)
9
{
* se determin indicele celui mai mic element, k, dintre a[i], . . . ,a[n];
* se interschimb a[i] cu a[k];
}
Iat ntreg programul care sorteaz prin selecie direct:
/* sel_dir.c - programul ordoneaza un vector prin selectie directa,
utilizand pentru aceasta determinarea minimului si a pozitiei lui,
la fiecare iteratie si realizand o singura inversiune intre acest
minim si valoarea a[i], corespunzatoare iteratiei curente;
se determina si numarul de comparatii si inversiuni realizate
*/
#include<stdio.h>
#include <conio.h>
int ncomp=0, ninv=0; /* numar de comparatii si inversiuni */
void sort_sel_direct ( double a[], int n )
/* functia sorteaza un vector prin metoda de selectie directa */
{
double x;
int i, j, k;
for ( i = 0 ; i < n-1 ; ++i )
{
k = i; /* initializare indice, k, si elementul minim, x */
x = a[i];
for ( j = i+1 ; j < n ; ++j, ncomp++ ) /* determinare minim si indicele lui din sir */
if (a[j] < x)
{
k = j;
x = a[k];
}
a[k] = a[i]; /* interschimbare minim cu primul din subsirul sursa, */
a[i] = x;
/* adica cu primul din subsirul neordonat */
ninv++;
}
}
void main(void)
{
double sir[100];
int ne,i, nl=0;
clrscr();
printf("Numar elemente:");
scanf("%d",&ne);
for(i=0;i<ne;i++) /* citirea elementelor sirului de ordonat */
{
printf("sir(%d)=",i+1);
scanf("%lf",& sir[i]);
}
sort_sel_direct(sir,ne); /* ordonarea sirului prin selectie directa */
for(i=0;i<ne;i++)
/* afisarea sirului ordonat */
{
10
printf(" sir(%2d)=%5.1lf",i+1,sir[i]);
nl++; /* actualizare contor numar de valori afisate pe o linie */
if ( nl % 5 == 0 ) /* daca s-au afisat 5 valori pe o linie se trece pe */
printf("\n"); /* o linie noua */
}
printf("\n");
printf("Ordonarea s-a realizat prin %d comparatii si %d inversiuni\n",
ncomp, ninv);
}
Sortare prin inserare direct.
Aceast metod este utilizat de juctorii de cri. Elementele irului (deci, crile de joc)
sunt mprite n dou subiruri:
- un subir destinaie a1, a2, a3, . . ., ai-1, care este ordonat pe msura crerii lui, i
- un subir surs ai, ai+1, ai+2, . . ., an;
Iniial irul destinaie, deci cel ordonat, este format doar din primul element al irului, a1. La
fiecare pas (iteraie), ncepnd cu i = 2, elementul i din irul surs este luat din acesta i transferat n
irul destinaie prin inserare pe poziia corespunztoare, dup compararea cu elementele irului
destinaie.
irul destinaie este parcurs de la dreapta la stnga, deoarece la fiecare comparaie, dac
elementul de inserat, cel din irul surs, nu trebuie inserat pe poziia respectiv n irul destinaie,
elementul cu care s-a comparat, din irul destinaie, este deplasat cu o poziie la dreapta pentru a
face loc noului element, de introdus n irul destinaie. Din cazurile particulare, adic situaiile n
care noul element trebuie inserat pe prima sau pe ultima poziie, rezult, n mod evident, aceast
condiie.
Deci algoritmul este urmtorul:
for ( i = 1; i < n ; i++)
{
x = a [i];
/* elementul curent de inserat; */
se insereaz x pe poziia corespunztoare n a1, a2, a3, . . ., ai-1,
parcurgnd acest subir de la dreapta la stnga
}
Programul pentru sortarea prin inserare direct este prezentat n continuare.
/* ins_dir.c prog. ordonare cresc. sir, utilizand metoda de inserare directa, adica:
se considera un sir ordonat, format initial din primul element din sirul initial,
si un sir neordonat, format din restul elementelor sirului, din care se iau pe
rand celelalte elemente si li sa cauta, de la dreapta la stanga, pozitia in
sirul ordonat, construit tot in sirul initial. */
#include <stdio.h>
#include <conio.h>
int ncomp=0, nins=0; /* numar de comparatii si inserari/ deplasari */
void sort_ins_direct (double a[], int n)
{/* functia de sortare prin inserare directa */
double x;
int i, j;
for (i=1; i<n; ++i)
{
x=a[i]; /* elementul curent de inserat */
j=i-1; /* dimensiunea sirului destinatie */
11
k=i;
/* se reine pozitia ultimei inversiuni */
ninv++;}
s=k+1;
/* se modifica corespunzator limita din stanga */
}while(s <= d);
Acest algoritm este mai rapid dect sortrile prin metoda inserrii directe sau cel al seleciei.
Sortarea unui vector, ce conine indicii vectorului iniial (de sortat)
n cazul n care datele care trebuie ordonate sunt reprezentate pe foarte muli octei, cum este
cazul unor structuri largi, atunci este de preferat, indiferent de algoritmul de sortare utilizat, s nu se
realizeze inversiunile (ordonarea) ntre componentele vectorului respectiv (tab[], ca n exemplul
urmtor), deoarece vor necesita mult timp de execuie pentru inversarea lor, ci s se ordoneze un
vector ce conine indicii componentelor din vectorul iniial (index[]); binneles, comparaiile
necesare ordonrii se vor face ntre valorile cheie (info) dup care se face ordonarea, avnd, ns, ca
indice indicele din tabloul de indici care se ordoneaz (adresare indirect). Iniial acest tablou
(index) va conine valorile indicilor tabloului de ordonat (de fapt aceste valori sunt iniial 0, 1, 2, 3,
). Indiferent de metoda de sortare utilizat ordonarea se va face dup o anumit cheie (informaie
coninut n componentele tabloului, n exemplul urmtor aceasta este numit medie) asupra
tabloului de indici (index), care va fi utilizat ca indici pentru tabloul iniial (tab[index[j]]). Se va
utiliza o adresare indirect, adic indicii tabloului ce trebuie sortat vor fi luai din tabloul de indici
(tab[index[j]]), iar sortarea se va face asupra acestuia i nu direct asupra tabloului iniial. Deci, n
final, tabloul iniial, cel de sortat (tab), va rmne neschimbat, dar tabloul cu indici (index), ai
tabloului de ordonat, va fi ordonat dup valorile (cmpurile) pe care acesta le selecteaz din tabloul
iniial. Vom exemplifica aceast metod de ordonare, des utilizat, a tabloului de indici asociat
tabloului de valori, utiliznd algoritmul de sortare shakersort.
/* sortindx.c - se sorteaza indecsii unui tablou de tip structura,
care contine date pentru un numar de studenti (nume, prenume si media)
asociat acestui tablou definim un tablou cu indecsii tabloului de studenti;
vom sorta studentii dupa medii prin intermediul tabloului de indecsi,
iar sortarea indicilor se va face utiliznd algoritmul ShakerSort
*/
#include <stdio.h>
#define DIM 100
#include <conio.h>
struct tip_struct
{
char nume_prenum [DIM];/* numele si prenumele unui student*/
float medie;
};
void main(void)
{
struct tip_struct stud [100];/* consideram un tablou de studenti */
int
ind[100]; /* vectorul ce contine indecsii tabloului initial, si ce
va fi ordonat in functie de valorile vectorului de ordonat "tab" */
int
i, ns;
float f;
void ShakerSort (struct tip_struct tab[], int index[], int n);
clrscr();
16
printf("Numarul de studenti:");
scanf("%d", &ns);
f=0.0; fflush(stdin);
for (i=0; i<ns; i++) /* citire date studenti: nume, prenume si media */
{
printf("Numele si prenumele studentului %d: ", i+1);
gets(stud[i].nume_prenum);
printf("Media notelor sale: ");
scanf("%f", &f);
stud[i].medie=f;
while (getchar() != '\n');
}
for (i=0; i<ns; i++)
/* initializarea tabloului de indici */
ind[i] = i;
ShakerSort (stud, ind, ns); /* sortarea vectorului */
printf("Lista ordonata cu numele / prenumele si media studentilor\n");
for (i=0; i<ns; i++)
printf("%s %.2f\n", stud[ind[i]].nume_prenum,
stud[ind[i]].medie);
}
void ShakerSort (struct tip_struct tab[], int index[], int n)
{
int i, s, d, k, t;
d=n-2; s=0; k=d;
do
{
for (i=s; i<=d; i++)
if (tab[index[i]].medie < tab[index[i+1]].medie)
{
t=index[i];
index[i]=index[i+1];
index[i+1]=t;
k=i;
}
d=k-1;
for (i=d; i>=s; i--)
if (tab[index[i+1]].medie > tab[index[i]].medie)
{
t=index[i];
index[i]=index[i+1];
index[i+1]=t;
k=i;
}
s=k+1;
} while (s <= d);
}
Pentru testare se poate simplifica programul considernd, pentru aceasta, un vector de valori
numerice i n acest caz dispare, din exemplul anterior, cmpul info, deci comparaiile respective
vor fi de forma urmtoare: if (tab[index[i]] < tab[index[i+1]]), respectiv if (tab[index[i+1]] >
tab[index[i]]).
17
QuickSort ( 1 , n ).
B I B LI O G RAFI E
19
20