<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blog despre resurse educaţionale din IT &#187; programare</title>
	<atom:link href="http://resurse-educationale.uv.ro/?feed=rss2&#038;tag=programare" rel="self" type="application/rss+xml" />
	<link>http://resurse-educationale.uv.ro</link>
	<description>Cu informatii pentru dezvoltare personala, dar şi pentru studentţi, elevi, profesori, webmasteri, programatori</description>
	<lastBuildDate>Fri, 27 Jan 2012 01:12:50 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>CONCEPTE DE BAZĂ ALE PROGRAMĂRII  ORIENTATE OBIECT</title>
		<link>http://resurse-educationale.uv.ro/?p=198</link>
		<comments>http://resurse-educationale.uv.ro/?p=198#comments</comments>
		<pubDate>Wed, 14 Sep 2011 13:31:17 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[clase]]></category>
		<category><![CDATA[mostenire]]></category>
		<category><![CDATA[obiecte]]></category>
		<category><![CDATA[pe obiect]]></category>
		<category><![CDATA[polimorfism]]></category>
		<category><![CDATA[POO]]></category>
		<category><![CDATA[programare]]></category>

		<guid isPermaLink="false">http://resurse-educationale.uv.ro/?p=198</guid>
		<description><![CDATA[9.1.  INTRODUCERE   Termenul &#8220;OOP&#8221; (&#8220;Object Oriented Programming&#8221;) desemnează disciplina programării obiectuale (orientate-obiect). Această disciplină care are la bază ideea unificării datelor cu modalităţile de prelucrare a acestora şi manevrează entităţi reprezentate sub formă de obiecte (obiect=date+cod de tratare a &#8230; <a href="http://resurse-educationale.uv.ro/?p=198">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p align="center"><strong>9.1.  INTRODUCERE</strong></p>
<p align="center"><strong> </strong></p>
<p>Termenul &#8220;OOP&#8221; (&#8220;<strong>O</strong>bject <strong>O</strong>riented <strong>P</strong>rogramming&#8221;) desemnează disciplina programării obiectuale (orientate-obiect). Această disciplină care are la bază ideea unificării datelor cu modalităţile de prelucrare a acestora şi manevrează entităţi reprezentate sub formă de <strong>obiecte</strong> (obiect=date+cod de tratare a acestor date).</p>
<p>&nbsp;</p>
<p>Aşa cum s-a subliniat în capitolul 1.3., rezolvarea unei probleme se poate face pe 3 direcţii:</p>
<p>q  Rezolvarea <em>orientată pe algoritm</em> (pe acţiune), în care organizarea datelor este neesenţială;</p>
<p>q  Rezolvarea <em>orientată pe date</em>, acţiunile fiind determinate doar de organizarea datelor;</p>
<p>q  Rezolvarea <em>orientată obiect</em>, care combină tendinţele primelor două abordări.</p>
<p>&nbsp;</p>
<p>Programarea obiectuală oferă posibilităţi de <strong>modelare </strong>a obiectelor, a proprietăţilor şi a relaţiilor dintre ele, dar şi posibilitatea de a <strong>descompune</strong> o problemă în componentele sale (soft mai mentenabil, adaptabil, reciclabil). Câteva exemple de limbaje de programare orientată obiect: SIMULA(1965), SIMULA-2(1967), Smalltalk, C++, Java (în plus, Java poate fi considerat un limbaj de programare orientată eveniment).</p>
<p><strong> </strong></p>
<p><strong>Facilităţile</strong> oferite de programarea orientată obiect (conform lui Pascou) sunt:</p>
<ol>
<li>abstractizarea datelor;</li>
<li>moştenirea;</li>
<li>încapsularea (ascunderea)  informaţiei;</li>
<li>legarea dinamică (“târzie”).</li>
</ol>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p align="center"><strong>9.2.  ABSTRACTIZAREA DATELOR</strong></p>
<p>&nbsp;</p>
<p>Obiectele sunt componente software care modelează fenomene din lumea reală. În general, un fenomen implică tipuri diferite de obiecte. Obiectele care reprezintă aceeaşi idee sau concept sunt de acelaşi <strong>tip</strong> şi pot fi grupate în <strong>clase</strong> (<em>concrete</em> sau <em>abstracte</em>). Clasele implementează tipuri de date (aşa cum s-a subliniat în capitolul 2, un tip de date înseamnă o mulţime de valori pentru care s-a adoptatat un anumit mod de reprezentare şi o muţime de operatori care pot fi aplicaţi acestor valori), deci şi operatorii destinaţi manipulării acestora:<strong> </strong><strong>Clasă = Date + Operaţii</strong><strong>.</strong></p>
<p>De exemplu, programatorul îşi poate defini tipul (clasa) matrice şi operatorii care pot fi aplicaţi matricilor (* pentru înmulţirea a două matrici, + pentru adunarea a două matrici, &#8211; pentru scăderea a două matrici, etc). Astfel, el poate folosi tipul matrice în mod similar unui tip predefinit:</p>
<p>matrice A, B;</p>
<p>matrice C=A+B;</p>
<p><strong>Tipul</strong> unui obiect (şablon al obiectului) este o <strong>clasă</strong>. O clasă se caracterizează prin: numele clasei, atribute, funcţii şi relaţii cu alte clase.</p>
<p><strong>Instanţa</strong> este un obiect dintr-o clasă (A, B, C sunt obiecte, instanţe ale clasei matrice) şi are proprietăţile definite de clasă. Pentru o clasă definită, se pot crea mai multe instanţe ale acesteia. Toate obiectele au o <strong>stare</strong> şi un <strong>comportament</strong>. <strong><em>Starea</em></strong> unui obiect se referă la elementele de date conţinute în obiect şi la valorile asociate acestora (datele membre). <strong><em>Comportamentul</em></strong> unui obiect este determinat de care acţiunile pe care obiectul poate să le execute (metodele).</p>
<p><strong>Atributele </strong>specificate în definiţia unei clase <strong>descriu valoric proprietăţile</strong> obiectelor din clasă, sub diferite aspecte. Cele mai multe limbaje orientate obiect fac următoarea distincţie între atribute:</p>
<p>q  atribute ale clasei (au aceeaşi valoare pentru toate instanţele clasei);</p>
<p>q  atribute ale instanţei (variază de la o instanţă la alta, fiecare instanţă având propria copie a atributului).</p>
<p>În limbajul C++ atributele se numesc <strong>date membre</strong>. Toate datele membre sunt atribute instanţă. Atributele de clasă se pot obţine în cazul datelor membre statice (aceeaşi adresă de memorare pentru orice instanţă a clasei).</p>
<p><span id="more-198"></span></p>
<p><strong>Metode (funcţii membre)</strong>. La definirea unei clase se definesc şi metodele acesteia (numite şi funcţii membre). Fiecare obiect are acces la un set de funcţii care descriu operaţiile care pot fi executate asupra lui. Metodele pot fi folosite de instanţele clasei respective, dar şi de instanţele altor clase (prin mecanismul moştenirii).</p>
<p>Clasa conţine atât structurile de date necesare descrierii unui obiect, cât şi metodele care pot fi aplicate obiectului. Astfel, gradul de abstractizare este, mult mai ridicat, iar programele devin mult mai uşor de înţeles, depanat sau întreţinut.</p>
<p>&nbsp;</p>
<p>La crearea unui obiect, alocarea memoriei se poate fi face <em>static</em> sau <em>dinamic</em> (cu ajutorul unor funcţii membre speciale, numite <strong><em>constructori</em></strong>). Eliberarea memoriei se realizează cu ajutorul unor funcţii membre speciale, numite <strong><em>destructori</em></strong>, în momentul încheierii existenţei obiectului respectiv.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p align="center"><strong>9.3.  MOŞTENIREA</strong></p>
<p>&nbsp;</p>
<p>Moştenirea este o caracteristică a limbajelor de programare orientate obiect, care permite refolosirea codului şi extinderea funcţionalităţii claselor existente. Între două clase pot exista multe diferenţe, dar şi multe asemănări. Este bine ca informaţia comună unor clase să fie specificată o singură dată (conceptul de <strong><em>clasă/subclasă</em></strong>, <strong><em>superclas</em></strong><strong><em>ă</em></strong><strong><em>/clasă</em></strong> în OOP). Mecanismul moştenirii permite crearea unei ierarhii de clase şi trecerea de la clasele generale la cele particulare. Procesul implică la început definirea clasei de bază care stabileşte calităţile comune ale tuturor obiectelor ce vor deriva din bază (ierarhic superioară)(figura 9.1.). Prin moştenire, un obiect poate prelua proprietăţile obiectelor din clasa de bază.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><strong> </strong></p>
<p><strong> </strong></p>
<p>&nbsp;</p>
<p><strong>9.3.1.  MOŞTENIREA UNICĂ</strong></p>
<p>&nbsp;</p>
<p>În cazul moştenirii unice, fiecare clasă are doar o superclasă. Există <em>două modalităţi de specializare </em>a unei clase de bază<em>:</em></p>
<p>q  introducerea de<em> extra-atribute</em> şi<em> extra-metode</em> în clasa derivată (particulare doar clasei derivate);</p>
<p>q  <em>redefinirea membrilor </em>în clase derivate<em> (polimorfism).</em></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><strong>9.3.2.  MOŞTENIREA MULTIPLĂ</strong></p>
<p>&nbsp;</p>
<p>În situaţia moştenirii multiple, o clasă are mai multe superclase. Astfel, moştenirea clasei va fi multiplă (rezultând o structură de reţea).</p>
<table cellspacing="0" cellpadding="0" align="left">
<tbody>
<tr>
<td width="20" height="5"></td>
<td width="308"></td>
<td width="41"></td>
<td width="236"></td>
</tr>
<tr>
<td height="1"></td>
<td colspan="2"></td>
<td rowspan="2" align="left" valign="top"></td>
</tr>
<tr>
<td height="221"></td>
<td rowspan="2" align="left" valign="top"></td>
</tr>
<tr>
<td height="3"></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><em> </em></p>
<p><em> </em></p>
<p><em> </em></p>
<p><em> </em></p>
<p><em> </em></p>
<p><em> </em></p>
<p><em> </em></p>
<p><em> </em></p>
<p><em> </em></p>
<p><em> </em></p>
<p><em> </em></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>Moştenirea multiplă este utilă, dar poate crea <strong>ambiguităţi</strong> (când pentru acelaşi atribut se moştenesc valori diferite). Există mai multe <strong>strategii de rezolvare a conflictului</strong> (părintele cel mai apropiat, cel mai depărtat, etc.). Deasemenea, este posibilă o <strong>moştenire repetată</strong>, în care o clasă ajunge să moştenească de la aceeaşi clasă, pe drumuri diferite în reţea (vezi figura 9.3., în care clasa E moşteneşte de la aceeaşi clasă A, pe drumurile A-B-E, A-C-E) . Aşa cum vedea în capitolele următoare, în aceste situaţii, limbajul C++ oferă programatorului două strategii: 1) clasa E poate avea două copii ale lui A, una pentru fiecare drum; 2) clasa E are o singură copie, iar A este clasă virtuală de bază şi pentru C şi pentru B. Ideea moştenirii multiple poate duce la utilizarea unor <strong>clase pentru care nu există instanţe</strong>, care să ajute doar la organizarea structurii (reţelei) de moştenire. În plus, limbajul C++ permite un control puternic asupra atributelor şi metodelor care vor fi moştenite.</p>
<p><strong> </strong></p>
<p><strong> </strong></p>
<p align="center"><strong>9.4.  ÎNCAPSULAREA (ASCUNDEREA) INFORMAŢIEI</strong></p>
<p>&nbsp;</p>
<p>Încapsularea (ascunderea) informaţiei reflectă faptul că <strong>atributele instanţă ş</strong>i <strong>metodele</strong> unui obiect îl definesc doar pe acesta. Vom spune că metodele şi atributele unui obiect sunt “private”, încapsulate în obiect. Interfaţa cu obiectul relevă foarte puţin din ceea ce se petrece în interiorul lui. Obiectul deţine controlul asupra atributelor instanţă, care nu pot fi alterate de către alte obiecte. Excepţia de la această observaţie o reprezintă doar <em>atributele de clasă</em> care nu sunt încapsulate, fiind partajate între toate instanţele clasei. Această tehnică de &#8220;plasare&#8221; a valorilor în datele membre private ale obiectului, reprezintă un mecanism de ascundere a datelor.</p>
<p>&nbsp;</p>
<p>În limbajul C++ încapsularea poate fi forţată prin controlul accesului, deoarece toate datele şi funcţiile membre sunt caracterizate printr-un <strong>nivel de acces</strong> (rezultând astfel o mare flexibilitate). Nivelul de acces la membrii unei clase poate fi (figura 9.4.):</p>
<table cellspacing="0" cellpadding="0" align="left">
<tbody>
<tr>
<td width="1" height="9"></td>
</tr>
<tr>
<td></td>
<td bgcolor="white" width="318" height="227">
<table width="100%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>
<div>
<p>q  private: membrii (date şi metode) la care accesul este private pot fi accesaţi doar prin metodele clasei (nivel acces implicit);</p>
<p>q  protected: aceşti membri pot fi accesaţi prin funcţiile membre ale clasei şi funcţiile membre ale clasei derivate;</p>
<p>q  public: membrii la care accesul este public pot fi accesaţi din orice punct al domeniului de existenţă a  clasei respective;</p>
<p>q  friend: aceşti membri pot fi accesaţi prin funcţiile membre ale funcţiei prietene specificate.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
</div>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>În limbajul C++, nivelul de acces poate preciza şi tipul de moştenire (capitolul 12).</p>
<p>q  Publică, unde în clasa derivată nivelul de acces al membrilor este acelaşi ca în clasa de bază;</p>
<p>q  Privată, unde membrii protected şi public din clasa bază devin private în clasa derivată.</p>
<p align="center"><strong>9.5.  LEGAREA DINAMICĂ (“TÂRZIE”)</strong></p>
<p>&nbsp;</p>
<p>Obiectele unei clase părinte trebuie cunoscute în momentul compilării. Efectul combinat al moştenirii poate determina ca o anumită metodă să fie specializată diferit (prin redefinire), pentru subclase diferite. <strong>Polimorfismul</strong> reprezintă comportamente diferite ale unei metode în raport cu tipul unui obiect. Selectarea unei metode redefinite poate fi realizată în faza de compilare (legarea iniţială), sau în momentul execuţiei (legare târzie). În limbajul C++, legarea dinamică se poate realiza prin implementarea de:</p>
<p>q  funcţii virtuale (pot fi redefinite polimorfic);</p>
<p>q  funcţii virtuale pure (doar declarate, nu definite).</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p align="center"><strong>9.6.  ALTE ASPECTE</strong></p>
<p><strong> </strong></p>
<p>q  <strong>Comunicarea între obiecte</strong></p>
<p>În limbajele de programare orientate obiect, obiectele comunică între ele prin <strong><em>mesaje</em></strong>, ceea ce conduce la accentuarea conceptului de încapsulare. Un obiect poate “stimula” un altul să activeze (declanşeze) o metodă, trimiţându-i un mesaj. După primirea mesajului, metoda respectivă este apelată cu parametrii furnizaţi, asigurând comportarea corespunzătoare a obiectelor. Metodele sunt invocate prin <strong>trimiterea de mesaje.</strong></p>
<p>În limbajul C++ <strong>funcţiile membre (metodele) sunt accesate</strong> în mod similar oricarei funcţii, cu deosebirea că este necesară specificarea obiectului căruia îi corespunde metoda.</p>
<p>&nbsp;</p>
<p>q  <strong>Pseudovariabile</strong></p>
<p>Limbajele de programare orientate obiect posedă două variabile (numite pseudo-variabile) care diferă de variabilele normale prin faptul că nu li se pot atribui valori în mod direct, de către programator. În general, pseudovariabilele sunt o formă scurtă pentru “<strong><em>obiectul curent </em></strong>” şi pentru <strong><em>“clasa părinte a obiectului curent”</em></strong>. În limbajul C++ există doar una din aceste pseudovariabile, numită <strong>”this”</strong> (pointer către obiectul curent).</p>
<p><strong> </strong></p>
<p>q  <strong>Metaclasele</strong></p>
<p>Metaclasele reprezintă “clase de clase”. O clasă este, de fapt, o instanţă a unei metaclase. <em>Diferenţele</em> dintre clase şi metaclase sunt:</p>
<p>q  Clasa defineşte caracteristici (atribute şi metode) ale instanţelor de acel tip. Metodele pot fi folosite doar de obiectele clasei, nu şi de însăşi clasa (restricţie).</p>
<p>q  Metaclasele furnizează un mijloc prin care variabilele clasă pot fi implementate: în unele limbaje OOP, variabilele clasă sunt instanţieri ale unei metaclase.</p>
<p>&nbsp;</p>
<p>Limbajul C++ nu include explicit metaclasele, dar suportă <em>variabilele clasă</em> sub forma datelor <strong>statice</strong>. Aşa cum funcţiile membre obişnuite sunt încapsulate înăuntrul fiecarei instanţe, pentru o <strong><em>funcţie membru statică</em></strong> a unei clase, se foloseşte o singură copie, partajată de către toate instanţele clasei. O asemenea funcţie nu este asociată unei anumite instanţe.</p>
<p><strong> </strong></p>
<p>q  <strong>Persistenţa</strong></p>
<p>Persistenţa reprezintă <em>timpul de viaţă al unui obiect</em> (între crearea obiectului şi ştergerea sa). Instanţele unei clase au un timp de viaţă dat de execuţia unei metode sau a unui bloc, de crearea sau ştergerea specificată explicit în program sau de durata întregului program. Persistenţa obiectelor este importantă în special în aplicaţiile de baze de date.</p>
<p><strong> </strong></p>
<p>q  <strong>Supraîncarcarea operatorilor</strong>.</p>
<p>Limbajul C++ furnizează modalităţi de <em>supraîncarcare a operatorilor</em> <em>(overloading)</em>: acelaşi operator are semnificaţii diferite, care depind de numărul şi tipul argumentelor.</p>
]]></content:encoded>
			<wfw:commentRss>http://resurse-educationale.uv.ro/?feed=rss2&#038;p=198</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Structuri de date. Stive. Cozi. (Pascal)</title>
		<link>http://resurse-educationale.uv.ro/?p=183</link>
		<comments>http://resurse-educationale.uv.ro/?p=183#comments</comments>
		<pubDate>Thu, 04 Aug 2011 14:18:38 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Pascal]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[algoritmi]]></category>
		<category><![CDATA[extraşcolar]]></category>
		<category><![CDATA[informatică]]></category>
		<category><![CDATA[multime]]></category>
		<category><![CDATA[program]]></category>
		<category><![CDATA[programare]]></category>
		<category><![CDATA[programe rezolvate]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[tipuri de date]]></category>
		<category><![CDATA[units]]></category>

		<guid isPermaLink="false">http://resurse-educationale.uv.ro/?p=183</guid>
		<description><![CDATA[Stucturi de date 8.1 Noţiuni generale Orice algoritm lucrează cu date (numere întregi, reale, şiruri de caractere etc.). Referitor la acestea, în informatică, s-au cristalizat anumite concepte fundamentale, pe care le vom prezenta în continuare. Printr-un tip de dată  înţelegem &#8230; <a href="http://resurse-educationale.uv.ro/?p=183">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Stucturi de date</p>
<p>8.1 Noţiuni generale</p>
<p>Orice algoritm lucrează cu date (numere întregi, reale, şiruri de caractere etc.). Referitor la acestea, în informatică, s-au cristalizat anumite concepte fundamentale, pe care le vom prezenta în continuare.</p>
<p><em>Printr-un tip de dată  înţelegem o mulţime cu elemente numite valori.</em></p>
<p>Exemplu:{-32768, 32767, &#8230;&#8230;.0,1,&#8230;&#8230;..32767} este omulţime de numere întregi. Atunci cînd nu există posibilatea de confuzie, putem nota mulţimea de mai sus astfel: [-32768,32767]. Un element al acestei mulţimi este 7 (valoarea 7). În Turbo Pascal un astfel de tip se numeşte <em>integer</em>. Şi este predefinit (este cunoscut de limbaj, nu trebuie definit de programator).</p>
<p><em>Pe mulţimea valorilor unui tip se definesc operaţiile asociate tipului</em>.</p>
<p>Exemplu: Pentru tipul integer se definesc operaţiile de adunare, scădere, înmulţire etc.</p>
<p><em>Pentru fiecare tip se defineşte modul în care se valorile sale.</em></p>
<p>Exemplu: Pentru tipul <em>integer </em>valorile se memorizează utilizînd codul complementar şi se folosesc 2 octeţi consecutivi.</p>
<p>Pentru a lucra cu date de un anumit tip se folosesc variabile.</p>
<p>O <em>variabilă </em>se caracterizează prin: tip (natura datelor şi modul de memorare), nume (prin care aceasta se adresează) şi adresă (număr de ordine al primului octet în care se reţin datele, memoria internă fiind privită ca o succesiune de octeţi numerotaţi).</p>
<p>Tipuri de date pot fi <em>simple</em> (mulţimile care alcătuiesc nu sunt rezultate ca produs cartezian a altor mulţimi) şi <em>stucturate</em> în caz contrar. Exemplu:tipul <em>integer</em> este simplu, iar tipul <em>record</em> este structurat.</p>
<p>Limbajele de programare evoluate utilizează din plin tipurile de date. Mai mult, unele din ele permit programului, folosind tipurile existente, să definească noi tipuri de date. Limbajul Turbo Pascal este un exemplu în acest sens.</p>
<p><span id="more-183"></span></p>
<p><em>Noţiunea de tip de date este strânsă legată de un anumit limbaj de programare. În situaţia în care se renunţă la această legătură, se ajunge la o altă noţiune mult utilizată şi anume cea de structură de date</em>.</p>
<p>Exemplu: <em>Mulţimea</em> este o structură de date (după cum vom arăta). În limbajul Turbo Pascal există tipul mulţime (<em>set</em>). Alte limbaje (de exemplu C) nu cunosc acest tip. Aceasta nu înseamnă că în C nu vom putea lucra cu mulţimi. Sarcina noastră este să înţelegem structura de date numită mulţime şi să o implementăm în orice limbaj de programare dorim.</p>
<p>Un curs de algoritmi trebuie să fie independenţi de orice limbaj. Fapt că în aceasta lucrare algoritmii se implementează în Turbo Pascal nu înseamnă că ei pot fi folosiţi numai în acest limbaj. Din acest motiv, orice curs de algoritmi va utiliza noţiunea de <em>structură de date</em>.</p>
<p><em>Structurile de date</em> se clasifică în două mari categorii:statice şi dinamice.</p>
<p>Criteriul de clasificare este dat de modul de alocare a memoriei interne.</p>
<p><em>Astfel, pentru structurile statice memoria se alocă la începutul execuţiei programului şi rămăne alocată pînă cînd se încheie execuţia acestuia. Pentru structurile dinamice se alocă memorie în timpul execuţiei programului, iar cînd nu mai este necesară, memoria se eliberează</em>.Modalitatea prin care se poate realiza aceasta în Turbo Pascal va fi arătată chiar în acest capitol.</p>
<p>8.1.1 Structuri statice</p>
<p>Aceste structuri ne sunt deja binecunoscute. În acest capitol le vom prezenta în mod sistematic şi, pe cît posibil, formalizat.</p>
<p>1)  Tabloul</p>
<p>Fie Ani={1,2,….ni} mulţimea primelor ni numere naturale.</p>
<p>Fie M=An1 x An2  x…..x Ank   produsul cartezian a k astfel de mulţimi.</p>
<p><em>Se numeşte tablou o funcţie f:M→T, unde T este o mulţime oarecare.</em></p>
<p><em>Numărul k este dimensiunea tabloului. Dacă k=1 tabloul se mai numeşte şi vector. Vectorul are n</em><em>1</em><em> componente. Dacă k=2 tabloul se mai numeşte şi matrice. Matricea are n</em><em>1</em><em>xn</em><em>2</em><em> elemente.</em></p>
<p>Atenţie! Frecvent se confundă numărul componentelor cu dimensiunea tabloului.</p>
<p>De exemplu, despre un vector cu n componente se spune că este de dimensiune n (cînd, de fapt, toţi vectorii au dimensiunea 1).</p>
<p>Majoritatea limbajelor de programare evoluate au implementat tipul tablou (<em>array</em> <em>în Turbo Pascal</em>). Pentru a identifica elementele unui tablou se folosesc indici (aceştia sunt elemente ale produsului cartezian pe care este definită funcţia).</p>
<p>2)       Articolul</p>
<p>Fie A1, A2,….An n mulţimi finite. În general, natura elementelor acestor mulţimi poate fi diferită. De exemplu, A1 poate fi alcătuită din numere întregi, A2 poate fi alcătuită din caractere etc. Fie A=A1xA2x…xAn produsul cartezian  a celor n mulţimi. <em>Un articol reţine un element al mulţimii A. Un cîmp reţine un element al</em> mulţimii Ai. Majoritatea limbajelor de programare  evaluate  cunosc tipul structurat articol (<em>record</em> în Turbo Pascal). Oricare cîmp poate fi, la rîndul său, articol (<em>record</em> în <em>record</em>).</p>
<p>3)       Mulţimea</p>
<p>Fie A o mulţime finită. Ea poate fi privită ca o structură de date. Puţine dintre limbaje  (Turbo Pascal) admit chiar un tip de date numit mulţime (set). Însă şi aici numărul elementelor unei mulţimi nu poate fi mai mare decît 255 (avantajul este că sunt predefinite operaţiile cu mulţimi ). În ipoteza că programatorul doreşte să implementeze  algoritmi care lucrează cu mulţimi, indiferent de limbaj, se poate folosi <em>vectorul caracteristic</em>. Astfel , pentru o mulţime cu n elemente, orice submulţime a sa (v) va fi definită cu ajutorul unui vector cu n componente, în care fiecare componentă poate lua doar două valori 0 şi 1.</p>
<p>¥ i Є{1..n} avem v(i)=</p>
<p>În acest caz, este sarcina programatorului să stimuleze diversele operaţii cu mulţimi.</p>
<p>4)       Stiva alocată static</p>
<p>Structura de date numită <em>stivă </em>a fost prezentată şi este binecunoscută cititorului. Nu ne rămîne decît să precizăm faprul că, pînă acum, a fost impementată ca structură statică, cu ajutorul vectorilor . modul în care s-a realizat implementarea ne este clar, cu ajutorul unui vector (ST l-am numit) şi a unei variabile k (indică vîrful ei). Principalul dezavantaj al unei astfel de implementări este dat de faptul că, deşi ca structură de date nu are limitat numărul nivelelor (putem folosi oricîte), practice, numărul acestora nu poate fi mai mare decît numărul componentelor vectorului. Acest dezavantaj se reduce simţitor în cazul cînd în care stivă este implementată dinamic, însă, din cauza limitării memoriei interne, se menţine totuşi.</p>
<p>5)       Coada alocată static</p>
<p><em>Coada este acea structură de date în care toate înserările sunt făcute la unul din capetele cozii, iar toate ştergerile (în general, prelucrările) sunt făcute la celălalt capăt.</em></p>
<p>Este cu totul nerecomandabilă utilizarea vectorilor pentru stimularea cozii (alocarea statică). Facem această precizare deoarece, în această situaţie are loc un fenomen de migraţie a datelor de la dreapta la stînga în cadrul vectorului.</p>
<p>Să presupunem că stimulăm o coadă cu ajutorul unui vector cu zece componente, care reţin numere întregi. Presupunem de asemenea că niciodată în coadă nu vom mai avea mai  mult bde 4 elemente. Introducem în coadă numerele 1,2,3,4. pentru a avea unde să introducem şi alte completăm vectorul de la dreapta la stînga.</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="64" valign="top"></td>
<td width="64" valign="top"></td>
<td width="64" valign="top"></td>
<td width="64" valign="top"></td>
<td width="64" valign="top"></td>
<td width="64" valign="top"></td>
<td width="64" valign="top">4</td>
<td width="64" valign="top">3</td>
<td width="64" valign="top">2</td>
<td width="64" valign="top">1</td>
</tr>
</tbody>
</table>
<p>Dacă scoatem din coadă pe 1 şi introducem în coadă pe 5, coada va arăta astfel:</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="64" valign="top"></td>
<td width="64" valign="top"></td>
<td width="64" valign="top"></td>
<td width="64" valign="top"></td>
<td width="64" valign="top"></td>
<td width="64" valign="top">5</td>
<td width="64" valign="top">4</td>
<td width="64" valign="top">3</td>
<td width="64" valign="top">2</td>
<td width="64" valign="top"></td>
</tr>
</tbody>
</table>
<p>Scoatem din coadă pe 2 şi obţinem pe 6:</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="64" valign="top"></td>
<td width="64" valign="top"></td>
<td width="64" valign="top"></td>
<td width="64" valign="top"></td>
<td width="64" valign="top">6</td>
<td width="64" valign="top">5</td>
<td width="64" valign="top">4</td>
<td width="64" valign="top">3</td>
<td width="64" valign="top"></td>
<td width="64" valign="top"></td>
</tr>
</tbody>
</table>
<p>Se observă acest fenomen de migraţie a datelor, de la dreapta spre stînga.</p>
<p>O altă soluţie ar fi ca, după fiecare stocare de date din coadă, să deplasăm întregul şir de date cărte dreapta, însă în acest caz se consumă mult timp.</p>
<p><em>O soluţie mai bună de implementare a cozii este să folosim un vector pe care îl privim ca fiind &#8220;circular&#8221; (facem convenţia ca după ultima componentă să urmeze prima). Adresa componentei de început a cozii va fi reţinută de altă variabilă, iar adresa componentei de sfîrşit va fi reţinută de o altă variabilă. </em>Un astfel de procedeu poate fi folosit, dar nu este recomandabil atît timp cît există alocarea dinamică a memoriei (aşa se lucra prin anii 70, când limbajele &#8220;la modă&#8221; <em>Fortan</em> şi <em>Cobol</em> nu putea aloca memoria dinamic).</p>
<p>Din cele prezentate nu rezultă în nici un fel la ce foloseşte această structură de date. Deşi are numeroase utilizări (rol fundamental în informatică) pentru moment nu putem da exemple (ne lipsesc condiţiile necesare). Vezi parcurgerea în lăţime a arborilor oarecare.</p>
<p>8.1.2. Alocarea dinamică a memoriei în Turbo Pascal</p>
<p>Din punct de vedere al unui programator, memoria calculatorului se prezintă ca o succesiune de octeţi, fiecare octet avînd o adresă binară bine stabilită. Aceşti octeţi sunt identificaţi prin numere cuprinse între 0 şi n-1. convenim să numim adresă numărul de ordine al unui octet. Un octet este format din 8 biţi. Fiecare bit poate memora fie cifra binară 1, fie cifra binară 0, diversele tipuri de date cunoscute pînă acum (INTEGER, REAL) ocupă 2 sau mai mulţi octeţi consecutive. Pentru fiecare tip de dată cunoscut există o anumită logică potrivit căreia se face memorarea efectivă a conţinutului. De exemplu, pentru tipul INTEGER memorarea se face în COD COMPLEMENTAR. Nu ne propunem să prezentăm modul de reprezintare a datelor. Ne mărginim numai să atragem atenţia că o variabilă folosită de noi în program are un nume (simbolic), o valoare şi o adresă la care o găsim memorată (adresa primului octet din cei <em>p</em> octeţi consecutive ocupaţi de variabilă). În general, în limbajele evaluate nu este necesar ca programatorul să cunoască adresa la care se găsesc variabilele cu care lucrează.</p>
<p>Se cunosc două forme de alocare a memoriei de către programator în cadrul limbajului PASCAL: statică şi dinamică.</p>
<ul>
<li>Utilizînd forma de alocare statică, variabilele se declară utilizînd cuvîntul cheie VAR la începutul programului.</li>
<li>Utilizînd forma de alocare dinamică, în timpul rulării programului, în funcţie de necesităţi, se alocă memorie suplimentară sau se renunţă la ea.</li>
</ul>
<p>Pentru alocarea dinamică utilizăm tipul de date referinţă. Se consideră secvenţa de program:</p>
<p>type  ref=^inr;</p>
<p>inr=record</p>
<p>nr:integer;</p>
<p>adrurm:ref</p>
<p>end;</p>
<p>var c:ref;</p>
<p>Aici variabila c este o variabilă de tip referinţă. Ea reţine adrese de înregistrări. La rîndul ei, o înregistrare are două cîmpuri: nr, care conţine un număr întreg (informaţia utilă) şi adrurm (adresa următoare), care conţine adresa unei alte înregistrări.</p>
<p>Procedura NEW (c) rezervă spaţiu (un număr de octeţi cosecutivi) pentru o înregistrare, adresa primului octet fiind depusă în variabila c. Presupunem că variabila c conţine adresa unei înregistrări.</p>
<p>Procedura DISPOSE (c) eliberează spaţiul de memorie afectat acelei înregistrări care avea adresa în c. Cuvîntul cheie NIL are semnificaţia &#8221; nici o adresă&#8221;.</p>
<p><em>Observaţii:</em></p>
<p>1)    c se referă la adresa care se găseşte în variabila c;</p>
<p>2)    c^.nr se referă la cîmpul numeric al înregistrării care are adresa memorată în variabil c;</p>
<p>3)    c^.adrurm semnifică adresa de înregistrare care se găseşte memorată în cadrul înregistrării care are adresa c;</p>
<p>4)    c^.adrurm.nr  semnifică variabila <em>nr </em>care se găseşte în înregistrarea care care adresa plasată în cîmpul <em>adrurm </em>al înregistrării cu adresa c.</p>
<p>Observaţie foarte importantă: spaţiul necesar variabilelor alocate dinamic se rezervă într-o zonă de memorie, special destinată numită <em>HEAP</em> (<em>pentru PC compatibile i.B.M.).</em></p>
<p><strong>8.2 Structuri dinamice</strong>.</p>
<p>8.2.1 Listă liniară simplu înlănţuită</p>
<p>O listă liniară simplu înlănţuită este o structură de forma:</p>
<p>adr1                                                   adr2                                                                       adrn</p>
<p>Semnificaţia notaţiilor folosite este următoarea:</p>
<ul>
<li> adr1, adr2,…,adrn reprezintă adresele din memorie ale celor <em>n</em> înregistrări;</li>
<li>in1, in2,…, inn reprezintă informaţiile utile din cele <em>n</em> înregistrări (altele decît cele de adresă pentru înregistrarea următoare ).</li>
</ul>
<p>Denumirea &#8220;simplu înlănţuită&#8221;  provine din faptul că fiecare element  al listei conţine o singură adresă, şi anume adresa elementului următor din listă. Aici avem o excepţie pentru ultimul element, care are în cîmpul de adresă cuvîntul cheie  NIL (semnificînd &#8220;nici o adresă&#8221;). Operaţiile pe care le putem face în legătură cu această structură de date sunt următoarele:</p>
<p>1)    creare;</p>
<p>2)    listare;</p>
<p>3)    adăugare;</p>
<p>4)    ştergere;</p>
<p>În programul care urmează aceste operaţii sunt realizate de   procedurile cu acelaşi nume (facem precizarea că, în program, informaţiile utile sunt date de numere 1,2,…,n). Am recurs la această cale din dorinţa de a simplifica pe cît posibil prezentarea.</p>
<p><strong><em>1) </em></strong><em>Creare</em></p>
<p>Se cere numărul n de înregistrări. Se creează o primă înregistrare avînd ca informaţie utilă numărul 1. Variabila <em>b</em> de tip referinţă reţine adresa primei înregistrări din listă. Pentru fiecare <em>i</em> cuprins între 2 şi n se adaugă cite o nouă înregistrare listei. Variabila <em>d</em> reţine adresa ultimei înregistrări deja create pentru a-i completa cîmpul de adresă. Se procedează astfel pentru că în momentul în care am creat o înregistrare nu se cunoaşte adresa înregistrării care urmează.</p>
<p><strong><em>2) </em></strong><em>Listare </em></p>
<p><em> </em>Am precizat faptul că <em>b</em> reţine adresa primei înregistrări. Pentru a nu deteriora această valoare, o vom memora în variabila <em>c</em> . Atît timp cît nu am ajuns  la sfîrşitul listei, tipărim informaţia utilă şi încărcăm  în <em>c</em> adresa înregistrării următoare.</p>
<p><strong><em>3) </em></strong><em>Adăugare </em></p>
<p>Operaţia de adăugare a unui nou element la listă comportă cunoaşterea a două informaţii:</p>
<ul>
<li>Informaţia utilă a elementului (înregistrării) din listă după care urmează  să se facă adăugarea;</li>
<li>Informaţia utilă a elmentului care urmează să fie adăugat.</li>
</ul>
<p>Adăugarea propriu-zisă constă în următoarele:</p>
<ul>
<li>Poziţionarea pe înregistrarea  după care urmează să adăugăm noua înregistrare;</li>
<li>Alocarea spaţiului pentru noua înregistrare;</li>
<li>Completarea informaţiei utile pentru aceasta;</li>
<li>Completarea adresei următoare a noii înregistrări, care va fi adresa următoare a înregistrării pe care suntem poziţionaţi;</li>
<li>Cîmpul de adresă al înregistrării pe care suntem poziţionaţi va lua ca valoare adresa noii înregistrări.</li>
</ul>
<p><em>Observaţie</em>:</p>
<p>- Aşa cum este concepută procedura, nu se poate adăuga  o primă înregistrare listei. Propunem ca exerciţiu modificarea ei în acest sens.</p>
<p>4) <em>Ştergerea</em></p>
<p>Pentru a şterge o înregistrare este necesar  să cunoaştem informaţia utilă</p>
<p>a acesteia. Vom proceda în mod diferit pentru situaţiile în care se şterge  prima înregistrare sau una diferită de prima.</p>
<p>În cazul în care ştergem prima înregistrare, efectuăm operaţiile:</p>
<ul>
<li>Se salvează în variabila <em>c</em> adresa primei înregistrări (cea care urmează a fi ştearsă);</li>
<li>Variabila <em>b</em> (care reţine adresa primei înregistrări) va lua ca valoare adresa următoare primei înregistrări;</li>
<li>Se eliberează spaţiul rezervat înregistrării şterse;</li>
</ul>
<p>În situaţia în care ştergem o altă înregistrare decît prima, procedăm în felul următor:</p>
<ul>
<li>Se face poziţionarea pe înregistrarea care urmează a fi ştearsă;</li>
<li>Cîmpul  de adresă al înregistrării precedente capătă valoarea cîmpului de adresă al înregistrării curente;</li>
<li>Eliberăm spaţiul rezervat înregistrării curente.</li>
</ul>
<p>program 11n;</p>
<p>type ref=^inr;</p>
<p>inr=record</p>
<p>nr:integer;</p>
<p>adrurm:ref</p>
<p>end;</p>
<p>var b,c,d:ref;</p>
<p>n,i: integer;</p>
<p>procedure creare;</p>
<p>begin</p>
<p>write (‘n=’); readln(n);</p>
<p>new ( c); c^.nr:=1;</p>
<p>b:=c; d:=c;</p>
<p>for i:=2 to n do</p>
<p>begin</p>
<p>new ( c);</p>
<p>c^.nr:=i;</p>
<p>d^.adrurm:=c;</p>
<p>d:=c</p>
<p>end;</p>
<p>procedure listare;</p>
<p>begin</p>
<p>c:=b;</p>
<p>while c&lt; &gt;nil do</p>
<p>begin</p>
<p>writeln( c^.nr);</p>
<p>c:=c^.adrurm</p>
<p>end</p>
<p>end;</p>
<p>procedure ştergere;</p>
<p>begin</p>
<p>write (‘i=’); readln(i);</p>
<p>if  i=1 then</p>
<p>begin</p>
<p>c:=b;</p>
<p>b:=b^.adrurm;</p>
<p>dispose (c)</p>
<p>end</p>
<p>else</p>
<p>begin</p>
<p>c:=b;</p>
<p>while  c^.nr&lt; &gt;i do</p>
<p>begin</p>
<p>d:=c;</p>
<p>c:=c^.adrurm</p>
<p>end;</p>
<p>d^.adrurm:=c^.adrurm;</p>
<p>dispose ( c)</p>
<p>end</p>
<p>end;</p>
<p>procedure adăugare;</p>
<p>begin</p>
<p>write(‘i=’); readln(i);</p>
<p>write(‘n=’); readln(n);</p>
<p>c:=b;</p>
<p>while c^.nr&lt; &gt;i do c:=c^.adrurm;</p>
<p>new (d );</p>
<p>d^.nr:=n;</p>
<p>d^.adrurm:=c^.adrurm;</p>
<p>c^.adrurm:=d</p>
<p>end;</p>
<p>begin</p>
<p>creare;</p>
<p>listare;</p>
<p>adăugare;</p>
<p>listare;</p>
<p>ştergere;</p>
<p>listare</p>
<p>end.</p>
<p>În continuare ne propunem să construim şi să tipărim o listă liniară simplu înlănţuită, utilizînd tehnici recursive.</p>
<p>Funcţia <em>lista</em> are sarcina de a construi lista liniară înlănţuită. La început se cere informaţia utilă. În situaţia în care aceasta este diferită de 0 (valoare care semnifică faptul  că nu mai avem de adăugat nici un element), se rezervă un spaţiu pentru noua înregistrare, se completează informaţia utilă, iar cîmpul <em>adrurm</em> va lua valoarea funcţiei  de tip <em>lista</em> care se autoapelează. În încheiere <em>lista </em>va lua valoarea <em>c </em>a cîmpului care reţine adresa noului element.</p>
<p>Este interesant să observăm că iniţial se creează lista simplu înlănţuită fără a completa cîmpul <em>adresa</em>, această completare urmînd să se facă la revenirea în procedură.</p>
<p>Să ne imaginăm că rulînd acest program dorim să creăm o listă cu două înregistrări care au informaţiile  utile 1 şi 2.</p>
<p>Rularea decurge astfel:</p>
<ul>
<li>Apelăm procedura;</li>
<li>Citim valoarea lui <em>n</em> şi anume 1;</li>
<li>Se alocă spaţiu pentru prima înregistrare;</li>
<li>Completăm informaţia utilă;</li>
<li>Pentru a completa adresa următoare înregistrării curente, se apelează din nou funcţia;</li>
<li>Citim valoarea lui <em>n</em> şi anume 2;</li>
<li>Alocăm spaţiu pentru a doua înregistrare;</li>
<li>Completăm informaţia utilă cu 2;</li>
<li>Se apelează din nou funcţia;</li>
<li>Se citeşte 0;</li>
<li>Funcţia ia valoarea NIL;</li>
<li>Se revine din apel şi se continuă de acolo de unde am rămas;</li>
<li>Cîmpul de adresă al celei de a doua înregistrări va lua valoarea NIL;</li>
<li>Funcţia capătă valoarea adresei înregistrării 2,</li>
<li>Se revine din apel;</li>
<li>Cîmpul de adresă al primei înregistrări ia valoarea celei de-a doua înregistrări;</li>
<li>Funcţia ia  valoarea adresei primei înregistrări;</li>
<li>Se revine în programul principal.</li>
</ul>
<p>Observăm că valoarea variabilei <em>c</em> a programului principal va fi după rulare adresa primei înregistrări.</p>
<p>Propunem ca exerciţiu construirea listei utilizînd o procedură recursivă. Putem defini recursiv lista astfel:</p>
<ul>
<li>O mulţime vidă de înregistrări este o listă;</li>
<li>Dacă la o listă se adaugă o înregistrare, se obţine o listă.</li>
</ul>
<p>Recursiv putem tipări informaţia utilă din listă în două moduri:</p>
<ul>
<li>În ordinea în care a fost creată;</li>
<li>În ordinea inversă celei în care a fost creată.</li>
</ul>
<p>Lăsăm pe seama cititorului analiza acestor două proceduri.</p>
<p>program 11r;</p>
<p>type ref=^inr;</p>
<p>inr=record</p>
<p>nr:integer;</p>
<p>adrurm:ref</p>
<p>end;</p>
<p>var n:integer;</p>
<p>c:ref;</p>
<p>function lista:ref;</p>
<p>var c:ref;</p>
<p>begin</p>
<p>write(‘n=’); readln(n);</p>
<p>if n&lt; &gt;0</p>
<p>then</p>
<p>begin</p>
<p>new(c);</p>
<p>c^.nr:=n;</p>
<p>c^.adrurm:=lista;</p>
<p>lista:=c;</p>
<p>end</p>
<p>else lista:nil</p>
<p>end;</p>
<p>procedure tipard(c:ref);</p>
<p>begin</p>
<p>if c&lt; &gt;nil</p>
<p>then</p>
<p>begin</p>
<p>writeln(c^.nr);</p>
<p>tipard (c^.adrurm)</p>
<p>end</p>
<p>end;</p>
<p>procedure tipari(c:ref);</p>
<p>begin</p>
<p>if c&lt; &gt; nil tfen</p>
<p>begin</p>
<p>tipari (c^.adrurm);</p>
<p>writeln(c^.nr)</p>
<p>end</p>
<p>end;</p>
<p>begin</p>
<p>c:=lista;</p>
<p>tipard©;</p>
<p>writeln(‘&#8212;&#8212;&#8212;&#8212;’);</p>
<p>tipari©</p>
<p>end.</p>
<p>Aplicaţie (Sortare topologică)</p>
<p><em>Presupunem că dorim sortarea numerelor. 1, 2, &#8230;.., n, numere care se găsesc într-o ordine oarecare, alta decît naturală. Pentru a afla relaţia în care se găsesc numerele, introducem un număr finit de perechi (i,j). O astfel de pereche ne spune că, în relaţia de ordine considerată, i se află înaintea lui j.</em></p>
<p><em><span style="text-decoration: underline;">Exemplu 1</span></em><em>: </em>n=3 şi citim perechile (3,1) şi (3,2). Numărul 3 se află înaintea lui1 şi 3 se află înaintea lui 2. Apar două soluţii posibile: 3,1,2 şi 3,2,1, întucît nu avem nici o informaţie asupra relaţiilor dintre 1şi 2. Tragem de aici concluzia că o astfel de problemă poate avea mai multe soluţii.</p>
<p><em><span style="text-decoration: underline;">Exemplu 2</span></em>: n=3 şi citim (1,2), (2,3), (3,1). În acest caz nu avem soluţie.di primele două relaţii rezultă că ordinea ar fi 1,2,3 iar a-3-a contrazice această ordine.</p>
<p>În concluzie, problema ar avea sau nu soluţie, iar dacă are poate fi sau nu unică.</p>
<p>Algoritmul pe care îl prezentăm în continuare furnizează o singură soluţie atunci cînd problema admite soluţii. În caz contrar specifică faptul că problema nu admite soluţie.</p>
<p>Vom exemplifica funcţionarea algoritmului pe exemplu următor: n=4 şi se citesc perechile (3,4), (4,2), (1,2), (3,1).</p>
<p>Pentru fiecare număr între 1 şi <em>n </em>trebuie să avem următoarele informaţii:</p>
<ul>
<li>Numărul predecesorilor săi;</li>
<li>Succesorii săi;</li>
</ul>
<p>Pentru aceasta folosi doi vectori:</p>
<ul>
<li><em> contor</em>, vector care reţine numărul predecesorilor fiecărui <em>k</em>, cu <em>k </em><em>Є </em><em>{1..n}.</em></li>
<li><em>a</em>, care reţine adresele de început ale listelor de succesori ai fiecărui element.</li>
</ul>
<p>Pentru fiecare element există o listă simplu înlănţuită a succesorulor săi. Fiecare înregistrare din aceste liste conţine două elemente:</p>
<ul>
<li>succesorul;</li>
<li>adresa următorului element din listă.</li>
</ul>
<p>Iniţial, în dreptul fiecărui element în vectorul „contor” se trece 0, iar în vectorul „a” se trece NIL.</p>
<p>Citirea unei perechi (i,j) înseamnă efectuarea următoarelor operaţii:</p>
<ul>
<li>mărirea cu 1 a cîmpului <em>contor (j)</em> (j are un predecesor, şi anume pe i);</li>
<li>adăugarea lui <em>j </em>la lista succesorului lui <em>i.</em></li>
</ul>
<p>Pentru exemplu nostru, lucrurile decurg astfel:</p>
<p>CONTOR</p>
<p>A</p>
<p>În continuare se procedează astfel:</p>
<ul>
<li>toate elementele au 0 în cîmpul lui <em>contor</em> se reţine într-un vector <em>c;</em></li>
<li>pentru fiecare element al vectorului <em>c</em> se procedează astfel:
<ul>
<li>se tipăreşte;</li>
<li>se marchează cu -1 cîmpul său de contor;</li>
<li>pentru toţi succesorii săi (aflaţi în lista succesorilor) se scade cu 1 din cîmpul <em>contor</em> (este normal, întrucît aceştia au un predecesor mai puţin).</li>
<li>Se reia algoritmul dacă nu este îndeplinită una din condiţiile următoare:</li>
</ul>
</li>
</ul>
<p>v   Au fost tipărite toate elementele, caz în care algoritmul se încheie cu succes;</p>
<p>v   Nu avem nici un element cu 0 în cîmpul <em>contor</em>, caz în care relaţiile au fost incoerente.</p>
<p>.</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="51" valign="top">1</td>
<td width="51" valign="top">2</td>
<td width="51" valign="top">-1</td>
<td width="51" valign="top">0</td>
</tr>
<tr>
<td width="51" valign="top">al1</td>
<td width="51" valign="top">nil</td>
<td width="51" valign="top">al3</td>
<td width="51" valign="top">al4</td>
</tr>
<tr>
<td width="51" valign="top">2</td>
<td width="51" valign="top"></td>
<td width="51" valign="top">4</td>
<td width="51" valign="top">2</td>
</tr>
</tbody>
</table>
<p>tipăresc 3, scad 1 din predecesorii lui 4 şi 1, cu -1 contorul lui 3;</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="50" valign="top">0</td>
<td width="50" valign="top">1</td>
<td width="50" valign="top">-1</td>
<td width="50" valign="top">-1</td>
</tr>
<tr>
<td width="50" valign="top"></td>
<td width="50" valign="top"></td>
<td width="50" valign="top"></td>
<td width="50" valign="top"></td>
</tr>
</tbody>
</table>
<p><em><span style="text-decoration: underline;">Observaţie:</span></em></p>
<p>Algoritmul are mai multe aplicaţii, ca de exemplu:</p>
<ul>
<li>Ordonarea unor activităţi, atunci cînd ele sunt condiţionate una după alta;</li>
<li>Ordonarea unor termeni care se cer explicaţi pentru a-i putea explica prin alţi deja prezentaţi.</li>
</ul>
<p>Program stoop;</p>
<p>type ref=^inr;</p>
<p>inr=record</p>
<p>succ:integer;</p>
<p>urm:ref</p>
<p>end;</p>
<p>vector=array [1..100] of integer;</p>
<p>vectad=array [1..100]of ref;</p>
<p>var n, m, i, j, k:integer;</p>
<p>contor, c:vector;</p>
<p>a:vectad;</p>
<p>gasit:boolean;</p>
<p>procedure adaug  (i,j:integer);</p>
<p>var c,d:ref;</p>
<p>begin</p>
<p>contor [j]:=contor [j]+1;</p>
<p>c:=a[i];</p>
<p>new (d);</p>
<p>d^.urm:=nil;</p>
<p>d^.succ:=j;</p>
<p>if c=nil</p>
<p>then a[i]:=d</p>
<p>else</p>
<p>begin</p>
<p>while c^.urm&lt; &gt;nil do c:=c^.urm;</p>
<p>c^.urm:=d</p>
<p>end</p>
<p>end;</p>
<p>procedure actual (i:integer);</p>
<p>var c:ref;</p>
<p>begin</p>
<p>c:=a[i];</p>
<p>while c &lt; &gt;nil do</p>
<p>begin</p>
<p>contor [c^.succ]:=contor[c^.succ]-1;</p>
<p>c:=c^.urm</p>
<p>end</p>
<p>end;</p>
<p>begin</p>
<p>write (’n=’); readln(n);</p>
<p>for i:=1 to n do</p>
<p>begin</p>
<p>contor [i]:=0;</p>
<p>a[i]:=nil</p>
<p>end;</p>
<p>while i&lt; &gt;0 do</p>
<p>begin</p>
<p>write (’tastati i,j=’);</p>
<p>readln (i,j);</p>
<p>if i&lt; &gt;0 then adaug (i,j)</p>
<p>end;</p>
<p>m:=n;</p>
<p>repeat</p>
<p>k:=1;</p>
<p>gasit:false;</p>
<p>for i:=1 to n do if contor [i]=0</p>
<p>then</p>
<p>begin</p>
<p>gasit:=true;</p>
<p>m:=m-1;</p>
<p>c[k]:=1;</p>
<p>k:=k+1;</p>
<p>contor [i]:=-1</p>
<p>end;</p>
<p>for i:=1 to k-1 do</p>
<p>begin</p>
<p>actual (c[i]);</p>
<p>writeln (c[i]);</p>
<p>end;</p>
<p>until (not gasit) or (m=0);</p>
<p>if m=0</p>
<p>then writeln (’totul e ok’)</p>
<p>else writeln (’relatii contradictorii’)</p>
<p>end.</p>
<p>8.2.2 Lista liniară dublu înlănţuită</p>
<p>O listă dublu înlănţuită este o structură de date de forma:</p>
<p>adr1                                                           adr2                                                            adrn</p>
<p>Operaţiile pe care le putem face cu o listă dublu înlănţuită sunt următoarele:</p>
<p>1)    Creare;</p>
<p>2)    Adăugare la dreapta;</p>
<p>3)    Adăugare la stînga;</p>
<p>4)    Adăugare în interiorul listei;</p>
<p>5)    Ştergere din interiorul listei;</p>
<p>6)    Ştergere la sînga listei;</p>
<p>7)    Ştergere la dreapta listei;</p>
<p>8)    Listare de  la sînga la dreapta;</p>
<p>9)    Listare de la dreapta  la sînga;</p>
<p>1)    Creare</p>
<p>O listă dublu înlănţuită se creează cu o singură înregistrare. Pentru a ajunge la numărul de înregistrări dorit, utilizăm proceduri de adăugare la stînga sau la dreapta. În programul de faţă acest lucru este realizat de procedura creare. Această procedură realizează operaţiile următoare:</p>
<ul>
<li>Citirea informaţiei utile;</li>
<li>Completarea înregistrării cu informaţia utilă;</li>
<li>Completarea adreselor de legătură la stînga şi la dreapta cu NIL;</li>
<li>Variabilele tip referinţă <em>b </em>şi <em>s</em> vor căpăta valoarea adresei acestei prime înregistrări (b semnfică adresa înregistrării cea de mai din stînga, s adresa ultimei înregistrări din dreapta).</li>
</ul>
<p>2) Adăugarea la dreapta</p>
<p>Această operaţie este realizată de procedura <em>addr</em>. Pentru adăugarea unei înregistrări se realizează următoarele operaţii:</p>
<ul>
<li>Citirea informaţiei utile;</li>
<li>Alocarea spaţiului pentru înregistrare;</li>
<li>Completarea adresei la dreapta cu NIL;</li>
<li>Completarea adresei din stînga şcu adresa celei mai din dreapta înregistrări (reţinute în variabila <em>s</em>);</li>
<li>Modificare cîmpului de adresă la dreapta a înregistrării din <em>s</em> cu adresa noii înregistrări;</li>
<li><em>s </em>va lua valorile noi înregistrări, deoarece va fi cea mai din dreapta.</li>
</ul>
<p><em> </em></p>
<p>3)    Adăugarea la stînga</p>
<p>Această operaţie o propunem ca exerciţiu.</p>
<p>4)    Adăugare în interiorul listei</p>
<p>Această operaţie este realizată de procedura <em>includ</em>, care realizează următoarele operaţii:</p>
<p>ü Parcurge lista de la stînga la dreapta căutînd înregistarea cu informaţia utilă <em>m</em>, în dreapta căreia urmează să introducem noua înregisrare;</p>
<p>ü Citeşte informaţia utilă;</p>
<p>ü Alocă spaţiu pentru noua înregistrare;</p>
<p>ü Completează informaţia utilă;</p>
<p>ü Adresa stîngă a noii înregistrări ia valoarea adresei înregistrării de informaţie utilă <em>m</em>;</p>
<p>ü Adresa dreaptă a noii înregistrări ia valoarea adresei dreapta a înregistrării de informaţia utilă <em>m</em>;</p>
<p>ü Adresa dreaptă a înregistrării cu informaţia utilă <em>m</em> ia valoarea noii înregistrări;</p>
<p><em><span style="text-decoration: underline;">Observaţie:</span></em></p>
<p>Propunem ca exerciţiu realizarea unei proceduri de adăugare în interiorul listei a unei înregistrări la dreapta înregistrării cu informaţia utilă <em>m.</em></p>
<p><em> </em></p>
<p>5)    Ştergere din interiorul listei</p>
<p>Această operaţie este realizată de procedura <em>sterg</em>. Operaţiile efectuate de această procedură următoarele:</p>
<p>ü Se parcurge lista de la stînga la dreapta pentru a ne poziţiona pe înregistrarea care urmează a fi ştearsă;</p>
<p>ü Cîmpul de adresă dreapta al înregistrării care o precede pe această şi va lua valoarea cîmpului de adresă dreapta al înregistrării care va fi ştearsă;</p>
<p>ü  Cîmpul de adresă stînga al înregistrării care urmează înregistrării care va fi ştearsă va lua valoarea cîmpului de adresă stînga al înregistrării pe care o ştergem;</p>
<p>ü Se eliberează spaţiul de memorie rezervat înregistrării care se şterge.</p>
<p>6)-7) Ştergere la sînga şi la dreapta  listei</p>
<p>Aceste două operaţii sunt propuse cititorului ca exerciţiu.</p>
<p>8) Listare de  la sînga la dreapta</p>
<p>Această operaţie este realizată de procedura <em>listare</em>, procedură care realizează următoarele operaţii:</p>
<p>v Porneşte din stînga listei;</p>
<p>v Atît timp cît nun s-a ajuns la capătul din dreapta al listei, se tipăreşte informaţia utilă şi se trece la înregistrarea următoare.</p>
<p>9)    Listare de la dreapta  la sînga</p>
<p>O propunem ca exerciţiu.</p>
<p>Program 1di;</p>
<p>type ref=^inr;</p>
<p>inr=record</p>
<p>as:ref;</p>
<p>nr:integer;</p>
<p>ad:ref</p>
<p>end;</p>
<p>var b,s,c:ref;</p>
<p>n,m,i:integer;</p>
<p>procedure creare (var b,s:ref);</p>
<p>begin</p>
<p>write (‘n=’); readln (n);</p>
<p>new (b); b^.nr:=n;</p>
<p>b^.as:=nil; b^.ad:=nil;</p>
<p>s:=b</p>
<p>end;</p>
<p>procedure addr (var s:ref);</p>
<p>var  d:ref;</p>
<p>begin</p>
<p>write (‘n=’); readln (n);</p>
<p>new (d); d^.nr:=n;</p>
<p>d^.as:=s; d^.ad:=nil;</p>
<p>s^.ad:=d; s:=d</p>
<p>end;</p>
<p>procedure listare (b:ref);</p>
<p>var d:ref;</p>
<p>begin</p>
<p>d:=b;</p>
<p>while d&lt; &gt;nil do</p>
<p>begin</p>
<p>writeln (d^.nr);</p>
<p>d:=d^.ad</p>
<p>end</p>
<p>end;</p>
<p>procedure include (m:integer; b:ref);</p>
<p>var d,e:ref;</p>
<p>begin</p>
<p>d:=b;</p>
<p>while d^.nr&lt; &gt;m do d:d^.ad;</p>
<p>write (‘n=’); readln (n);</p>
<p>new (e);</p>
<p>e^.nr:=n;</p>
<p>e^.as:=d;</p>
<p>d^.ad^.as:=e;</p>
<p>e^.ad:=d^.ad;</p>
<p>d^.ad:=e</p>
<p>end;</p>
<p>procedure sterg (m:integer; b:ref);</p>
<p>var d:ref;</p>
<p>begin</p>
<p>d:=b;</p>
<p>while d^.nr&lt; &gt;m do d:=d^.ad;</p>
<p>d^.as^.ad:=d^.ad;</p>
<p>d^.ad^.as:=d^.as;</p>
<p>dispose (d)</p>
<p>end;</p>
<p>begin</p>
<p>writeln (‘creare lista cu o singura inregistrare’);</p>
<p>creare (b, s);</p>
<p>write (‘cite inregistrari se adauga?’);</p>
<p>readln (m);</p>
<p>for i:=1 to m do addr (s);</p>
<p>writeln (‘acum listez de la stinga la dreapta’);</p>
<p>listare (b);</p>
<p>writeln (‘includem la dreapta o inregistrare’);</p>
<p>write (‘dupa care inregistrare se facec includerea?’);</p>
<p>readln (m);</p>
<p>include (m,b);</p>
<p>writeln (‘acum listez de la stinga la dreapta’);</p>
<p>listare (b);</p>
<p>writeln (‘Acum stergem o inregistrare din interior’);</p>
<p>write (‘Ce inregistrare stergem?’);</p>
<p>readln (m);</p>
<p>sterg (m,b);</p>
<p>writeln (‘Acum  listez de la stinga la dreapta’);</p>
<p>listare (b)</p>
<p>end.</p>
<p>8.2.3 Lista circulară</p>
<p><em>Se consideră o listă liniară. Dacă, ultima înregistrare, adresa următoare va fi înregistrării, am definit o listă circulară. În cazul în care lista iniţială este simplu înlănţuită, listă circulară va fi simplu înlănţuită, iar dacă listă iniţială este dublu înlănţuită şi lista ciculară va fi dublu înlănţuită.</em></p>
<p>Întucît operaţiile care se efectuează cu aceasta sunt asemănătoare cu cele prezente anterior, ne oprim cu explicaţiile în acest punct.</p>
<p>8.2.4 Stiva</p>
<p><em>O stivă poate fi definită şi ca o listă liniară  simplu înlănţuită în care toate intrările şi ieşirile se fac la un singur capăt al ei.</em></p>
<p>În acest caz, elementul de pe nivelul <em>k</em> al stivei va reţine adresa elementului de pe nivelul <em>k-1</em>.</p>
<p>În versiunile anterioare ale acestei cărţi am prezentat stiva ca  fiind o listă liniară <em>dublu înlănţuită</em>, fapt pentru care am fost criticat. Motivul? Prezentînd stiva ca o listă dublu înlănţuită, am avantajul că o pot folosi în mai multe aplicaţii (de exemplu, pentru backtracking, unde pentru a valida un element era necesară comparaţia sa cu cele aflate în stivă pe nivelele inferioare). Desigur, chiar folosind pentru stiva actuala definiţie (prezentă în toate lucrările de specialitate) putem realiza toate aplicaţiile făcute pînă în acest moment, însă mai greu (recursiv, cu pierdere de timp). Chiar modul de lucru standart cu stiva calculatorului (în limbaj de asamblare) permite accesul la elemente ale stivei care nu se află pe ultimul nivel.</p>
<p>Datorită celor prezentate, vom implementa stiva tot ca listă liniară dublu înlănţuită. Cititorul, dacă nu este de acord cu aceasta, îşi poate scrie propriile rutine.</p>
<p>Fiecare înregistrare corespunzătoare stivei conţine trei informaţii: adresa înainte (a elementului următor), adresa înapoi şi informaţia utilă care se diferă de la caz la caz.</p>
<p>Pentru a lucra cu o astfel de stivă sunt suficiente două proceduri: <em>adaug</em> şi <em>scot</em>, cu rolul de a adăuga şi, respectiv, de a scoate o informaţie din stivă. Modul de alcătuire al acestora îl putem analiza din programul următor:</p>
<p>Program stivă;</p>
<p>type ref=^inr;</p>
<p>inr=record</p>
<p>adrurm, adrinap:ref</p>
<p>end;</p>
<p>var  v:ref;</p>
<p>n:integer;</p>
<p>procedure adaug (var v:ref);</p>
<p>var c:ref;</p>
<p>n:integer;</p>
<p>begin</p>
<p>write (‘n=’); readln (n);</p>
<p>new (c);</p>
<p>c^.nr:=n;</p>
<p>c^.adrurm:=nil;</p>
<p>c^.adrinap:=v;</p>
<p>if v&lt; &gt;nil then v^.adrurm:=c;</p>
<p>v:=c</p>
<p>end;</p>
<p>procedure scot (var v:ref);</p>
<p>var c:ref;</p>
<p>begin</p>
<p>if v=nil</p>
<p>then</p>
<p>writeln (’Stiva este vida’)</p>
<p>else</p>
<p>begin</p>
<p>writeln (v^.nr);</p>
<p>c:=v;</p>
<p>v:=v^.adrinap;</p>
<p>dispose (c)</p>
<p>end</p>
<p>end;</p>
<p>begin</p>
<p>adaug (v);  adaug (v);</p>
<p>scot (v);  scot (v); scot (v)</p>
<p>end.</p>
<p>Spre deosebire de stimularea stivei prin intermediul vectorilor, aici avem avantajul că stiva nu este limitată la cele <em>n</em> componente alocate vectorului. Principalul dezavantaj al acestui mod de stimulaqre a stivei este faptul că pe lîngă informaţia utilă se reţin informaţii de adresă, fapt care duce la consum de memorie.</p>
<p>8.2.5 Coada</p>
<p>Structura de coadă a fost deja prezentată (nu şi exemplificată). Reamintim faptul că toate intrările se fac la un capăt şi toate ieşirile se fac la celălalt capăt. Coada nu se poate implementa dinamic cu mare uşurinţă. Astfel va fi implementată ca o listă <em>simplu înlănţuită </em>(sau, pentru a uşura anumite operaţii, chiar <em>dublu înlănţuită</em>). O variabilă de tip referinţă va reţine o adresă de început a cozii, iar alta de acelaşi tip va reţine adresa de sfîrşit. Exerciţiu: scrieţi un program care creează o coadă cu două, trei elemente, apoi le scoate. La sfîrşit se va da mesajul coadă vidă (asemănător cu programul care exemplifică stiva).</p>
<p>8.2.6 Structuri arborescente</p>
<p>8.2.6.1 Arbori binari</p>
<p>Vom defini arborii binari ca un set finit T de unul sau mai multe noduri, astfel încît:</p>
<ul>
<li>există un nod cu destinaţie specială numită tulpina (rădăcina) arborelui;</li>
<li>Celelalte noduri sunt repartizate în două seturi disjuncte şi fiecare din aceste seturi este la rîndul lui un arbore.</li>
</ul>
<p><em><span style="text-decoration: underline;">Observaţii:</span></em></p>
<ul>
<li>Cei doi arbori subordonaţi tulpinei poartă denumirea de <em>subarbore stîng</em> şi <em>subarbore drept</em>,</li>
<li>Definiţia este recursivă, acest lucru fiind de mare folos în continuare,</li>
<li>În cele ce urmează, pentru tulpină vom folosi  şi termenul de <em>vîrf</em>,</li>
<li>Dacă un nod nu subordonează arbori, îl vom numi <em>nod terminal</em>, în caz contrar îl vom numi <em>nod neterminal</em>.</li>
</ul>
<p>Ne propunem să construim un program care generează în memorie un arbore binar. Pentru aceasta, fiecare nod va fi o înregistrare care conţine trei cîmpuri: informaţia utilă, adresa subarborelui stîng şi adresa subarborelui drept. Modul recursiv de definire a arborilor binari ne conduce la ideea de a folosi o funcţie recursivă şi chiar de a utiliza metoda DIVIDE ET IMPERA conform acestei metode se procedează astfel:</p>
<p>Se citeşte informaţia utilă pentru un nod;</p>
<p>Se alocă spaţiu în memorie pentru aceasta;</p>
<p>Se completează informaţia utilă;</p>
<p>Se costruieşte subarborele stâng;</p>
<p>Se costruieşte subarborele drept;</p>
<p>Exact în acest mod se procedează funcţia <em>arb</em> de tip referinţă. Aici, este de remarcat modalitate de trecere la construcţia subarborilor stâg şi drept. Atunci cînd trebuie completate cîmpurile de adresă, acestea primesc ca valoare funcţiei, ceea ce duce autoapelarea ei. Semnalizarea faptului că nu avem subarbore stîng sau drept se face completînd 0 pentru informaţia utilă.</p>
<p>În principal se folosesc trei metode de parcurgere a arborilor.</p>
<ul>
<li>Stînga, vîrf, dreapta sau inordine, în care se parcurg mai întîi                                                               subarborele stîng, rădăcina şi apoi subarborele drept;</li>
<li> Vîrf, stînga, dreapta saunpreordine, în care se parcurg mai întîi rădăcina, subarborele stîng şi apoi subarborele drept;</li>
<li>Stînga, dreapta, vîrf sau postordine, în care se parcurg mai întîi subarborele stîng, subarborele drept şi apoi rădăcina.</li>
</ul>
<p>Fie arborele de mai jos:</p>
<p>Datele se introduc astfel:</p>
<p>1240050800360079001000.</p>
<p>Parcurgerea în <em>inordine</em> înseamnă:</p>
<p>4 2 5 8 1 6 3 9 7 10.</p>
<p>Parcurgerea în <em>preordine</em> înseamnă:</p>
<p>1 2 4 5 8 3 6 7 9 10.</p>
<p>Parcurgerea în <em>postordine</em> înseamnă:</p>
<p>8 5 2 6 9 10 7 3 1.</p>
<p>Parcurgerile arborului binar sunt realizate de procedurile: <em> svd</em> ( Stînga, vîrf, dreapta), <em>vsd</em> (Vîrf, stînga, dreapta), <em>sdv</em> (Stînga, dreapta, vîrf).în comentariul pe care îl facem acestor proceduri ne mărginim  să precizăm că sunt realizate utilizînd tehnica DIVIDE ET IMPERA.</p>
<p>Program arbori;</p>
<p>type  ref=^inr;</p>
<p>inr=record</p>
<p>st,dr:ref;</p>
<p>nr:integer</p>
<p>end;</p>
<p>var  c:ref;</p>
<p>function arb:ref;</p>
<p>var n:integer;</p>
<p>c:ref;</p>
<p>begin</p>
<p>write (‘n=); readln (n);</p>
<p>if n&lt; &gt;0</p>
<p>then</p>
<p>begin</p>
<p>new (c);</p>
<p>arb:=c;</p>
<p>arb^.nr:=n;</p>
<p>arb^.st:=arb;</p>
<p>arb^.dr:=arb</p>
<p>end</p>
<p>else arb:=nil</p>
<p>end;</p>
<p>procedure svd (c:ref);</p>
<p>begin</p>
<p>if c&lt; &gt;nil</p>
<p>then</p>
<p>begin</p>
<p>svd (c^.st);</p>
<p>writeln (c^.nr);</p>
<p>svd (c^.dr)</p>
<p>end</p>
<p>end;</p>
<p>procedure vsd (c:ref);</p>
<p>begin</p>
<p>if c&lt; &gt;nil</p>
<p>then</p>
<p>begin</p>
<p>writeln (c^.nr);</p>
<p>vsd (c^.st);</p>
<p>vsd (c^.dr)</p>
<p>end</p>
<p>end;</p>
<p>procedure sdv (c:ref);</p>
<p>begin</p>
<p>if c&lt; &gt;nil</p>
<p>then</p>
<p>begin</p>
<p>svd (c^.st);</p>
<p>svd (c^.dr);</p>
<p>writeln (c^.nr)</p>
<p>end</p>
<p>end;</p>
<p>begin</p>
<p>c:=arb;</p>
<p>writeln (‘Parcurg stinga virf dreapta’);</p>
<p>svd(c);</p>
<p>writeln (‘Parcurg virf stinga dreapta’);</p>
<p>vsd (c);</p>
<p>writeln (‘Parcurg  stinga dreapta virf’);</p>
<p>sdv (c)</p>
<p>end.</p>
<p>Aplicaţie. Forma poloneză</p>
<p><em>Se dă o expresie aritmetică. Să se construiască forma poloneză asociată acesteia.</em></p>
<p>Acest exerciţiu l-am rezolvat utilizînd diagramele de sintaxă. În acest capitol îl vom rezolva cu ajutorul arborilor binari. Tehnica de programare folosită va fi DEVIDE ET IMPERA.</p>
<p>Expresiile aritmetice pot fi reprezentate utilizînd arbori binari, respectînd următoarele reguli:</p>
<ul>
<li>Fiecare operaţie corespunde unui nod neterminal, avînd ca informaţie utilă operaţia respectivă;</li>
<li>Fiecare nod terminal este etichetat cu o variabilă sau cu o constantă;</li>
<li>Pentru fiecare nod neterminal subarborele din stînga şi cel din dreapta reprezintă, în această ordine, cei doi operanzi;</li>
<li>Rădăcina corespunde ultimei operaţii executate la evaluarea expresiei.</li>
</ul>
<p>Exemplu: Expresiei (a+b)*c-d/e i se asociază arborele binar din figura de mai jos. Parcurgerea acestui arbore în <em>postordine</em> va da chir forma poloneză: ab+c*de/-. Utilizînd cele spuse, pentru rezolvarea problemei, vom proceda în felul următor:</p>
<ul>
<li>Construim arborele binar asociat, expresiei aritmetice;</li>
<li>Îl parcurgem în <em>postordine</em> pentru a obţine forma poloneză.</li>
</ul>
<p>Parcurgerea arborelui a fost deja prezentată, problema principală rămînînd construirea acestuia.</p>
<p>Pentru  aceasta vom acorda priorităţi operatorilor şi operanzilor (mai puţin parantezelor), după cum urmează:</p>
<ul>
<li>Prioritatea iniţială a operatorilor &#8216;+&#8217;, &#8216;-&#8217; este  1;</li>
<li>Prioritatea iniţială a operatorilor &#8216;*&#8217;, &#8216;/&#8217; este 10;</li>
<li>La prioritatea unui operator se adună 10 pentru fiecare pereche de paranteze între care se găseşte;</li>
<li>Prioritatea unui operand este 1000.</li>
</ul>
<p>În program acest lucru se realizează astfel:</p>
<ul>
<li>Se citeşte expresia aritmetică în variabila e;</li>
<li>Se utilizează o variabilă <em>j</em> care indică ce număr se adaugă la prioritatea iniţială a unui operator (la întîlnirea unei paranteze deschise <em>j</em> creşte cu 10, iar la întîlnirea unei paranteze închise <em>j</em> scade cu 10);</li>
<li>Se parcurge expresia caracter cu caracter şi se pun în vectorul p priorităţile acestor operatori şi operanzi (mai puţin ale parantezelor);</li>
<li>În <em>efp</em> se construieşte  expresia fără paranteze (la expresia aritmetică iniţială lipsesc parantezele), iar în <em>pfp </em> se obţine vectorul priorităţilor, din care, spre deosebire de p, lipsesc componentele corespunzătoare parantezelor (acestea nu aveau nici o valoare).</li>
</ul>
<p>Utilizînd <em>efp</em> şi <em>pfp </em>,cu ajutorul funcţiei <em>arb</em>, se construieşte arborele ataşat expresiei aritmetice. Un nod al acestui arbore are ca informaţie utilă un operator sau un operand.</p>
<p>Conform tehnicii DIVIDE ET IMPERA, funcţia <em>arb </em> procedează în felul următor:</p>
<ul>
<li>de la limita superioară către limita inferioară (limite corespunzătoare subşirurilor de caractere tratate din efp) caută operatorul sau operandul cu prioritate minimă, reţinînd poziţia acestuia;</li>
<li>acesta constituie informaţia utilă din nod, care va fi completată;</li>
<li>în situaţia în care limita inferioară este diferită de limita superioară, pentru completarea adresei subarborelui din stînga şi a arborelui din dreapta se reapelează funcţia, iar în caz contrar aceste cîmpuri capătă valoarea NIL.</li>
</ul>
<p>Pentru listarea în postordine se utilizează procedura <em>parc </em>.</p>
<p>program fp;</p>
<p>type ref=^inr;</p>
<p>sir=array [1..30] of char;</p>
<p>vector=array [1..30] of integer;        inr=record</p>
<p>as, ad:ref;</p>
<p>op:char</p>
<p>end;</p>
<p>var e, efp:sir;</p>
<p>pfp, p:vector;</p>
<p>i, j, n:integer;</p>
<p>c:ref;</p>
<p>a:char;</p>
<p>function arb (1i,1s:integer; var efp:sir; var pfp:vector):ref;</p>
<p>var c:ref;</p>
<p>i, j, min: integer;</p>
<p>begin</p>
<p>min:=pfp [1s];</p>
<p>i:=1s;</p>
<p>for j:= 1s downto 1i do</p>
<p>if pfp [j]&lt;min<br />
then</p>
<p>begin</p>
<p>min:=pfp [j];</p>
<p>i:=j</p>
<p>end;</p>
<p>new ( c);</p>
<p>arb:=c;</p>
<p>arb^.op:=efp [i];</p>
<p>if 1i=1s</p>
<p>then</p>
<p>begin</p>
<p>arb^.as:=nil;</p>
<p>arb^.ad:=nil</p>
<p>end</p>
<p>else</p>
<p>begin</p>
<p>arb^.as:=arb(1i, i-1, efp, pfp);</p>
<p>arb^.ad:=arb(i+1, 1s, efp, pfp)</p>
<p>end</p>
<p>end;</p>
<p>procedure parc (c:ref);</p>
<p>begin</p>
<p>if c&lt; &gt;nil</p>
<p>then</p>
<p>begin</p>
<p>parc ( c^.as);</p>
<p>parc (c^.ad);</p>
<p>write (c^.op)</p>
<p>end</p>
<p>end;</p>
<p>begin</p>
<p>j:=0;</p>
<p>read (a);</p>
<p>n:=1;</p>
<p>while a&lt; &gt;’.’ do</p>
<p>begin</p>
<p>e [n]:=a;</p>
<p>n;=n+1;</p>
<p>read (a )</p>
<p>end;</p>
<p>n:=n-1;</p>
<p>for I;=1 to n do</p>
<p>case e[i] of</p>
<p>‘)’:j:=j-10;</p>
<p>‘(‘:j:=j+10;</p>
<p>‘+’,’-‘:p[i]:=j+1;</p>
<p>‘*’,’/’:p[i]:=j+10</p>
<p>else p[i]:=1000</p>
<p>end;</p>
<p>j:=1;</p>
<p>for i:=1 to n do</p>
<p>if  (e[i] &lt; &gt;’)’) and ( e[i]&lt; &gt;’(‘)</p>
<p>then</p>
<p>begin</p>
<p>efp[j]:=e[i];</p>
<p>pfp[j]:=p[i];</p>
<p>j:=j+1</p>
<p>end;</p>
<p>c:=arb (1,j-1, efp,pfp);</p>
<p>parc ( c);</p>
<p>writeln</p>
<p>end.</p>
<p>Aplicaţie. Arbori de căutare</p>
<p><em> Se numeşte arbore de căutare un arbore binar ale cărui noduri au o cheie de identificare ( mulţimea cheilor asociate nodurilor este o mulţime bine ordonată – între oricare două elemente distincte ale acestei mulţimi a şi b avem sau a&gt;b sau a&lt;b=, iar pentru fiecare nod avem proprietăţile următoare:</em></p>
<ul>
<li><em>Orice cheie asociată unui nod al subarborelui stîng este mai mică decît cheia asociată nodului;</em></li>
<li><em>Orice cheie asociată unui nod al subarborelui drept este mai mare decît cheia asociată nodului.</em></li>
</ul>
<p><em>Orice nod al arborelui are asociate trei informaţii</em></p>
<ul>
<li><em>Cheia de identificare (NR);</em></li>
<li><em>Adresa subarborelui stîng (AS);</em></li>
<li><em>Adresa subarborelui drept (AD).</em></li>
</ul>
<p>Arborii de căutare au fost creaţi pentru regăsirea rapidă a informaţiei.</p>
<p>Aplicaţiile care creează şi actualizează un arbore de căutare, care reţine numerele naturale citite (acestea var fi şi chei asociate noduri).</p>
<p>Vor fi prezentate următoarele funcţii:</p>
<ul>
<li>Inserarea şi căutarea;</li>
<li>Listarea;</li>
<li>Ştergerea;</li>
</ul>
<p>Inserarea şi căutarea</p>
<p>Crearea arborilor de căutare se face aplicînd de un număr de ori operaţia de inserare. Regula de inserare este următoarea:</p>
<ul>
<li>se compară cheia asociată a unui nod cu numărul de inserat;avem trei posibilităţi:
<ul>
<li>cheia coincide cu numărul – se renunţă la inserarea acelui număr;</li>
<li>cheia este mai mare decît numărul – se încearcă inserarea în subarborele stîng;</li>
<li>cheia este mai mic decît numărul – se încearcă inserarea în subarborele drept.</li>
</ul>
</li>
</ul>
<p>Inserarea propriu-zisă se realizează atunci cînd subarborele stîng, respectiv drept, este vid, altfel se reia.</p>
<p>Mecanismul descris este tipic tehnicii DIVIDE ET IMPERA.</p>
<p>Pornim de la un arbore de căutare vid. Inserăm numărul 10.</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="33" valign="top">10</td>
</tr>
</tbody>
</table>
<p>Inserăm 5. Acest număr se inserează în subarborele sting.</p>
<p>Inserăm 7. Acesta este mai mic decît 10. Se trece la subarborele stîng. Se compară cu 5, faţă de care este mai mare. Se inserează în subarborele drept.</p>
<p>Se inserează 15; cum acesta este mai mare decît 10 vom avea:</p>
<p>Iată cum arată arborele după inserarea numerelor 3, 9, 12, 30.</p>
<p>Operaţia de căutare este asemănătoare cu cea de inserare. Cheia căutată se compară cu cheia asociată vîrfului. În caz de egalitate imformaţia a fost găsită. Dacă este mai mică decît cheia asociată nodului, se caută în subarborele stîng iar dacă este mai mare se caută în subarborele drept. Dacă în procesul de căutare s-a ajuns să se caute cheia într-un subarbore vid, înseamnă că nodul cu cheia respectivă lipseşte.</p>
<p>Programul care urmează conţine o procedură de inserare (C_I). Când cheia pentru care se încearcă inserarea lipseşte se execută inserarea, altfel se dă un mesaj corespunzător.</p>
<p>Transmiterea parametrului <em>c</em> se face prin referinţă. Adresa de alocare (obţinută prin NEW) va fi trecută automat părintelui, ca adresă de subarbore stîng sau drept (după caz).</p>
<p>Odată creat, un arbore de căutare permite regăsirea mai rapidă a informaţiei decât în cazul în care ar fi memorate secvenţial. Odată analizată informaţia ataşată prin nod, în caz de inegalitate se trece la subarborele stâng (sau drept) caz în care informaţiile cu cheile din subarborele drept (sau stâng) nu se mai ia în calcul. Numărul de comparaţii este mai mic sau egal cu numărul de niveluri ale arborelui de căutare. De exemplu, pentru regăsirea unei imformaţii, în cadrul arborelui din figură se fac cel mult 4 comparaţii. Dacă pentru memorizare se utilizează o listă simplu înlănţuită, în cazul cel mai defavorabil trebuie de efectuate 8 comparaţii.</p>
<p>Există totuţi o problemă care poate duce la scăderea eficienţei de căutare. În cazul în care cheile sunt introduse în ordine strict crescătoare sau în ordine descrescătoare, arborele degenerează într-o listă liniară (fiecare nod are un singur subarbore nevid). Putem aprecia că introducerea numerelor în această ordine este improbabilă.</p>
<p>Listarea informaţiei</p>
<p>Informaţia se poate lista utilizând oricare din metodele cunoscute pentru parcurgerea arborilor. Dacă dorim listarea imformaţiilor în ordinea strict crescătoare a cheilor, se utilizează metoda stânga-vârf-dreapta (inordine), întucât pentru orice nod avem următoarele:</p>
<ul>
<li>cheile nodurilor din subarborele stâng sunt mai mici decât cheia asociată nodului;</li>
<li>cheile nodurilor din subarborele drept sunt mai mari decât cheia asociată nodului.</li>
</ul>
<p>Vom lista arborele stâng,informaţia din nod şi informaţiile din subarborele drept (SVD).</p>
<p>Ştergerea</p>
<p>După ştergerea unui nod care are o anumită cheie, arborele rămas trebuie să fie de căutare. Nodul care urmează a fi şters se caută după metoda de acum binecunoscută. Se disting 4 situaşii posibil:</p>
<p>a)     nodul care urmează a fi şters este nod terminal – în acest caz se face ştergerea  având grijă ca la părintele lui să înlocuim adresa către el cu NIL;</p>
<p>b)    nodul care urmează a fi şters subordonează un singur subarbore – cel drept – caz în care părintelui i se va înlocui adresa către el cu adresa subarborelui drept, iar nodul respectiv se va şterge;</p>
<p>c)     nodul care urmează a fi şters subordonează un singur subarbore – cel stâng – caz în care părintelui i se va înlocui adresa către el cu adresa subarborelui stâng, iar nodul respectiv se va şterge;</p>
<p>d)    nodul care urmează a fi şters (după cum vom vedea, acesta se va şterge numai logic) subordonează doi subarbori, caz în care se fac operaţiile:</p>
<ul>
<li>se identifică cel mai din dreapta nod al subarborelui stâng corespunzător nodului care urmează a fi şters (acesta va fi şters ăn mod efectiv, ni înainte de a muta informaţiile sale la nodul care se şterge logic);</li>
<li>cheia acestuia şi alte informaţii utile conţinute de el (altele decât cele de adresă) se mută lanodul care urmează a fi şters;</li>
<li>subarborele stâng care se va şterge fizic se leagă:
<ul>
<li>în stânga nodului care se va şterge logic (dacă nodul identificat ca cel mai din dreapta din subarborele stâng este descendentdirect al nodului care se va şterge logic)</li>
<li>în dreapta tatălui nodului care se va şterge fizic (în caz contrar);</li>
</ul>
</li>
</ul>
<p>se şterge fizic nodul care a fost identificat şi ale cărui informaţii au fost mutate (cu cheia cea mai mare din suarborele stâng).</p>
<p><em>Exemlu</em>: pentru cazul d):</p>
<p>Fie arborele din figura de mai jos la care se şterge nodul 6:</p>
<ul>
<li>se identifică nodul cel mai din dreapta pentru subarborele stâng (5);</li>
<li>el nu este descendent direct al nodului care se şterge (6);</li>
<li>informaţia sa se trece nodului şi se obţine:</li>
</ul>
<ul>
<li>subarborele stâng al nodului care se şterge fizic este dat de nodul 4;</li>
<li>acesta se leagă în dreapta tatălui nodului care se şterge fizic (3);</li>
<li>se execută ştergerea fizică şi se obţine:</li>
</ul>
<p>Ştergerea unui nod este realizată de procedura ŞTERG. Pentru situaţia în care un nod care urmează a fi şters subordonează doi arbori, se apelează procedura CMMD.</p>
<p>Mecanismul de transmitere al parametrilor prin referinţă face ca această procedură să fie exterm de scurtă. Astfel, căutarea nodului cel mai din dreapta pentru subarborele stâng (adresa F) se face recursiv, ce procedura a fost apelată pentru primul nod al subarborelui stâng. În situaţia în care acesta este subordonat direct nodului care se şterge, procedura nu se autoapelează, iar după transferul informaţiilor adresa subarborelui stâng (F^.AS) trece ca adresă în stînga nodului care se şterge logic. În caz contrar, datorită faptului că procedura s-a autoapelat, F^.AS trece ca adresa în dreapta pentru părintele nodului care se şterge fizic.</p>
<p>Întrebarea la care trebuie să răspundem în continuare este următoarea: de ce, dacă se şterge în acest mod un nod, arborele rămîne în căutare? Ştergerea unui nod se face în mod distinct pentru fiecare din cele 4 cazuri arătate. Datorită simplităţii prelucrării, primele 3 cazuri nu necesită comentarii. În cazul 4 se identifică nodul cel mai din dreapta din arborele stâng (care este cu cheia cea mai mare din aceste subarbore). Cheia acestuia trece în locul cheii nodului care se şterge. Aceasta este mai mică decât cheia iniţială (pentru că se găseşte în subarborele stâng), este în acelaşi timp cea mai mare cheie din subarborele stâng care este cea mai mică decât cheia care se şterge. Iată motivul pentru care aceasta trece în locul cheii şterge logic.</p>
<p>program c;</p>
<p>type ref=^inr;</p>
<p>inr=record</p>
<p>nr:integer;</p>
<p>as, ad:ref</p>
<p>end;</p>
<p>var  v, man:ref;</p>
<p>k:integer;</p>
<p>opt:char;</p>
<p>procedure c_i (var  c:ref;  k:integer;);</p>
<p>begin</p>
<p>if c&lt; &gt;nil</p>
<p>then</p>
<p>if c^.nr=k</p>
<p>then</p>
<p>writeln (‘nr deja inserat’)</p>
<p>else</p>
<p>if  c^.nr&lt;k</p>
<p>then</p>
<p>c_i(c^.ad,k)</p>
<p>else</p>
<p>c_i(c^.as,k)</p>
<p>else</p>
<p>begin</p>
<p>new (c);</p>
<p>c^.as:=nil;</p>
<p>c^.ad:=nil;</p>
<p>c^.nr:=k</p>
<p>end;</p>
<p>end.</p>
<p>procedure svd (c:ref);</p>
<p>begin</p>
<p>if c&lt; &gt;nil then</p>
<p>begin</p>
<p>svd (c^.as);</p>
<p>writeln (c^.nr);</p>
<p>svd( c^.ad)</p>
<p>end;</p>
<p>end;</p>
<p>procedure cmmd (var  c,f:ref);</p>
<p>begin</p>
<p>if f^.ad&lt; &gt;nil</p>
<p>then</p>
<p>cmmd (c,f^.ad)</p>
<p>else</p>
<p>begin</p>
<p>c^.nr:=f^.nr;</p>
<p>man:=f;</p>
<p>f:=f^.as;</p>
<p>dispose (man);</p>
<p>end;</p>
<p>end;</p>
<p>procedure sterg;</p>
<p>var f:ref;</p>
<p>begin</p>
<p>if c&lt; &gt;nil</p>
<p>then</p>
<p>if c^.nr=k</p>
<p>then</p>
<p>begin</p>
<p>if (c^.as=nil) and (c^.ad=nil)</p>
<p>then</p>
<p>begin</p>
<p>dispose (c);</p>
<p>c:=nil</p>
<p>end</p>
<p>else</p>
<p>if c^.as=nil</p>
<p>then</p>
<p>begin</p>
<p>f:=c^.ad;</p>
<p>dispose (c);</p>
<p>c:=f;</p>
<p>end</p>
<p>else</p>
<p>if c^.ad=nil</p>
<p>then</p>
<p>begin</p>
<p>f:=c^.as;</p>
<p>dispose (c);</p>
<p>c:=f;</p>
<p>end</p>
<p>else</p>
<p>cmmd  (c, c^.as)</p>
<p>end</p>
<p>else</p>
<p>if c^.nr&lt;k</p>
<p>then</p>
<p>sterg (c^.ad, k)</p>
<p>else</p>
<p>sterg (c^.as, k)</p>
<p>else</p>
<p>writeln (‘numar absent – tentativa esuata ‘)</p>
<p>end;</p>
<p>begin</p>
<p>v:=nil;</p>
<p>repeat</p>
<p>write (‘optiunea’);</p>
<p>readln (opt);</p>
<p>case opt of</p>
<p>’i’:    begin</p>
<p>write (‘k=’); readln (k);</p>
<p>c_i (v, k)</p>
<p>’l’:   svd (v);</p>
<p>’s’:   begin</p>
<p>write (‘se va sterge numarul  ‘);  readln (k);</p>
<p>sterg  (v, k)</p>
<p>end;</p>
<p>end  {case}</p>
<p>until   opt=’t’</p>
<p>end.</p>
<p>Teoria regăsirii informaţiei este deosebit de importantă pentru viaţa practică. Reţinem faptul că se pot crea arbori de căutare (echilibraţi) în care toate nodurile terminale se găsesc numai pe două niveluri consecutive. Aceasta conduce la o căutare rapidă (puţine operaţii).</p>
<p>8.2.7   Arbori oarecare</p>
<p><em>Vom defini arbori oarecare după D.E.   KNUTH. Se numeşte arbore oarecare un set finit T de unul sau mai multe noduri astfel încât:</em></p>
<ul>
<li><em>există un nod cu destinaţie specială numit tulpina arborelui;</em></li>
<li><em>celelalte noduri sunt repartizate în m≥0 seturi disjunctive T</em><em>1,</em><em>T</em><em>2,</em><em> &#8230;,</em><em> </em><em>T</em><em>m</em><em> unde fiecare din aceste seturi la rândul său este un arbore.</em></li>
</ul>
<p>Am folosit această definiţie recursivă întrucît ne este de mare folos în scrierea programului care creează un arbore oarecare.</p>
<p>În programul care urmează construim un arbore oarecare în care fiecărui nod i se subordonează cel mult trei subarbori.</p>
<p>Pentru un nod se completează informaţia utilă (un număr întreg) precum şi un vector de adrese ale subarborilor subordonaţi nodului respectiv. Am utilizat tehnica DIVIDE ET IMPERA atât la creare cât şi la parcurgere.</p>
<p>Fie arborele oarecare din figura de mai jos:</p>
<p>Pentru a crea acest arbore vom introduce informaţiile în ordinea următoare:</p>
<p>1 2 3 0 0 0 4 0 0 0 5 0 0 0 6 0 0 0.</p>
<p>Vom prezenta două dintre cele mai uzuale metode de parcurgere a arborilor oarecare:</p>
<p>1) <em>Parcurgerea în adâncime</em> (realizată de procedura <em>padinc</em>), în care se utilizează întâi tulpina, apoi subarborii de la stânga la dreapta (pentru arboreledin figura de mai sus avem: 1 2 3 4 5 6);</p>
<p>program arbg;</p>
<p>type ref=^inr;</p>
<p>vectad=array [1..3] of ref;</p>
<p>inr=record</p>
<p>nr:integer;</p>
<p>a:vectad</p>
<p>end;</p>
<p>var  c:ref;</p>
<p>function arb:ref;</p>
<p>var  c:ref;</p>
<p>n, i:integer;</p>
<p>begin</p>
<p>write (‘n=’); readln (n);</p>
<p>if n&lt; &gt;0</p>
<p>then</p>
<p>begin</p>
<p>new (c);</p>
<p>arb:=c;</p>
<p>arb^.nr:=n;</p>
<p>for i:=1 to 3 do arb ^.a[i]:=arb</p>
<p>end</p>
<p>else arb:=nil</p>
<p>end;</p>
<p>procedure padinc (c:ref);</p>
<p>var i:integer;</p>
<p>begin</p>
<p>if c&lt; &gt;nil then</p>
<p>begin</p>
<p>writeln (c^.nr);</p>
<p>for i:=1 to 3 do padinc (c^.a[i])</p>
<p>end</p>
<p>end;</p>
<p>begin</p>
<p>c:=arb;</p>
<p>padinc (c)</p>
<p>end.</p>
<p>2)    <em>Parcurgerea în lăţime.</em></p>
<p>În acest caz, fiecare element al listei liniare care constituie coada va fi o înregistrare care cuprinde în general două câmpuri: adresa înapoi şi informaţia utilă. Dacă variabilele de tip referinţă <em>b</em> şi <em>v </em>vor reţine adresa utimului element introdus în coadă şi adresa elementului care poate fi scos din coadă.</p>
<p>Lucrul cu coada se poate face utilizînd trei proceduri:</p>
<p>1)    crearea cozii;</p>
<p>2)    adăugarea la coadă;</p>
<p>3)    scoaterea (prelucrarea) din coadă.</p>
<p>1)                Crearea cozii</p>
<p>Această operaţie este realizată de procedura <em>ccoada. </em>Crearea cozii constă în:</p>
<ul>
<li>alocarea spaţiului pentru o înregistrare;</li>
<li>completarea informaţiei utile;</li>
<li>completarea informaţiei îapoi prin NIL.</li>
</ul>
<p>2)                Adăugarea la coadă</p>
<p>Operaţia de adăugare la coadă este realizată de procedura <em>adcoada</em>. Parametrii ei sunt: t (informaţia utilă) şi b (adresa ultimului element introdus în coadă). Pentru aceasta se realizează următoarele operaţii:</p>
<ul>
<li>alocarea spaţiului pentru noua înregistrare;</li>
<li>completarea informaţiei utile;</li>
<li>completarea câmpului de adresă înapoi a înregistrării de la b cu adresa noii înregistrări;</li>
<li>b va lua valoarea adresei noii înregistrări.</li>
</ul>
<p>3)                Scoaterea din coadă</p>
<p>Această operaţie este realizată de procedura <em>scoada</em>. În acest sens se realizează operaţiile:</p>
<ul>
<li>se reţine adresa elementului care urmează a fi scos din coadă;</li>
<li>se şterge înregistrarea acestui element;</li>
<li><em>v</em> va lua valoarea adresei înregistrării plasate înaintea celei şterse.</li>
</ul>
<p>O aplicaţie foarte importantă a structurii de coadă este parcurgerea în lăţime a arborilor oarecare.</p>
<p>Pentru arborele din figura de mai sus, ordinea de parcurgere a vârfurilor este următoarea:</p>
<p>1 2 5 6 3 4.</p>
<p>În exemplul care urmează, această parcurgere este realizată de procedura <em>tipari</em>. Ideea de lucru este următoarea:</p>
<ul>
<li>se porneşte cu o coadă care conţine numai rădăcinile arborelui;</li>
<li>pentru fiecare element din vârful cozii procedăm astfel:</li>
<li>îl listăm;</li>
<li>îi încărcăm toţi succesorii în coadă;</li>
<li>algoritmul se încheie când coada este vidă.</li>
</ul>
<p>Recomandăm cititorului analizarea cu  atenţie a acestei proceduri.</p>
<p>program arbg;</p>
<p>type ref=^inr;</p>
<p>vectad=array [1..3]of ref;</p>
<p>inr=record</p>
<p>nr:integer;</p>
<p>a:vectad</p>
<p>end;</p>
<p>refl=^inr1;</p>
<p>inr1=record</p>
<p>inreg:inr;</p>
<p>inapoi:ref1</p>
<p>end;</p>
<p>var  c:ref;</p>
<p>b, v:ref1;</p>
<p>function  arb:ref;</p>
<p>var  c:ref;</p>
<p>n,i:integer;</p>
<p>begin</p>
<p>write (‘n=’);</p>
<p>readln (n);</p>
<p>if n&lt; &gt;0</p>
<p>then</p>
<p>begin</p>
<p>new (c);</p>
<p>arb:=c;</p>
<p>arb^.nr:=n;</p>
<p>for i:=1  to  3  do  arb^.a[i]:=arb</p>
<p>end</p>
<p>else  arb:=nil</p>
<p>end;</p>
<p>procedure ccoada;</p>
<p>var  d:ref1;</p>
<p>i:integer;</p>
<p>begin</p>
<p>new (d);</p>
<p>d^.inreg:=c^;</p>
<p>d^.inapoi:=nil;</p>
<p>b:=d;</p>
<p>v:=d</p>
<p>end;</p>
<p>procedure adcoada (t:inr;  var  b:ref1);</p>
<p>var  d:ref1;</p>
<p>begin</p>
<p>new (d);</p>
<p>d^.inapoi:=nil;</p>
<p>d^.inreg:=t;</p>
<p>b^.inapoi:=d;</p>
<p>b:=d</p>
<p>end;</p>
<p>procedure scoada  (var  v:ref1);</p>
<p>var  d:ref1;</p>
<p>begin</p>
<p>d:=v;</p>
<p>dispose (v);</p>
<p>v:=d^.inapoi</p>
<p>end;</p>
<p>procedure  tipari (var  b, v:ref1);</p>
<p>var  d:ref;</p>
<p>t:inr;</p>
<p>i:integer;</p>
<p>begin</p>
<p>while  v&lt; &gt;nil do</p>
<p>begin</p>
<p>writeln (v^.inreg.nr);</p>
<p>for  i:=1  to  3  do  begin</p>
<p>d:=v^.inreg.a[i];</p>
<p>if d&lt; &gt;nil</p>
<p>then</p>
<p>begin</p>
<p>t:=d^;</p>
<p>adcoada (t,b)</p>
<p>end</p>
<p>end;</p>
<p>scoada (v)</p>
<p>end</p>
<p>end;</p>
<p>begin</p>
<p>c:=arb;</p>
<p>ccoada;</p>
<p>tipari  (b, v)</p>
<p>end.</p>
<p>Aplicaţie. Partiţia determinată de o relaţie de echivalenţă.</p>
<p>Un arbore oarecare poate fi memorat utilizînd o legătură de tip <em>tată</em>. Pentru aceasta este necesar un singur vector <em>v</em>, în care, pentru fiecare nod <em>i, v(i)</em> are semnificaţia de <em>tatăl lui i</em>. Avem v(i)=0 dacănodul lui <em>i</em> este vârf.</p>
<p><em><span style="text-decoration: underline;">Observaţii:</span></em></p>
<p>- această formă de memorare este extrem de economică din punct de vedere al memoriei folosite (un nod poate avea mai multe noduri subordonate, dar numai un nod <em>tată</em>, deci avem o singură informaţie de adresă).</p>
<p>-parcurgerea arborilor reprezintanţi astfel de greoaie, fiind consumat mult timp.</p>
<p>Din matematică este cunoscută relaţia de echivalenţă. Aici o vom reaminti. O relaţie de echivalenţă &#8216;≈&#8217; este o relaţie între elementele unei mulţimi, care satisface următoarele trei proprietăţi:</p>
<p>1)    x≈x (reflexivitate);</p>
<p>2)    dacă x≈y avem şi y≈x (simetrie);</p>
<p>3)    dacă x≈y şi y≈z, atunci x≈z (tranzitivitate).</p>
<p>Pentru că formează o submulţime aparte a mulţimii considerate, toate elementele sunt echivalente între ele. Cum fiecare element este cel puţin echivalent cu el însuşi, înseamnă că o relaţie de echivalenţă determină pe mulţimea considerată o partiţie.</p>
<p><em>Se consideră mulţimea primilor n numere naturale {1, 2, …, n}. Se dau un număr neprecizat de perechi echivalente de forma x≈y şi se cere  partiţia determinată de această relaţie de echivalenţă.</em></p>
<p><em>Exemplu</em>:</p>
<p>Fie n=4 şi perechile 1≈3, 1≈4, 3≈4.</p>
<p>În acest caz relaţia 3≈4 ar putea fi dedusă dinprimele două relaţii:anume din 1≈4 rezultă 4≈1 (simetrie), iar din 4≈1 şi 1≈3 rezultă 4≈3 (tranzitivitate), deci 3≈4 (simetrie). Partiţia determinată de această relaţie de echivalenţă este {1,3,4}, {2}.</p>
<p>Pentru rezolvare, considerăm o pădure cu arbori oarecare, cu nodurile elemente ale mulţimii considerate, reprezintaţi într-un vector cu <em>n</em>, componente, utilizând legătura de tip &#8216;tată&#8217;.</p>
<p>Iniţial, fiecare element constituie un arbore aparte, deci componentele vectorului <em>v</em> au valoarea 0.</p>
<p>Aplicăm soluţia următoare: toate elementele echivalente între ele (care vor alcătui o submulţime aparte a partiţiei) formează un arbore oarecare. Deci la citirea unei perechi j≈k se pune v(j) =k (adică tatăl lui <em>j</em> este <em>k</em>). Există posibilitatea ca j să fie subordonat unui alt părinte (v(j)≠0). În această situaţie j va lua valoarea lui v(j); raţionamentul continuă pînă când v(j) va fi 0 (se ajunge la tulpina arborelui construit pentru această submulţime). În acest moment v(j) va lua valoarea lui k, ceea ce înseamnă că întreg arborele se subordonează lui k. preluăm un exemplu al lui D.E. KNUTH.</p>
<p>Fie n=9 şi perechile citite: 1≈5, 6≈8, 7≈2, 9≈8, 3≈7, 4≈2, 9≈3.</p>
<p>Iniţial vectorul <em>v</em> va arăta astfel:</p>
<p>indici      1  2  3  4  5  6  7  8  9</p>
<p>v            0  0  0  0  0  0   0  0  0</p>
<p>arbori      1  2  3  4  5  6  7  8  9</p>
<p>indici      1  2  3  4  5  6  7  8  9</p>
<p>v             5  0  0  0  0  0  0  0  0            am citit 1=5</p>
<table cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="30" height="30" bgcolor="white">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>111</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p>arbori      2   3   4   5   6  7  8  9</p>
<p>indici      1  2  3  4  5  6  7  8  9</p>
<p>v             5  0  0  0  0  8  0  0  0             am citit 6=8</p>
<p>arbori       2   3    4  5    7   8   9</p>
<p>1        6</p>
<table cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="30" height="30" bgcolor="white">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>6</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p>indici      1  2  3  4  5  6  7  8  9</p>
<p>v             5  0  0  0  0  8  2  0  0            am citit 9=8</p>
<p>arbori        2  3  4      5  7    8</p>
<p>indici      1  2  3  4  5  6  7  8  9</p>
<p>v              5  0  7  2  0  8  2  0  8         am citit 3=7</p>
<p>arbori             2   4  5       8</p>
<table cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="30" height="30" bgcolor="white">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>3</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<table cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="30" height="30" bgcolor="white">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>1</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<table cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="30" height="30" bgcolor="white">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>7</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p>indici      1  2  3  4  5  6  7  8  9</p>
<p>v             5  0  7  2   0  8  2  0  8       am citit 4=2</p>
<p>arbori            2         5      8</p>
<table cellspacing="0" cellpadding="0" align="left">
<tbody>
<tr>
<td width="131" height="3"></td>
<td width="30"></td>
<td width="18"></td>
<td width="26"></td>
<td width="10"></td>
<td width="30"></td>
<td width="18"></td>
<td width="30"></td>
</tr>
<tr>
<td height="30"></td>
<td rowspan="2" align="left" valign="top"></td>
<td></td>
<td width="26" height="30" bgcolor="white">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>4</td>
</tr>
</tbody>
</table>
</td>
<td></td>
<td width="30" height="30" bgcolor="white">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>6</td>
</tr>
</tbody>
</table>
</td>
<td></td>
<td width="30" height="30" bgcolor="white">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>9</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td height="47"></td>
</tr>
</tbody>
</table>
<p>indici      1  2  3  4  5  6  7  8  9</p>
<table cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="30" height="30" bgcolor="white">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>5</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<table cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="30" height="30" bgcolor="white">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>2</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p>v              5  0  7  2  0  8  2  3  8        am citit 8=3arbori</p>
<p>Se obţine partiţia {2,7,4,3,8,6,9} şi {5,1}.</p>
<p><em><span style="text-decoration: underline;">Observaţie:</span></em></p>
<p>- Algoritmul nu înregistrează relaţii de forma j≈j sau, dacă a înregistrat j≈k, nu înregistrează k≈j. Pentru listare utilizăm procedura tipar. Precizăm faptul că, în acest algoritm nu sunt permise ca intrări informaţii redundante.</p>
<p>Exemplu:(1,2),  (2,3),  (3,1).  Modificarea algoritmuui în acest sens este propusă ca exerciţiu.</p>
<p>program rechiv;</p>
<p>type  vector=array [1..100]  of integer;</p>
<p>var  v:vector;</p>
<p>n, j, k:integer;</p>
<p>procedure adaug (var j, k:integer; var  v:vector);</p>
<p>begin</p>
<p>while v[j]&lt; &gt;0  do  j:=v[j];</p>
<p>if  (j&lt; &gt;k)  and  (v[k]&lt; &gt;j)  then  v[j]:=k</p>
<p>end;</p>
<p>procedure tipar  (j:integer);</p>
<p>var  i:integer;</p>
<p>begin</p>
<p>for  i:=1  to n do  if  v[i]=j</p>
<p>then</p>
<p>begin</p>
<p>if j=0  then writeln (‘&#8212;&#8212;-clasa&#8212;&#8212;-‘);</p>
<p>writeln (i);</p>
<p>tipar (i);</p>
<p>end</p>
<p>end;</p>
<p>begin</p>
<p>write (‘n=’); readln (n);</p>
<p>for j:=1  to  n  do  v[j]:=0;</p>
<p>while  j&lt; &gt;0 do</p>
<p>begin</p>
<p>write (‘j k’);</p>
<p>readln   (j, k);</p>
<p>if  j&lt; &gt;0  then adaug (j, k, v)</p>
<p>end;</p>
<p>tipar (0)</p>
<p>end.</p>
<p><strong>Probleme propuse</strong><strong> </strong></p>
<p>1)    Se citesc <em>n</em> numere naturale, distincte. Să se sorteze crescător, utilizînd lista liniară simplu înlănţuită, după următorul algoritm</p>
<ul>
<li>iniţial lista va conţine numai primul număr;</li>
<li>dacă al doilea este mai mare decît primul, se va pune în coada listei, altfel va fi primul element din listă;</li>
<li>orice număr se aşează în listă înaintea celui mai mic număr care este mai mare decît el (dacă există un astfel de număr), sau la sfîrşitul listei, în caz contrar.</li>
</ul>
<p>În final, se listează conţinutul listei liniare simplu înlănţuită. (sortare prin inserţie).</p>
<p>2)    Să se rezolve una din problemele propuse la capitolul 1 utilizînd stiva implementată dinamic.</p>
<p>3)    Să se creeze un obiect numit LLSI – lista liniară simplu înlănţuită – care conţine numere naturale. Acesta va cuprinde metode pentru adăugarea la sfîrşitul listei, ştergerea unui element ş.a.m.d. (în general toate operaţiile care se fac cu liste liniar simplu înlănţuite).</p>
<p>4)    Utilizînd obiectul creat la problema anterioară să se construiască un descendent al acestuia, numit NUMĂR_MARE, în care fiecare element al listei reţine o cifră între 0 şi 9 (în ansamblu o astfel de listă va reţine un număr cu mai multe cifre). Obiectul va fi înzestrat cu metode pentru citarea şi tipărirea numărului.</p>
<p>5)    Să se scrie o procedură care poate aduna două ’’numere mari’’.</p>
<p>6)    Să se scrie o procedură care înmulţeşte două ’’numere mari’.</p>
<p>7)    Pentru realizarea unui curs în care se explică conţinutul a <em>n</em> noţiuni, se citesc <em>p</em> perechi de cuvinte de forma (ni, nj). Fiecare cpereche citită are semnificaţia următoare: noţiunea <em>i</em> foloseşte în definirea noţiunii <em>j</em>. Se cere să se precizeze ordinea de prezentare a noţiunilor în curs.</p>
<p>8)    În jurul arbitrului sunt aşezaţi în cerc N jucători, numerotaţi în sens orar. Arbitrul, începînd de la jucătorul K, numără pînă la M. persoana la care sa oprit numărătoarea este eliminată din cerc. Arbitrul se poziţionează pe următoarea persoană şi repetă procedeul pînă cînd în cerc rămîne un singur jucător (L).</p>
<p>Să se scrie un program care:</p>
<ul>
<li>Citind M, N şi K, să-l determuine pe L;</li>
<li>Citind M, N şi L, să-l determuine pe K.</li>
</ul>
<p>9)    Să se sorteze n numere naturale cu ajutorul arborilor de căutare.</p>
<p>10)               Evidenţa produselor aflate în stocul unui magazin se ţine pe baza unui arbore de căutare. Pentru fiecare produs se reţine:</p>
<ul>
<li>denumirea;</li>
<li>preţul;</li>
<li>cantitatea existentă (buc.).</li>
</ul>
<p>În fiecare seară arborele estev actualizat prin comenzi de forma:</p>
<p>i – se introduc produsele primite de la depozit (Atenţie! Un astfel de produs poate să mai existe în stoc);</p>
<p>s – se şterg produsele vândute în ziua respectivă;</p>
<p>De asemenea, programul acceptă şi comenzile:</p>
<p>v – se tipăreşte valoarea tuturor produselor aflate în stoc;</p>
<p>l – se tipăreşte o listă completă a produselor aflate în stoc, în ordine alfabetică. Pentru fiecare produs se va tipări şi numărul de bucăţi.</p>
<p>11)           <em>Problema jocurilor între doi parteneri</em>, în care unul din jucători este calculatorul. Pentru a putea juca, calculatorul îşi construieşte un arbore corespunzător situaţiilor care pot apărea.</p>
<p>Pentru a exemplifica vom considera un joc simplu, numit ’GRUNDY’. Se consideră o stivă de n monede. Unul din cei doi parteneri o împarte în două părţi inegale. Celălalt partener împarte una din cele două stive de monede rămase în două părţi inegale ş.a.m.d.. Pierde acel jucător care nu mai poate face o astfel de împărţire.</p>
<p>Vom considera cazul n=5. În această situaţie calculatorul îşi construieşte arborele din figura de mai jos:</p>
<p>O primă problemă care se pune este dacă într-o anumită situaţie, presupunînd că trebuie să mute calculatorul, acesta dispune sau nu de strategie sigură de cîştig. Această problemă se poate rezolva utilizînd algoritmul MINI-MAX. Aplicarea acestui algoritm presupune următoarele:</p>
<ul>
<li>analiza nodurilor terminale ale arborelui, unde pot apărea două situaţii:</li>
<li>trebuie să mute calculatorul, caz în care nodul se etichetează cu 0;
<ul>
<li>trebuie să mute partenerul uman, caz în care nodul se etichetează cu 1;</li>
</ul>
</li>
<li>analiza nodurilor neterminale ale arborelui, unde apar din nou două situaţii:
<ul>
<li>mută calculatorul, situaţie în care nodul se etichetează cu maximul dintre etichetele nodurilor subordonate acestuia;</li>
<li>mută partenerul uman, situaţie în care nodul se etichetează cu minimul dintre etichetele nodurilor subordonate acestuia.</li>
</ul>
</li>
</ul>
<p>Acest mod de etichetare îşi găseşte explicaţia în faptul că, la mutarea efectuată de calculator, acesta va alege o mutare convenabilă (se va duce într-un nod etichetat cu 1), iar la mutarea efectuată de partenerul uman se presupune că acesta va alege o mutare  convenabilă lui (va face o mutare care îl va duce într-un nod etichetat 0).</p>
<p>Scrieţi un program cu ajutorul căruia calculatorul va juca Grundy cu dumneavoastră.</p>
]]></content:encoded>
			<wfw:commentRss>http://resurse-educationale.uv.ro/?feed=rss2&#038;p=183</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>68 de pagini de probleme rezolvate si teorie in Pascal</title>
		<link>http://resurse-educationale.uv.ro/?p=154</link>
		<comments>http://resurse-educationale.uv.ro/?p=154#comments</comments>
		<pubDate>Thu, 17 Mar 2011 08:47:24 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Pascal]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Teze]]></category>
		<category><![CDATA[algoritmi]]></category>
		<category><![CDATA[probleme]]></category>
		<category><![CDATA[programare]]></category>
		<category><![CDATA[programe rezolvate]]></category>
		<category><![CDATA[teza]]></category>

		<guid isPermaLink="false">http://resurse-educationale.uv.ro/?p=154</guid>
		<description><![CDATA[1.1. GHID DE LUCRU Rezolvarea unei probleme cu ajutorul calculatorului presupune parcurgerea următoarelor faze: ‑ precizarea completă a problemei de rezolvat; ‑ proiectarea algoritmului de rezolvare a problemei; ‑ programarea propriu‑zisă (implementarea); ‑ testarea programului obţinut; ‑ exploatarea şi întreţinerea &#8230; <a href="http://resurse-educationale.uv.ro/?p=154">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p><em><a rel="attachment wp-att-155" href="http://resurse-educationale.uv.ro/?attachment_id=155"><br />
</a></em></p>
<p><em>1.1. GHID DE LUCRU </em></p>
<p>Rezolvarea unei probleme cu ajutorul calculatorului presupune parcurgerea următoarelor faze:</p>
<p>‑ precizarea completă a problemei de rezolvat;</p>
<p>‑ proiectarea algoritmului de rezolvare a problemei;</p>
<p>‑ programarea propriu‑zisă (implementarea);</p>
<p>‑ testarea programului obţinut;</p>
<p>‑ exploatarea şi întreţinerea programului.</p>
<p>Aceste faze constituie ciclul de viaţă al programului.</p>
<p>De foarte multe ori, atunci când beneficiarul discută cu executantul despre problema care trebuie rezolvată, acesta dă un enunţ vag, incomplet, dacă nu chiar inexact sau contradictoriu, pentru problema de rezolvat. Urmează mai multe discuţii, uneori întinse în timp, în urma cărora se ajunge la un enunţ relativ complet şi exact al problemei. Întrucât problemele propuse sunt luate din domeniul matematicii sarcina noastră va fi mult mai uşoară.</p>
<p>După enunţarea problemei urmează modelarea matematică şi căutarea unei metode de rezolvare a ei. Uneori sunt posibile mai multe moduri de rezolvare, caz în care se va alege metoda considerată cea mai potrivită scopului urmărit. Modelarea matematică şi alegerea unei metode de rezolvare se îmbină aproape întotdeauna cu conceperea algoritmului, fiind greu să se separe una de cealaltă. Activităţile de mai sus constituie ceea ce numim proiectarea programului.</p>
<p>Pe toată durata proiectării trebuie menţionate în scris toate deciziile luate, întrucât este posibil ca ulterior să fie necesară o reproiectare şi deci, să se revină asupra acestor decizii. Documentaţia realizată este necesară în primul rând pentru următoarea fază a ciclului de viaţă al programului, implementarea. De asemenea, în faza de întreţinere a programului este posibilă modificarea unor module, modificare în care sunt necesare să fie cunoscute şi aceste decizii. E bine ca proiectarea să fie astfel făcută încât să permită o întreţinere cât mai uşoară.  Faza următoare, implementarea sau codificarea, constă în traducerea algoritmului într‑un limbaj de programare. Evident, prima decizie ce trebuie luată constă în alegerea limbajului de programare în care va fi scris programul. În cele ce urmează vom folosi în acest scop limbajul Pascal. De multe ori se vor folosi mai multe limbaje pentru această activitate. De exemplu, pot exista unele module a căror scriere se poate face numai în limbajul de asamblare. Urmează testarea programului elaborat, care uneori pune în evidenţă erori grave de programare, erori care au dus în unele situaţii la refacerea (parţială sau integrală) a activităţilor anterioare. Sigur că este de dorit să nu se ajungă la astfel de situaţii şi, dacă proiectarea şi implementarea au fost făcute corect, în faza de testare nu ar trebui să întâlnim erori.</p>
<p>Următoarea fază din viaţa programului constă în exploatarea propriu-zisă a acestuia, fază în care execuţia se face cu date reale. Această activitate se întinde în timp pe mai mulţi ani şi cere adeseori schimbări în program, motiv pentru care este cunoscută sub numele de întreţinerea programului. Este faza cea mai costisitoare şi cea mai importantă din viaţa unui produsul real. Toată activitatea de realizare a programului trebuie să ţină seama de acest fapt şi programul să fie astfel conceput încât să se permită modificări în ceea ce face programul cu un număr minim de modificări în textul acestuia. Documentarea programului presupune elaborarea unor materiale scrise în care se precizează toate informaţiile utile despre programul realizat. Pentru proiectarea algoritmilor vom folosi limbajul Pseudocod. Avantajele folosirii acestui limbaj pentru proiectarea algoritmilor constau în faptul că permit programatorului să-şi îndrepte complet atenţia asupra logicii rezolvării problemei şi să uite de restricţiile impuse de limbajul de programare şi calculatorul folosit. În această fază este necesară o analiză atentă a problemei în vederea găsirii unui algoritm corect proiectat.</p>
<p>De asemenea, proiectarea algoritmului permite evitarea duplicării unui grup de instrucţiuni în mai multe părţi ale programului. Identificarea unui astfel de grup permite definirea lui ca un singur subalgoritm şi folosirea acestui subalgoritm ori de câte ori este necesar.</p>
<p>În descrierea unui algoritm deosebim următoarele activităţi importante:</p>
<p>- specificarea problemei;</p>
<p>- descrierea metodei alese pentru rezolvarea problemei;</p>
<p>- precizarea denumirilor şi semnificaţiilor variabilelor folosite;</p>
<p>- descrierea algoritmului propriu-zis.</p>
<p>Astfel, dacă ni se cere să calculăm radicalul de ordinul 2 din <em>x</em>, în partea de specificare a problemei vom menţiona:</p>
<p>Se dă un număr real nenegativ, notat prin <em>x</em>.</p>
<p>Se cere să găsim un alt număr pozitiv <em>r</em> astfel încât <em>r</em><sup>2</sup>=<em>x</em>.</p>
<p>Pentru un informatician este clar că un astfel de număr nu se poate găsi în general prin nici un procedeu finit. Este însă posibil să găsim o aproximare oricât de bună a lui <em>r</em>. Deci specificarea făcută nu este corectă, neputând găsi un algoritm care să rezolve problema în forma enunţată. Vom modifica această specificaţie, cerând să se calculeze aproximativ <em>r</em> cu o eroare ce nu depăşeşte un număr real <em>eps</em> oricât de mic.</p>
<p>Specificaţia problemei este:</p>
<p><em>DATE eps,x;                                                                                                    {eps,xR,  eps&gt;0 şi x0}</em></p>
<p><em> REZULTATE r;                                                                                                          {r-rad(x)&lt;eps}</em></p>
<p>unde prin <em>rad</em>(<em>x</em>) am notat radicalul de ordinul 2 din <em>x</em> definit în matematică.</p>
<p>Urmează să precizăm metoda de rezolvare a problemei. Se ştie că există cel puţin două posibilităţi de a calcula pe <em>r</em>:</p>
<p>- ca limită a unui şir (definit printr-o relaţie de recurenţă) convergent la <em>r</em>;</p>
<p>- prin rezolvarea ecuaţiei <em>r</em><sup>2</sup>=<em>x</em>.</p>
<p>Precizăm că-l vom calcula pe <em>r</em> rezolvând ecuaţia <em>r</em><sup>2</sup>=<em>x</em>. Dar şi rezolvarea acestei ecuaţii se poate face prin mai multe metode. Decidem că o vom rezolva prin metoda njumătăţirii. Această metodă constă în njumătăţirea repetată a intervalului [<em>a,b</em>] care conţine rădăcina <em>r</em> la intervalul [<em>a',b'</em>], care este jumătatea stângă, sau jumătatea dreaptă a intervalului [<em>a,b</em>], cea care conţine rădăcina.</p>
<p>Variabilele folosite în descrierea algoritmului sunt:</p>
<p>- <em>a</em> şi <em>b</em> = capetele intervalului în care se află rădăcina;</p>
<p>- <em>m</em> mijlocul intervalului (<em>a,b</em>). În momentul în care <em>b-a&lt;eps,</em></p>
<p><em>m</em> va fi chiar valoarea căutată pentru <em>r</em>.</p>
<p>Algoritmul propriu-zis este descris în continuare:</p>
<p><em>*Iniţializează pe a şi b;</em></p>
<p><em> REPETĂ</em></p>
<p><em> FIE m:=(a+b)/2; </em></p>
<p><em> * Dacă rădăcina se află în [a,m] atunci b:=m altfel a:=m.</em></p>
<p><em> PNĂCND b-a&lt;eps SF-REPETĂ</em></p>
<p><em> FIE r:=(a+b)/2;</em></p>
<p><em> </em></p>
<p>În textul de mai sus apar două propoziţii nestandard care sugerează însă foarte bine ce acţiuni trebuiesc întreprinse. Prima stabileşte intervalul iniţial în care se află rădăcina, care depinde de mărimea lui <em>x</em>: (<em>x</em>,1) când <em>x</em> este mai mic decât 1 sau (1,<em>x</em>) în caz contrar. Deci ea se va transcrie în propoziţia standard</p>
<p><em> DACĂ x&lt;1 ATUNCI ATRIBUIE  a:=x;  b:=1</em></p>
<p><em> ALTFEL ATRIBUIE  a:=1;  b:=x</em></p>
<p><em> SF-DACĂ</em></p>
<p>A doua propoziţie înjumătăţeşte intervalul. Condiţia ca rădăcina să se afle în jumătatea stângă a intervalului este (<em>a</em><sup>2</sup>-<em>x</em>)*(<em>m</em><sup>2</sup>-<em>x</em>)&lt;0. Se ajunge la următoarea variantă finală:</p>
<p><em>ALGORITMUL RADICAL ESTE:                                                       {Calculează radical din x}</em></p>
<p><em> DATE eps,x;                                                                                                     {eps,xR, eps&gt;0 şi x0}</em></p>
<p><em> DACĂ x&lt;1 ATUNCI FIE  a:=x;  b:=1                                                    {Iniţializează pe a şi b}</em></p>
<p><em> ALTFEL FIE  a:=1;  b:=x </em></p>
<p><em> SF-DACĂ</em></p>
<p><em> REPETĂ</em></p>
<p><em> DACĂ (a<sup>2</sup>-x)*(m<sup>2</sup>-x)&lt;0 ATUNCI b:=m                                                   {rădăcina în stânga}</em></p>
<p><em> ALTFEL a:=m                                                                       {rădăcina în dreapta}</em></p>
<p><em> SF-DACĂ</em></p>
<p><em> PNĂCND b-a&lt;eps SF-REPETĂ</em></p>
<p><em> FIE r:=(a+b)/2;</em></p>
<p><em> REZULTATE r;                                                                                                          {r-rad(x)&lt;eps}</em></p>
<p><em> SF-ALGORITM</em></p>
<p><em> </em></p>
<p>Programul Pascal corespunzător este dat în continuare.</p>
<p>PROGRAM RADICAL;                                                                {Programul 1.1. Calculează radical din x}</p>
<p>VAR eps,                                                                                               {eps= precizia cu care se calculează}</p>
<p>x,                                                                                                                       {radical din x, eps&gt;0 si x&gt;=0}</p>
<p>r,                                                                                                                                 {valoarea radicalului x}</p>
<p>a,b,                                                                                                   {capetele intervalului ce conţine pe r}</p>
<p>m : REAL;                                                                                                           {mijlocul intervalului [a,b]}</p>
<p>BEGIN</p>
<p>WRITELN(&#8216;Se calculează radical din x cu precizia eps:&#8217;);</p>
<p>WRITE(&#8216;eps=&#8217;);   READLN(eps);</p>
<p>WRITE(&#8216; x =&#8217;);   READLN(x);</p>
<p>IF x&lt;1 THEN BEGIN a:=x;  b:=1 END                                                                     {Iniţializează pe a si b}</p>
<p>ELSE BEGIN a:=1;  b:=x END;</p>
<p>REPEAT</p>
<p>m:=(a+b)/2;</p>
<p>IF (a*a‑x)*(m*m‑x)&lt;0</p>
<p>THEN b:=m                                                                                                       {rădăcina în stânga}</p>
<p>ELSE a:=m;                                                                                                       {rădăcina in dreapta}</p>
<p>UNTIL b‑a&lt;eps;</p>
<p>r:=(a+b)/2;</p>
<p>WRITELN;  WRITELN;</p>
<p>WRITELN(&#8216;Radical(&#8216;,x:6:1,&#8217;) = &#8216;,r:6:3);                                                                                     {r‑rad(x)&lt;eps}</p>
<p>READLN</p>
<p>END.</p>
<p><em>1.2. NUMERE PITAGORICE</em>.</p>
<p>Numerele <em>a,b,c</em>, se numesc pitagorice dacă</p>
<p>Specificarea problemei este:</p>
<p><em>DATE n;                                                                               {nN; pentru n&lt;12 nu există triplete}</em></p>
<p><em> REZULTATE toate tripletele de numere pitagorice (a,b,c) cu proprietatea</em></p>
<p><em> 0&lt;a&lt;b&lt;c şi a+b+cn.</em></p>
<p>Vom nota prin <em>S</em> suma <em>a+b+c</em>. Se ştie că (3,4,5) este primul triplet de numere pitagorice. În acest caz <em>S</em> ia valori de la 12 la <em>n</em>. Întrucât  <em>3a&lt;S</em> variabila <em>a</em> ia valori de la 3 la <em>S</em>/3. Apoi 2<em>b</em>&lt;<em>S-a</em> deci <em>b</em> va lua valori de la <em>a+1</em> la (<em>S-a</em>)/2. Algoritmul pentru rezolvarea problemei este dat în continuare :</p>
<p><em>Algoritmul NRPITAGORICE este :</em></p>
<p><em> Date n;                                                                                                {nN; pentru n&lt;12 nu există triplete}</em></p>
<p><em> Dacă n&lt;12</em></p>
<p><em> atunci Tipăreşte &#8220;Nu există numerele cerute&#8221;</em></p>
<p><em> altfel Pentru S=12,n execută</em></p>
<p><em> Pentru a=3,S/3 execută</em></p>
<p><em> Pentru b=a+1,(S-a)/2 execută</em></p>
<p><em> Fie c:=S-a-b;</em></p>
<p><em> Dacă c=a+b atunci Tipăreşte(a,b,c) Sf-dacă</em></p>
<p><em> Sf-pentru</em></p>
<p><em> Sf-pentru</em></p>
<p><em> Sf-pentru </em></p>
<p><em> Sf-dacă</em></p>
<p><em>Sf-algoritm.</em></p>
<p><em> </em></p>
<p>Programul Pascal corespunzător este dat în continuare.</p>
<p>PROGRAM  NRPITAGORICE;                                                         {Programul 1.1.2. Numere pitagorice}</p>
<p>VAR n,                                                                                                                             {    nN;  a+b+cn        }</p>
<p>S,                                                                                                                                   {    S  =  a+b+c          }</p>
<p>a,b,c,                                                                                                   {(a,b,c) triplet de numere pitagorice}</p>
<p>{  0 &lt; a &lt; b &lt; c          }</p>
<p>k     : integer;                                                                                                                                    { contor }</p>
<p>BEGIN</p>
<p>WRITELN(&#8216;Se tipăresc tripletele(a,b,c) de numere pitagorice&#8217;);</p>
<p>WRITELN(&#8216;cu proprietatea: a+b+c&lt;=n, pentru n dat&#8217;);</p>
<p>WRITE(&#8216;Daţi valoarea lui n:&#8217;); READLN(n);</p>
<p>For k:=1 to 4 do writeln;</p>
<p>k:=0;</p>
<p>IF n&lt;12</p>
<p>THEN WRITELN(&#8216;Nu exista numerele cerute&#8217;)</p>
<p>ELSE FOR S:=12 TO n DO</p>
<p>FOR a:=3 TO S DIV 3 DO</p>
<p>FOR b:=a+1 TO (S‑a) DIV 2 DO</p>
<p>BEGIN</p>
<p>c:=S‑a‑b;</p>
<p>IF c*c=a*a+b*b THEN BEGIN</p>
<p>k:=k+1;</p>
<p>WRITELN(&#8216;Tripletul (a,b,c)&#8217;,k:3,&#8217;= &#8216;,a:3, b:3,c:3);</p>
<p>END {IF}</p>
<p>END;</p>
<p>READLN;</p>
<p>END.</p>
<p><em><a rel="attachment wp-att-155" href="http://resurse-educationale.uv.ro/?attachment_id=155">68 de pagini de probleme rezolvate si teorie in Pascal</a></em></p>
]]></content:encoded>
			<wfw:commentRss>http://resurse-educationale.uv.ro/?feed=rss2&#038;p=154</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Utilizarea variabilelor aleatoare la rezolvarea problemelor</title>
		<link>http://resurse-educationale.uv.ro/?p=150</link>
		<comments>http://resurse-educationale.uv.ro/?p=150#comments</comments>
		<pubDate>Thu, 17 Mar 2011 08:43:23 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Pascal]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[algoritm]]></category>
		<category><![CDATA[aplicatii]]></category>
		<category><![CDATA[extraşcolar]]></category>
		<category><![CDATA[programare]]></category>
		<category><![CDATA[variabile aleatoare]]></category>

		<guid isPermaLink="false">http://resurse-educationale.uv.ro/?p=150</guid>
		<description><![CDATA[Îmbinarea de cuvinte „variabilă aleatoare” în sensul direct se utilizează atunci cînd dorim să subliniem, că nu se ştie dinainte care va fi valoarea acestei variabile. Deasemenea în spatele acestor cuvinte se ascunde şi neştirea cum ar arăta această variabilă. &#8230; <a href="http://resurse-educationale.uv.ro/?p=150">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Îmbinarea de cuvinte „variabilă aleatoare” în sensul direct se utilizează atunci cînd dorim să subliniem, că nu se ştie dinainte care va fi valoarea acestei variabile. Deasemenea în spatele acestor cuvinte se ascunde şi neştirea cum ar arăta această variabilă.</p>
<p>Însă un matematician utilizează aceleaşi cuvinte – „variabilă aleatoare”, punînd în sensul acestor cuvinte ceva bine determinat. Într-adevăr, spune un matematician, noi nu ştim ce valoare va primi variabila aleatoare în cazul dat concret, dar noi putem determina ce valori poate primi această variabilă, şi putem calcula care este probalilitate de apariţie a evenimentelor.</p>
<p>Pe baza acestor date noi nu putem să anticipăm care ar fi rezultatul unui experiment legat de această mărime, dar noi putem să ştim care ar fi rezultatul unei serii întregi de experimente. Cu cît este mai mare numărul de experimente cu atît mai exact putem să prezicem care va fi rezultatul.</p>
<p>Pentru a defini o variabilă aleatoare, trebuie să indicăm ce valori ar putea lua această variabilă şi care sunt probabilităţile de apariţie ale acestor valori.</p>
<p>Există două tipuri de variabile aleatoare: continue şi discrete.</p>
<p><strong> </strong></p>
<h2>§1. Variabile aleatoare continue</h2>
<p><strong> </strong></p>
<p>Variabile aleatoare, valorile căreia aparţin unui interval, se numeşte continuă.</p>
<p>În cazuri particulare acesta poate fi nu un singur interval, dar reuniunea a mai multor intervale. Intervalele pot fi finite, parţial finite sau infinite, de exemplu:  (<em>a</em>;<em> b</em>], (–µ ; <em>a</em>), [<em>b</em>;µ), (–µ; µ).</p>
<p>În general variabila aleatoare continuă este o abstractizare. Вообще непрерывная случайная величина – это абстракция. Obuzul, lansat de un proectil, poate să parcurgă o distanţă cuprinsă între 5 şi 5,3 km, dar nimănui nu-i va veni în gînd să măsoare această distanţă cu exactitatea de pînă la milimetri, nemaivorbind de exactitatea absolută. În practică această distanţă va fi o variabilă aleatoare discretă, la care fiecare valoare a variabilei se deosebeşte de alta cel puţin cu distanţa de un metru.</p>
<p>La descrierea unei variabile aleatoare continue principial nu pot fi scrise şi numerotate toate valorile pe care le poate lua această variabilă, care aparţin unui interval destul de îngust. Aceste valori formează o mulţime nenumărabilă, care se numeşte „”continuu”.</p>
<p>Dacă x este o variabilă aleatoare continuă, atunci egalitatea x = <em>х</em> reprezintă în sine, ca şi în cazul variabilei aleatoare discrete, un careva eveniment aleator, dar pentru variabila aleatoare continuă acest eveniment poate fi legat cu o probabilitate egală cu zero, ceea ce nu indică că evenimentul este imposibil. Aşa de exemplu, putem spune, că obuzul va parcurge distanţa de 5245,7183m cu probabiliatea zero, sau, că diametrului unei piese deviază de la cel ideal cu 0,001059 milimetri. În aceste cazuri este greu să ne dăm seam  - avut loc experimentul sau nu, deoarece măsurarea acestor mărim se efectuiază cu o careva eroare, şi în calitate de rezultat pot fi doare indicate limitele între care se va afla mărimea dată.</p>
<p>Valorilor variabilelor aleatoare le este specifică o careva nedeterminare. De exemplu, nu are sens distingem două valori care se abat de la valoarea matematic ideală cu 0,5mm şi 0,5000025mm. Probabilitatea, diferită de zero, poate fi legată doar cu nimerirea  mărimii în intervalul dat, chiar dacă este destul de îngust.</p>
<p>Fie x – o variabilă aleatoare continuă. Vom cerceta pentru un careva număr <em>х </em>probabilitatea inegalităţii  <em>х</em> &lt; x &lt; <em>х </em>+ D<em>х</em></p>
<p><em>P</em>(<em>х</em> &lt; x &lt; <em>х </em>+ D<em>х</em>).</p>
<p>Aici D<em>х –</em> mărimea unui interval îngust.</p>
<p>Evident, că dacă  D<em>х </em>® 0, atunci <em>P</em>(<em>х</em> &lt; x &lt; <em>х </em>+ D<em>х</em>)<em> </em>® 0. Notăm prin <em>р</em>(<em>х</em>) limita raportului <em>P</em>(<em>х</em> &lt; x &lt; <em>х </em>+ D<em>х</em>) la D<em>х , </em>cînd D<em>х </em>® 0, dacă această limită există:</p>
<p>Funcţia <em>р</em>(<em>х</em>) se numeşte <em>densitatea de repartiţie </em>a variabilea aleatoare. Di for formula (1) rezultă egalitatea, care este adevărată pentru valori foarte mici lae lui D<em>х</em> şi care poate fi considerată definirea funcţiei  <em>р</em>(<em>х</em>):</p>
<p><em>P</em>(<em>х</em> &lt; x &lt; <em>х </em>+ D<em>х</em>)</p>
<p>Evident, că funcţia <em>p</em>(<em>x</em>) este o funcţie nenegativă. Pentru definirea probabilităţii, că variabila aleatoare x va lua valori din intervalul [<em>a</em>, <em>b</em>] de lungime finită, vom alege pe acest interval numerele arbitrare <em>x</em><sub>1</sub>, <em>х</em><sub>2</sub>,¼, <sub> </sub><em>х<sub>n</sub></em> care satisfac condiţiei <em>а=х</em><sub>0</sub>&lt;<em>х</em><sub>1</sub>&lt;<em>x</em><sub>2</sub>&lt;¼&lt;<em>x<sub>n</sub></em>&lt;<em>b=x<sub>n+</sub></em><sub>1</sub>. Aceste numere impart intervalul [<em>a</em>, <em>b</em>] în <em>n</em>+1 părţi, care nu sunt altceva decît tot nişte intervale [<em>х</em><sub>0</sub>, <em>х</em><sub>1</sub>), [<em>х</em><sub>1</sub>, <em>х</em><sub>2</sub>), ¼,[<em>х<sub>n</sub></em>, <em>b</em>]. Introducem notaţiile:</p>
<p>D<em>х</em><sub>0</sub>=<em> х</em><sub>1 </sub>–<em> х</em><sub>0</sub>, D<em>х</em><sub>1</sub>=<em> х</em><sub>2 </sub>–<em> х</em><sub>1</sub>, ¼, D<em>х<sub>n </sub></em>= <em>b – х<sub>n</sub></em>,</p>
<p>şi formăm suma</p>
<p><a rel="attachment wp-att-151" href="http://resurse-educationale.uv.ro/?attachment_id=151">teza_var_aleatoare</a></p>
]]></content:encoded>
			<wfw:commentRss>http://resurse-educationale.uv.ro/?feed=rss2&#038;p=150</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sisteme de numeraţie. Congruenţe. Rezolvarea problemelor în limbajul de programare Pascal</title>
		<link>http://resurse-educationale.uv.ro/?p=146</link>
		<comments>http://resurse-educationale.uv.ro/?p=146#comments</comments>
		<pubDate>Thu, 17 Mar 2011 08:40:16 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Informatica aplicata]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Teze]]></category>
		<category><![CDATA[congruente]]></category>
		<category><![CDATA[programare]]></category>
		<category><![CDATA[reprezentarea numerelor]]></category>
		<category><![CDATA[sisteme de numereaţie]]></category>
		<category><![CDATA[teza]]></category>

		<guid isPermaLink="false">http://resurse-educationale.uv.ro/?p=146</guid>
		<description><![CDATA[În calculatoarele digitale informaţia de orice categorie este reprezentată, stocată şi prelucrată în formă numerică. Numerele se reprezintă prin simboluri elementare numite cifre. Totalitatea regulilor de reprezentare a numerelor împreună cu mulţimea cifrelor poartă denumirea de sistem de numeraţie. Există &#8230; <a href="http://resurse-educationale.uv.ro/?p=146">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>În calculatoarele digitale informaţia de orice categorie este reprezentată, stocată şi prelucrată în formă numerică. Numerele se reprezintă prin simboluri elementare numite <strong>cifre</strong>. <strong>Totalitatea regulilor de reprezentare a numerelor împreună cu mulţimea cifrelor poartă denumirea de <em>sistem de numeraţie</em>.</strong> Există două tipuri de sisteme de numeraţie: <em> sisteme poziţionale de numeraţie şi sisteme nepoziţionale de numeraţie</em>.</p>
<p>Un sistem de numeraţie poziţional este caracterizat de baza sa. Numărul cifrelor defineşte <strong>baza sistemului de numeraţie.</strong> Pentru un sistem de numeraţie poziţional este justă următoarea egalitate:</p>
<p>X(q)=a<sub>n</sub>q<sup>n</sup>+a<sub>n-1</sub>q<sup>n-1</sup>+&#8230;+a<sub>1</sub>q<sup>1</sup>+a<sub>0</sub>q<sup>0</sup>+a<sub>-1</sub>q<sup>-1</sup>+&#8230;+a<sub>-m</sub>q<sup>-m</sup>,          (1)</p>
<p>unde q – baza sistemului poziţional de numeraţie, un număr întreg; X(q) – un număr arbitrar reprezentat în sistemul de numeraţie poziţional cu baza q; a<sub>i</sub> – coeficienţii şirului (cifrele sistemului de numeraţie); n, m – numărul de clase întregi şi fracţionare. În practică se utilizează forma prescurtată de reprezentare a numerelor, adică X(q)=a<sub>n</sub>a<sub>n-1</sub>&#8230;a<sub>1</sub>a<sub>0</sub>a<sub>-1</sub>&#8230;a<sub>-m</sub>.</p>
<p>Egalitatea (1) se utilizează şi pentru conversia numerelor reprezentate într-un sistem poziţional de numeraţie cu baza q în echivalentul său zecimal.</p>
<p>Conversia numărului zecimal X<sub>10</sub> în echivalentul său în baza q se efectuează conform următoarelor reguli:</p>
<p>Întrucât 8=2<sup>3</sup>, conversia <strong>binar – octală</strong> şi <strong>octal – binară</strong> se poate face direct. Orice cifră octală se reprezintă prin trei cifre binare, numită triadă:</p>
<p>0 = 000           4 = 100</p>
<p>1 = 001           5 = 101</p>
<p>2 = 010           6 = 110</p>
<p>3 = 011           7 = 111.</p>
<p>Dacă se consideră un număr octal, pentru conversia în binar se va scrie fiecare cifră octală prin trei cifre binare.</p>
<p>Dacă se consideră un număr binar, pentru conversia în octal se vor grupa cîte trei cifre binare, pornind de la poziţia virgulei spre stînga pentru partea întreagă, respectiv dreapta pentru partea fracţionară, găsind corespondentul octal. Pentru completarea unui grup de trei cifre binare, zerourile din faţa numărului, respectiv după ultima cifră a părţii fracţionare nu modifică semnificaţia numărului.</p>
<p>Într-un mod similar se procedează şi în cazul sistemului hexazecimal, baza căruia 16=2<sup>4</sup>. Orice cifră hexazecimală se reprezintă prin 4 cifre binare, numită tetradă:</p>
<p>0 = 0000               8 = 1000</p>
<p>1 = 0001               9 = 1001</p>
<p>2 = 0010               A = 1010</p>
<p>3 = 0011               B = 1011</p>
<p>4 = 0100               C = 1100</p>
<p>5 = 0101               D = 1101</p>
<p>6 = 0110               E = 1110</p>
<p>7 = 0111               F = 1111.</p>
<p><a rel="attachment wp-att-147" href="http://resurse-educationale.uv.ro/?attachment_id=147">teza_sisteme</a></p>
]]></content:encoded>
			<wfw:commentRss>http://resurse-educationale.uv.ro/?feed=rss2&#038;p=146</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sistem de calcul. Algoritmică. Programare</title>
		<link>http://resurse-educationale.uv.ro/?p=142</link>
		<comments>http://resurse-educationale.uv.ro/?p=142#comments</comments>
		<pubDate>Thu, 17 Mar 2011 08:37:07 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Pascal]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[algoritmi]]></category>
		<category><![CDATA[algoritmica]]></category>
		<category><![CDATA[gindirea algoritmica]]></category>
		<category><![CDATA[programare]]></category>
		<category><![CDATA[sistem de calcul]]></category>

		<guid isPermaLink="false">http://resurse-educationale.uv.ro/?p=142</guid>
		<description><![CDATA[Dezvoltarea informaticii actuale se datorează cercetărilor, rezultatelor şi experienţelor din domeniile sistemelor de calcul, algoritmicii şi programării, dar mai ales a interdependenţei acestor domenii prin aşa-numita triadă: sistem de calcul &#8211; algoritmică &#8211; programare La baza acestei interdependenţe se află &#8230; <a href="http://resurse-educationale.uv.ro/?p=142">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<h4>Dezvoltarea informaticii actuale se datorează cercetărilor, rezultatelor şi experienţelor din domeniile sistemelor de calcul, algoritmicii şi programării, dar mai ales a interdependenţei acestor domenii prin aşa-numita triadă:</h4>
<h4>sistem de calcul &#8211; algoritmică &#8211; programare</h4>
<p>La baza acestei interdependenţe se află conceptul de algoritm, concept ce a construit  pentru om o nouă filosofie: gândirea algoritmică. Această gândire algoritmică a facut posibilă apariţia şi dezvoltarea Tehnologiei Informaţiei (IT) ce reprezintă de fapt implementarea filosofiei procesării, gestionării şi comunicării informaţiilor.</p>
<p>Întâmplător sau nu, deceniul 7 al sec. XX a fost deceniul marilor schimbări în domeniul informaticii şi al sistemelor de calcul:</p>
<p>Toate aceste aspecte au fost şi sunt într-o interdependenţa continuă ţinând seama de particularitatea informaticii care oferă sisteme de calcul performante şi produse-program competitive în rezolvarea problemelor. Utilizarea eficientă a sistemelor de calcul şi a produselor-program reclamă o instruire continuă, atât pentru informaticieni-programatori, cât şi pentru utilizatori.</p>
<p><strong>Gîndirea algoritmică</strong> trebuie să se aiba în vedere în instruire, şi atunci când se invaţă algoritmică (metode şi tehnici), şi atunci când se invaţă programarea (limbaje de programare). Practica instruirii elevilor şi studenţilor a demonstrat că invăţarea unui limbaj de programare este, în general, mai uşoară decat invăţarea elaborarii algoritmilor (algoritmică). Acest lucru se poate justifica prin faptul că elaborarea unui algoritm este echivalentă cu implementarea (reprezentarea) raţionamentelor (procese demonstrative) deduse din <strong>metode </strong><strong>şi</strong><strong> tehnici</strong> utilizate în rezolvarea unei probleme. <strong>Rezolvarea problemelor</strong> necesită nu numai cunoştinţe clare şi precise, dar şi capacitate de sinteză şi control şi mai ales capacitate de creaţie. Dacă vrem să facem o analogie, un programator poate fi compozitorul ce realizează o lucrare muzicală.</p>
<p>Succesele unui programator depind de cunoaşterea foarte bine a programării într-un limbaj de programare modern, dar mai ales depind de bogatia şi stapanirea cunoştinţelor în elaborarea algoritmilor. Şi mai este ceva: experinţa acumulată în activitatea de rezolvare a problemelor prin formarea unei gândiri algoritmice solide şi consistente.</p>
<p><a rel="attachment wp-att-143" href="http://resurse-educationale.uv.ro/?attachment_id=143">teza_congruenta</a></p>
]]></content:encoded>
			<wfw:commentRss>http://resurse-educationale.uv.ro/?feed=rss2&#038;p=142</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Aplicaţii ale arborilor în programare.</title>
		<link>http://resurse-educationale.uv.ro/?p=134</link>
		<comments>http://resurse-educationale.uv.ro/?p=134#comments</comments>
		<pubDate>Thu, 17 Mar 2011 08:31:09 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Grafuri]]></category>
		<category><![CDATA[Pascal]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[arbori binari]]></category>
		<category><![CDATA[extraşcolar]]></category>
		<category><![CDATA[grafuri]]></category>
		<category><![CDATA[programare]]></category>
		<category><![CDATA[teza]]></category>

		<guid isPermaLink="false">http://resurse-educationale.uv.ro/?p=134</guid>
		<description><![CDATA[Dacă oricare două vîrfuri x, yÎV sînt unite printr-un lanţ simplu unic, atunci orice muchie [x, y]ÎU reprezintă  unicul lanţ dintre  x şi y. Suprimînd muchia [x, y], între x şi y nu va mai exista lanţ, deci graful obţinut &#8230; <a href="http://resurse-educationale.uv.ro/?p=134">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Dacă oricare două vîrfuri x, yÎV sînt unite printr-un lanţ simplu unic, atunci orice muchie [x, y]ÎU reprezintă  unicul lanţ dintre  x şi y. Suprimînd muchia [x, y], între x şi y nu va mai exista lanţ, deci graful obţinut nu va mai fi conex.</p>
<p><em> </em>3 Þ 4</p>
<p>Notăm cu n numărul de vîrfuri şi cu m numărul de muchii din graf.</p>
<p>Pentru a demonstra că orice graf conex minimal are n-1 muchii vom demonstra prin inducţie completă după n că  m £ n-1. Cum în orice graf conex m ³ n-1, deducem m = n-1.</p>
<p>P(1)                 Dacă n = 1, atunci m = 0 Þ  m = n-1.</p>
<p>P(2)                 Dacă n = 2, atunci  m =1 Þ  m = n-1.</p>
<p>P(n)                 Presupunem că într-un graf conex minimal cu cel mult n vîrfuri numărul de muchii este strict mai mic decît numărul de vîrfuri.</p>
<p>P(n+1)              Demonstrăm că într-un graf conex minimal cu n+1 vîrfuri, numărul de muchii este cel mult egal cu n.</p>
<p>Fie G conex minimal cu n+1 vîrfuri şi m muchii. Eliminînd o muchie oarecare din graf obţinem un graf G&#8217; cu m-1 muchii şi două componente conexe C<sub>1</sub> şi C<sub>2</sub> cu n<sub>1</sub>, respectiv n<sub>2</sub> vîrfuri (n<sub>1</sub>+n<sub>2 </sub>= n+1) şi m<sub>1</sub>, respectiv m<sub>2</sub> muchii (m<sub>1</sub>+m<sub>2 </sub>= m-1). Subgrafurile C<sub>1</sub> şi C<sub>2 </sub>sînt conexe minimale, altfel graful G nu ar fi conex minimal. Din ipoteza inductivă rezultă că m<sub>1 </sub>£ n<sub>1</sub>-1, m<sub>2</sub><sub> </sub>£ n<sub>2</sub>-1; dar m<sub>1</sub>+m<sub>2 </sub>= m-1 £ n<sub>1</sub>+n<sub>2 </sub>= n-2 Þ m £ n-1. Deci G conex minimal implică G conex cu n-1 muchii.</p>
<p>4 Þ 5</p>
<p>Fie G un graf conex cu n-1 muchii. Să demonstrăm că G este aciclic.</p>
<p>Presupunem prin reducere la absurd, că graful G conţine un ciclu C format din  vîrfurile v<sub>1</sub>, v<sub>2</sub>, &#8230;, v<sub>k</sub>.</p>
<p>Să considerăm subgraful parţial G<sub>k </sub>= (V<sub>k</sub>, U<sub>k</sub>) constînd  din ciclul C. Deci V<sub>k </sub>= {v<sub>1</sub>, v<sub>2 </sub>,&#8230;, v<sub>k</sub>}, iar U<sub>k </sub>= {[v<sub>1</sub>,v<sub>2</sub>)], [v<sub>2</sub>,v<sub>3</sub>],&#8230;,[v<sub>k-1</sub>,v<sub>k</sub>], (v<sub>k</sub>,v<sub>1</sub>]} (½V<sub>k</sub>½=½U<sub>k</sub>½= k). Dacă  ½V<sub>k</sub>½&lt;½V½, atunci  $v<sub>i</sub>ÎV<sub>k</sub> şi v<sub>k</sub><sub>+</sub><sub>1</sub>ÎV-V<sub>k</sub> astfel încît [v<sub>i</sub>, v<sub>k</sub><sub>+</sub><sub>1</sub>]ÎU, graful G fiind conex.</p>
<p>Construim G<sub>k</sub><sub>+</sub><sub>1 </sub>= (V<sub>k</sub><sub>+</sub><sub>1</sub>, U<sub>k</sub><sub>+</sub><sub>1</sub>) în modul următor: V<sub>k</sub><sub>+</sub><sub>1 </sub>= V<sub>k</sub> È{v<sub>k</sub><sub>+</sub><sub>1</sub>};     U<sub>k</sub><sub>+</sub><sub>1</sub>=U<sub>k</sub>È{[v<sub>i</sub>,v<sub>k</sub><sub>+</sub><sub>1</sub>]} şi ½U<sub>k</sub><sub>+</sub><sub>1</sub>½=½V<sub>k</sub><sub>+</sub><sub>1</sub>½=k+1.</p>
<p>Cît timp k+1 &lt; n, aplicăm acelaşi procedeu pînă cînd obţinem un graf  G<sub>n </sub>= (V, U<sub>n</sub>), cu ½U<sub>n</sub>½= n, U<sub>n </sub>Í U; deci ½U½ ³ n, contradicţie cu ipoteza ½U½= n-1.</p>
<p>5 Þ 6</p>
<p>Presupunem că graful G este aciclic cu n-1 muchii, să demonstrăm că G este aciclic maximal.</p>
<p>Fie C<sub>1</sub>, C<sub>2</sub>,&#8230;, C<sub>p</sub> cele p componentele conexe ale grafului G, avînd respectiv n<sub>1</sub>, n<sub>2</sub>,&#8230;, n<sub>p</sub> vîrfuri şi m<sub>1</sub>, m<sub>2</sub>,&#8230;, m<sub>p</sub> muchii fiecare. Evident că n<sub>1</sub>+n<sub>2</sub>+&#8230;+n<sub>p </sub>= n  şi m<sub>1</sub>+m<sub>2</sub>+&#8230;+m<sub>p </sub>= n-1.</p>
<p>Cum graful G este aciclic, deducem că fiecare componentă conexă este un arbore. Deoarece am demonstrat că 1 Þ 5, rezultă că m <sub>i</sub>= n<sub>i</sub>-1, &#8220;iÎ{1, 2, &#8230;, p}. Înlocuind în relaţia de mai sus, obţinem  n-p = n-1 Þ  p = 1, deci G conex. Dacă G este conex şi aciclic, conform definiţiei G este arbore. Dar am demonstrat că 1 Þ 2, deci oricare două vîrfuri din G sînt unite printr-un lanţ simplu. Astfel, adăugînd orice muchie obţinem un ciclu.</p>
<p>6 Þ 1</p>
<p><em> </em>Presupunem că graful G este aciclic, dar dacă am mai adăuga o muchie s-ar obţine un ciclu. Să demonstrăm că G este conex.</p>
<p>Fie u şi v două vîrfuri neadiacente din graf, arbitrar alese. Deoarece adăugînd muchia [u, v] se obţine un ciclu, rezultă că u şi v sînt unite printr-un lanţ ale cărui muchii aparţin grafului G. Cum u,v au fost alese arbitrar, deducem că graful G este conex.</p>
<p>Q.E.D.</p>
<p><strong> </strong></p>
<p><strong> </strong></p>
<p><strong> </strong></p>
<p><strong>Teorema 2 </strong></p>
<p>Numerele întregi 0 &lt; d<sub>1 </sub>£ d<sub>2 </sub>£ &#8230;£ d<sub>n</sub> (n ³ 2) sînt gradele vîrfurilor unui arbore dacă şi numai dacă d<sub>1</sub>+d<sub>2</sub>+&#8230;+d<sub>n </sub>= 2n-2.</p>
<p><em> </em></p>
<p><em>Demonstraţie</em>:</p>
<p><em>Necesitatea </em> Condiţia este necesară, deoarece orice arbore cu n vîrfuri are n-1 muchii, iar suma gradelor vîrfurilor oricărui graf este de două ori numărul de muchii. Deci d<sub>1</sub>+d<sub>2</sub>+&#8230;+d<sub>n </sub>= 2n-2.</p>
<p><em>Suficienţa</em> Fie 0 &lt; d<sub>1 </sub>£ d<sub>2 </sub>£&#8230;£ d<sub>n</sub> astfel încît d<sub>1</sub>+d<sub>2</sub>+&#8230;+d<sub>n </sub>= 2n-2.</p>
<p>Să demonstrăm că există un arbore cu gradele vîrfurilor d<sub>1</sub>, d<sub>2</sub>,&#8230;, d<sub>n</sub>. Vom proceda prin inducţie.</p>
<p>P(2)                 Dacă d<sub>1</sub>+d<sub>2 </sub>= 2, atunci d<sub>1 </sub>= d<sub>2 </sub>= 1 , arborele fiind cel din figura de mai jos:</p>
<p>Fig. 3</p>
<p>P(n)                 Presupunem acum că proprietatea este adevărată pentru orice secvenţă de n numere naturale 0 &lt; d<sub>1 </sub>£ d<sub>2 </sub>£ &#8230;£ d<sub>n</sub>, astfel încît d<sub>1</sub>+d<sub>2</sub>+&#8230;+d<sub>n </sub>= 2n-2.</p>
<p>P(n+1)             Să demonstrăm că pentru orice secvenţă 0 &lt; d&#8217;<sub>1 </sub>£ d&#8217;<sub>2 </sub>£&#8230;£ d&#8217;<sub>n </sub>£ d&#8217;<sub>n</sub><sub>+</sub><sub>1</sub> astfel încît d&#8217;<sub>1</sub>+d&#8217;<sub>2</sub>+&#8230;+d&#8217;<sub>n</sub><sub>+</sub><sub>1 </sub>= 2n, există un arbore cu n+1 vîrfuri cu secvenţa gradelor d&#8217;<sub>1</sub>, d&#8217;<sub>2</sub>, &#8230;, d&#8217;<sub>n</sub><sub>+</sub><sub>1</sub>.</p>
<p>Observăm că există măcar un nod terminal x<sub>1</sub> cu gradul d&#8217;<sub>1</sub>=1, altfel dacă  d<sub>i </sub>³ 2,&#8221;iÎ{1, 2,&#8230;, n+1} Þ d&#8217;<sub>1</sub>+d&#8217;<sub>2</sub>+&#8230;+d&#8217;<sub>n</sub><sub>+</sub><sub>1 </sub>³ 2(n+1), ceea ce contrazice ipoteza. În mod analog, observăm că există măcar un nod neterminal  x<sub>n</sub><sub>+</sub><sub>1</sub>, cu gradul d&#8217;<sub>n</sub><sub>+</sub><sub>1 </sub>&gt; 1, altfel dacă d&#8217;<sub>i </sub>= 1,&#8221;iÎ{1, 2, &#8230;, n+1} Þ d&#8217;<sub>1</sub>+d&#8217;<sub>2</sub>+&#8230;+d&#8217;<sub>n</sub><sub>+</sub><sub>1 </sub>= n+1 &lt; 2n .</p>
<p>Să considerăm următoarea secvenţă de n numere întregi d&#8217;<sub>2</sub>,&#8230;, d&#8217;<sub>n</sub>, d&#8217;<sub>n</sub><sub>+</sub><sub>1</sub>-1 cu proprietatea că d&#8217;<sub>2</sub>+&#8230;+d&#8217;<sub>n</sub>+d&#8217;<sub>n</sub><sub>+</sub><sub>1 </sub>= 2n-2. Din ipoteza inductivă există un arbore A<sub>n</sub> cu n vîrfuri şi secvenţa gradelor d&#8217;<sub>2</sub>,&#8230;, d&#8217;<sub>n</sub>, d&#8217;<sub>n</sub><sub>+</sub><sub>1</sub>-1. Adăugăm la arborele A<sub>n</sub> un vîrf pe care îl unim printr-o muchie cu vîrful avînd gradul d&#8217;<sub>n</sub><sub>+</sub><sub>1</sub>-1. Obţinem un arbore A<sub>n</sub><sub>+</sub><sub>1</sub> cu gradele vîrfurilor d&#8217;<sub>1</sub>, d&#8217;<sub>2</sub>,&#8230;, d&#8217;<sub>n</sub><sub>+</sub><sub>1</sub>.</p>
<p>Q.E.D.</p>
<p>Demonstraţia acestei teoreme oferă şi o soluţie constructivă pentru obţinerea unui arbore cu secvenţa gradelor dată.</p>
<p>Vom reţine gradele vîrfurilor într-un vector d de dimensiune n, ordonat crescător, cu suma componentelor egală cu 2n-2.</p>
<p>Arborele va fi reprezentat prin matricea muchiilor, o matrice a cu două linii şi n-1 coloane, în care pentru fiecare muchie din arbore vom reţine extremităţile.</p>
<p>Spre deosebire de ideea din demonstraţie, pentru a conserva ordinea în vectorul d, la fiecare pas al algoritmului gradul care va fi decrementat va fi primul grad mai mare ca 1 şi nu ultimul.</p>
<p><a rel="attachment wp-att-135" href="http://resurse-educationale.uv.ro/?attachment_id=135">Capit1</a></p>
<p><a rel="attachment wp-att-136" href="http://resurse-educationale.uv.ro/?attachment_id=136">Capit2_partea1</a></p>
<p><a rel="attachment wp-att-137" href="http://resurse-educationale.uv.ro/?attachment_id=137">Capit2_partea2</a></p>
]]></content:encoded>
			<wfw:commentRss>http://resurse-educationale.uv.ro/?feed=rss2&#038;p=134</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Analiza timpului de calcul.</title>
		<link>http://resurse-educationale.uv.ro/?p=130</link>
		<comments>http://resurse-educationale.uv.ro/?p=130#comments</comments>
		<pubDate>Thu, 17 Mar 2011 08:26:44 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Pascal]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Teze]]></category>
		<category><![CDATA[algoritm]]></category>
		<category><![CDATA[analiza]]></category>
		<category><![CDATA[calcul]]></category>
		<category><![CDATA[programare]]></category>
		<category><![CDATA[teza]]></category>
		<category><![CDATA[timp]]></category>

		<guid isPermaLink="false">http://resurse-educationale.uv.ro/?p=130</guid>
		<description><![CDATA[Ne propunem să lămurim modul în care se estimează timpul de calcul necesar unui program pentru a furniza rezultatul. Să considerăm, una din cele mai simple probleme. Se dă un vector cu n componente. Se cere sa se calculeze maximul &#8230; <a href="http://resurse-educationale.uv.ro/?p=130">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Ne propunem să lămurim modul în care se estimează timpul de calcul necesar unui program pentru a furniza rezultatul.</p>
<p>Să considerăm, una din cele mai simple probleme. Se dă un vector cu n componente. Se cere sa se calculeze maximul dintre componentele sale.</p>
<p>Reamintim, pe scurt algoritmul:</p>
<p>Timpul de calcul depinde, în primul rînd, de lungimea(mărimea) datelor de  intrare, pe care o vom nota cu n.</p>
<p>Exemple:</p>
<p>Pentru a calcula timpul de calcul ar trebui inventariem toate instrucţiunile programului şi să ştim d cîte ori se execută fiecare din ele(în funcţie de n).Mai mult, ar trebuie să cunoaştem cît durează execuţia fiecărui tip de instrucţiune.</p>
<p>Observaţie 1.</p>
<p>Exemplu. Pentru calculul maximului, nu putem şti de cîte ori se execută atribuirea max:=v[i]. Cu toate acestea putem considera că există o proporţionalitate între valoarea n şi numărul de execuţii.</p>
<p>Observaţia 2.</p>
<p>Datorită acestor considerate vom proceda astfel.</p>
<p>Se alege o operaţie numită operaţie de bază, şi se vede de cîte ori se execută aceasta. Cerinţa pentru operaţia de bază este ca aceasta să se execute de un număr de ori, numărul care să poată calcula de la început pornind de la n.</p>
<p>Exemplu.</p>
<p>În astfel de cazuri(cînd avem de ales între mai multe operaţii de bază), vom alege acea operaţie care corespunde cît mai bine scopului propus.</p>
<p>Astfel, dacă analizăm un algoritm de generare a permutării comparativ cu altele de aceeaşi natură vom alege ca operaţie de bază comparaţia.</p>
<p>În cazul în care analizăm un algoritm oarecare, în care soluţia este sub formă de permutare, putem considera ca operaţie de bază permutarea. Problema se spune în felul următor: dacă căutăm soluţia printre toate permutările pe care se pot genera vom avea n! căutări(un număr imens !), oare nu se poate altfel?</p>
<p>Exemple de probleme la care se foloseşte un astfel de raţionament: problema comis voiajorului, problema celor n dame.</p>
<p>Timpul estimat de calcul se trece sub formă aproximativă astfel:</p>
<p>O(număr estimat de execuţii ale operaţiei de bază)</p>
<p>Exemplu de exprimare a timpului.</p>
<p>Dacă un algoritm efectuiază 3n<sup>2</sup>+7n+5 operaţii de bază, vom spune că aceasta este un algoritm cu O(n<sup>2</sup>).</p>
<p>Exemple.</p>
<p>În cazul de faţă operaţia aleasă este cea de comparare. Pentru un vector cu n componente se fac n-1 comparaţii. Aceasta înseamnă că dacă vectorul are o sută de componente se fac 99 de comparaţii ş.a.m..d.. Se poate demonstra faptul că un algoritm mai bun nu există!</p>
<p>2.  Pentru generarea permuntărilor(în cazul în care se consideră ca operaţie de bază generarea unei permutări) timpul estimat de calcul este O(n!).</p>
<p>În anumite cazuri nu putem preciza nici macar numărul de execuţie ale operaţiilor de bază.</p>
<p>Exemplu. Sortarea prin interschimbare(vezi 6.2.1). În cazul în care vectorul este sortat se execută n-1 comparaţii (se parcurge vectorul o singură dată), dacă vectorul este sortat invers se execută n(n-1)/2 operaţii de bază (se parcurge vectorul de n ori).</p>
<p>În astfel de cazuri se poate considera:</p>
<p>De fiecare dată cînd se trece timpul estimat se precizează despre care este vorba (minim, mediu, maxim). În practică, prezintă interes timpul madiu sau maxim.</p>
<p>Dacă timpul estimat este sub forma O(n<sup>k</sup>), k=N*, spunem că algoritmul este în timp polinomial.</p>
<p>Exemlu. Sortarea prin interschimbare are timpul (mediu, maxim) polinomial şi anume O(n<sup>2</sup>).</p>
<p>Un algoritm în O(n) se numeşte algoritm liniar.</p>
<p>Dacă un algoritm are un timp estimat O(2<sup>n</sup>), O(3<sup>n</sup>).. spunem că algoritmul este în timp exponenţial.</p>
<p>Un algoritm în timp O(n!) este asimilat unui algoritm în timp exponenţial.</p>
<p>n!=1x2x&#8230;n&lt;2x2x&#8230;.x2=2<sup>n-1</sup>.</p>
<p>În practică nu sunt admişi decît algoritm în timp polinomial, deşi nu este deloc indiferent gradul polinomului.</p>
<p>Şi totuşi pentru ce tot acest efort de estimare a timplui de calcul? Oare viteza de lucru a unui calculator nu este atît de mare, în cît abstracţie făcînd de cîteva minute de calcul, în plus sau în minus, să renunţăm la estimarea lui? Răspunsul la această la această întrebarea este categoric negativ. Mai mult timpul de calcul este esenţial dacă este prea mare algoritmul nu are nici un fel de valoare practică. Să ne imaginăm un algoritm care are un timp de calcul O(2<sup>n</sup>). Dacă n este de 10, calculatorul va efectua aproximativ 1024 operaţii elementare. Dacă n este 100 acesta va trebui să efectueze 1024<sup>*</sup>1024<sup>*</sup>&#8230;<sup>*</sup>1024 operaţii elementare, adică un număr mai mare decît 1000<sup>*</sup>1000<sup>*</sup>&#8230;<sup>*</sup>1000 adică 1000000&#8230;0000 (de treizeci de ori). Aceasta este un număr imens. Dar dacă n este 1000? pentru un n nu foarte mare, nici cel mai modern calculator din lume nu scoate rezultatul decît în sute sau în mii de ani. De astfel ce înseamnă în asemenea cazuri un calculator modern? Să presupunem că un sistem PENTIUM are o viteză de circa 25 de ori mai mare decît un sistem XT. Să presupunem că avem un program care are un timp de calcul de ordinul O(2<sup>n</sup>). Se cere să rezolvăm o problemă pentru n=30. Fie că timpul necesar rulării acestei probleme pe un XT. Această problemă va fi rulată pe PENTIUM în timpul t/25. Dorim să rezolvăm problema pe PENTRIUM pentru n=35 (n a crescut numai cu 5). Dar 2<sup>35</sup>=2<sup>30*</sup>2<sup>5</sup>=32<sup>*</sup>2<sup>30</sup>. Deci dacă n a crescut cu 5, vom avea nevoie de mai mult timp de lucru să rezolvăm problema pe PENTIUM decît timpul pentru rezolvarea ei pentru n=30 pe XT.</p>
<p>Vă daţi seama ce înseamnă un timp de calcul de ordinul O(2<sup>n</sup>)? Sporul lui n cu o singură unitate duce la dublarea timpului de calcul.</p>
<p>Ce concluzie tragem de aici? De cîte ori avem de rezovat o problemă căutăm pentru aceasta un algoritm în timp polinomial (polinomul va avea gradul minim). Mai mult căutăm un algoritm care să rezovle problema în timp polinomial de grad minim.</p>
<p><a rel="attachment wp-att-131" href="http://resurse-educationale.uv.ro/?attachment_id=131">analiza timpului de calcul</a></p>
]]></content:encoded>
			<wfw:commentRss>http://resurse-educationale.uv.ro/?feed=rss2&#038;p=130</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Iniţializare grafică în Pascal.</title>
		<link>http://resurse-educationale.uv.ro/?p=126</link>
		<comments>http://resurse-educationale.uv.ro/?p=126#comments</comments>
		<pubDate>Thu, 17 Mar 2011 08:23:05 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Pascal]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Teze]]></category>
		<category><![CDATA[grafica]]></category>
		<category><![CDATA[graphics]]></category>
		<category><![CDATA[modulul grafic]]></category>
		<category><![CDATA[programare]]></category>

		<guid isPermaLink="false">http://resurse-educationale.uv.ro/?p=126</guid>
		<description><![CDATA[Placa grafică sau adaptorul de ecran este componenta hard a calculatorului care asigură gestiunea memoriei şi controlul monitorului video. Driver-ul grafic este componenta soft-ului care comandă placa grafică. Placa grafică tratează ecranul în două moduri: În regimul text fiecare caracter &#8230; <a href="http://resurse-educationale.uv.ro/?p=126">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Placa grafică sau adaptorul de ecran este componenta hard a calculatorului care asigură gestiunea memoriei şi controlul monitorului video. Driver-ul grafic este componenta soft-ului care comandă placa grafică. Placa grafică tratează ecranul în două moduri:</p>
<p>În regimul <strong>text</strong> fiecare caracter ce apare la ecran este păstrat în memoria calculatorului în doi octeţi, unul cuprinde codul ASCII al caracterului, iar al doilea culorile, iluminarea, culoarea fonului şi clipirea. În regimul <strong>grafic</strong> memoria ecranului are un cod pentru fiecare pixel prin care se determină culoarea pixelui.</p>
<p>Zona de memorie ecran pentru memorarea unui ecran se numeşte <strong>pagină video</strong>. Pagina video care apare la un moment dat pe ecran se numeşte <strong>pagină vizibilă</strong>. Prelucrarea informaţiei grafice în Pascal este susţinută de modulul <strong>Graph</strong>.</p>
<p>Modulul <strong>Graph</strong> pune la dispoziţie circa 90 de proceduri şi funcţii păstrate în fişierul graph.tpu. Utilizarea procedurilor şi funcţiilor grafice este posibilă dacă în partea declarativă <strong>uses</strong> vom declara modulul <strong>graph</strong>. Fiecare regim grafic are driver-ul său specific. Tabelul  următor conţine lista regimurilor grafice posibile pentru diferite adaptoare grafice. În prima coloniţă sunt indicare  tipurile de drivere, în a doua – numărul de pixeli de pe ecran, în coloniţa a treia este indicată palitra de culori a regimului dat, în ultima coloniţă sunt indicate numărul de pagini video care se pot încărca simultan în memoria videoadaptorului.</p>
<p>Orice program Turbo Pascal ce conţine prelucrarea informaţiei grafice trebuie să cuprindă:</p>
<p>Iniţializarea regimului grafic se relizează prin procedura <strong>InitGraph</strong> cu formatul:</p>
<p><strong>InitGraph</strong>(var GraphDriver:integer; {tipul adaptorului}</p>
<p>var GraphMode:integer; {regimul grafic}</p>
<p>var DriverPath:string); {calea spre driver}</p>
<p>De exemplu:</p>
<p>procedure ini;</p>
<p>var gd, gm:integer;</p>
<p>begin</p>
<p>gd:=detect;</p>
<p>initgraph(gd,gm,&#8217;c:\tp\bgi&#8217;);</p>
<p>if graphresult&lt;&gt;grok then halt(1);</p>
<p>end;</p>
<h2><em>2. Detecţia rezoluţiei</em></h2>
<p><em>Funcţia GetMaxX întoarce un numar întreg reprezentând numărul maxim de pixeli (rezoluţia), după direcţia orizontală.</em></p>
<p><em>Function GetMaxX:integer;</em></p>
<p><em>Funcţia GetMaxY determină numărul maxim de pixeli (rezoluţia), dupa direcţia verticală.</em></p>
<p><em>Function GetMaxY:integer;</em></p>
<p><em>Funcţia GetMaxColor determină numărul maxim de culori cu care se poate desena pe ecran. </em><em>În mod convenţional, &#8220;culoarea&#8221; 0 este cea neagră, astfel încât numărul de culori &#8220;de lucru&#8221; se află în gama 1..GetMaxColor.</em></p>
<p><em>Function GetMaxColor:word;</em></p>
<p><em>Cele 3 funcţii sunt necesare pentru scrierea de programe ce folosesc modul grafic şi care pot rula pe orice calculator, indiferent de tipul monitorului şi a placii grafice.</em></p>
<h2><em>3. Ecranul în modul grafic</em></h2>
<p><em>Dimensiunea unui element de imagine (pixel) pe direcţia orizontală diferă, în general, de dimensiunea lui pe verticală. Doar adaptoarele mai noi (cum ar fi VGA, VESA) consideră pixelul că având dimensiunile egale pe cele două direcţii.</em></p>
<p><em>Raportul între dimensiunea pe orizontală şi dimensiunea pe verticală a unui pixel se numeşte &#8220;aspect ratio&#8221; (factor/raport de forma).</em></p>
<p><em>Procedura prin care se poate afla factorul de forma este GetAspectRatio.</em></p>
<p><em>PROCEDURE GetAspectRatio(Var xasp,yasp:word ); </em></p>
<p><em>Parametrii </em><strong>xasp</strong><em> şi </em><strong>yasp</strong><em> reprezintă numărul de pixeli pe direcţie orizontală şi verticală necesari pentru a obţine o dimensiune &#8220;reală&#8221;.</em></p>
<p><em>Procedura complementară cu GetAspectRatio este SetAspectRatio, ce modifică factorul de forma la valorile dorite. Parametrii </em><strong>xasp</strong><em>, </em><strong>yasp</strong><em> au semificaţie identică cu cei ce apar în procedura GetAspectRatio.</em></p>
<p><em>Function SetAspectRatio(xasp,yasp:word):word;</em></p>
<h2>4. Noţiunea de cursor grafic</h2>
<p>O noţiune specifică modului grafic este cursorul grafic sau &#8220;curent pointer&#8221;, notat CP. El este similar cu conceptul de cursor din modul text, dar, spre deosebire de acesta, cursorul este invizibil în mod grafic. Poziţia acestui cursor este importantă la trasarea liniilor, scrierea de text etc.</p>
<p>Pentru a determina poziţia curentă a cursorului grafic se folosesc funcţiile GetX pentru coordonata orizontală şi GetY pentru coordonata verticală.</p>
<p><a rel="attachment wp-att-127" href="http://resurse-educationale.uv.ro/?attachment_id=127">Initializare_grafica_pascal</a></p>
]]></content:encoded>
			<wfw:commentRss>http://resurse-educationale.uv.ro/?feed=rss2&#038;p=126</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tipul de date string în Pascal</title>
		<link>http://resurse-educationale.uv.ro/?p=102</link>
		<comments>http://resurse-educationale.uv.ro/?p=102#comments</comments>
		<pubDate>Tue, 01 Feb 2011 11:11:52 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Pascal]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[download]]></category>
		<category><![CDATA[programare]]></category>
		<category><![CDATA[string]]></category>
		<category><![CDATA[tipuri de date]]></category>

		<guid isPermaLink="false">http://resurse-educationale.uv.ro/?p=102</guid>
		<description><![CDATA[Elaborarea cursurilor multimedia instructive prin aplicarea tehnologiilor multimedia nu necesită abilităţi şi cunoştinţe de specialitate în informatică şi sunt accesibile tuturor ce deţin o cultură informaţională adecvată. Dat fiind faptul că sistemele şi tehnologiile multimedia sunt în continuă dezvoltare, cresc &#8230; <a href="http://resurse-educationale.uv.ro/?p=102">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Elaborarea cursurilor multimedia instructive prin aplicarea tehnologiilor multimedia nu necesită abilităţi şi cunoştinţe de specialitate în informatică şi sunt accesibile tuturor ce deţin o cultură informaţională adecvată. Dat fiind faptul că sistemele şi tehnologiile multimedia sunt în continuă dezvoltare, cresc şi performanţele fiecărui tip de programe, fiind mai interesante şi mai captivante.</p>
<p>Un <em>modul</em> este un element simplu şi autonom, care însă poate intra în calitate de componentă într-un ansamblu mai complex.</p>
<p>Se numeşte <em>curs multimedia instructiv</em> (CMI) o reţea de module, create pe baza tehnologiilor multimedia, reprezentînd informaţii multimedia, pentru acumularea cunoştinţelor în orice domeniu disciplinar.</p>
<p>La elaborarea unui curs instructiv asistat de calculator trebuie de pacurs următoarele etape:</p>
<p>După cum s-a meţionat mai sus una din priorităţile instruirii asistate de calculator este aplicarea elementelor multimedia: imagini grafice, imagini 3D, elemente de sunet (voce, mizică), clipuri-video, filme, animaţie. Ele oferă posibilitatea explicării proceselor complexe prin adăugarea efectelor ilustrative multimedia.</p>
<p><em>Obietivul de bază</em> al implementării lecţiilor electronice, incluse în cursurile multimedia instructive este asistarea şi înlocuirea patţială a materiei studiate în mod tradiţional. Deaceea la crearea cursurilor de instruire electronice autorul trebuie să selecteze minuţios temele ce vor fi incluse în curs. Cursul creat trebuie să fie consecutiv şi integru.</p>
<p>Utlizarea tehnologiilor informaţionale asigură instruirea computerizată cu acomodarea la viteza de asimilare a informaţiei pentru fiecare utilizator în parte.</p>
<p>Modulele cursului multimedia elaborat trebuie să conţină un număr suficient de obiecte de navigare, hottascuri (combinaţii de taste), pauze, posibilităţi de anulare (ESC) a unor acţiuni etc. Modumele informaţionale şi paginile cursului pot fi legate prin cuvinte-cheie, legături definite de autor.</p>
<p>E necesar să oferim posibilitatea alegerii de către utilizator a oricărei teme pentru strudiere. Trebuie să asigurăm ieşirea către începutul programului (meniul de bază), cît şi către pagina primară a oricărui modul&#8230;</p>
<p><em>Sugestii şi recomadări</em> de creare a cursului:</p>
<p>Este bine de folosit nu mai mult de trei culori pe o pagină. Alte efecte pot fi obţinute prin schimbarea temporară a culorii fragmentului, care apoi revine la culoarea iniţială.</p>
<p>Documentele grafice sunt informaţii în formă de imagini fixe reprezentînd grafice, schiţe tehnice, desene, imagini foto. Utilizarea imaginilor la crearea unui curs multimedia insctructiv îl face mai explicit, mai interesant, mai captivant</p>
<p>Secvenţele video sunt informaţii în formă de imagini în mişcare – filme etc. Pregătirea benzilor animate este un proces mai complicat, dar în unele cazuri poate fi necesar. O deosebire clară între video-clipuri şi animaţie nu este reliefată. Cu filme sunt reflectate imagini din lumea reală, iar cu animaţii şi vedeo-clipuri – imagini din lumea virtuală.</p>
<p>Există mai multe forme de proiectare a unui dialog. Din cele mai cunoscute tipuri de dialog sunt:</p>
<p><strong>- </strong>selectarea cu ajutorul mause-lui a opţiunii necesare din meniu;</p>
<p>- înscrierea opţiunii necesare, sau a abrevierii acesteia;</p>
<p>- activarea unei taste corespunzătoare funcţiei date.</p>
<p>Cea mai eficientă este selectarea cu ajutorul mouse-lui.</p>
<p>Secvenţele audio sunt informaţii în formă acustică: voce, muzică,sunet, etc. În cadrul creării unui curs multimedia instructiv sunetul reprezintă un mijloc eficient de influenţare. Cu ajutorul sunetului putem contribui la focalizarea atenţiei către un obiect de pe ecran. Secvenţele audio ocupă un volum mare, deaceea se vor utiliza doar în caz de strictă necesitate.</p>
<p>O valoare psihologică înaltă o are maniera sau tonul de expunere a informaţiei de studiu. Pentru ca expunerea informaţiei să fie mai accesibilă este necesar să fie ales un ton agreabil. O abordare aproblemei de-o manieră autoritară va avea o expunere severă şi neatractivă, deaceea poate duce la plictiseală şi la scăderea interesului faţă de studiu, pînă la abandonarea cursului. Folosirea binevoinţei, nuanţelor de umor contribuie la stabilirea unui <em>feedback</em> (conexiune inversă)sănătos între utilizator şi CMI</p>
<p><a rel="attachment wp-att-103" href="http://resurse-educationale.uv.ro/?attachment_id=103">Download Tipul de date string</a></p>
]]></content:encoded>
			<wfw:commentRss>http://resurse-educationale.uv.ro/?feed=rss2&#038;p=102</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
