Iterators/ro: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
No edit summary
Line 1: Line 1:
=Containere și iteratori=


==Generalități==
Qt are clase pentru a înlocui clasele C + + <span class="caps">STL</span>. Containerele Qt sunt clase șablon și pot conține orice alte clase mutabile. Aceste clase container au fost concepute pentru a fi mai compacte, mai sigure și mai ușor de folosit decât containerele <span class="caps">STL</span>. Ele sunt [http://doc.qt.nokia.com/4.7-snapshot/implicit-sharing.html partajate implicit] ''[doc.qt.nokia.com]'' și pot fi apelate din mai multe threaduri. Există o largă gamă de containere, incluzând aici liste, stive, cozi, vectori asociativi și liste hash. Aceste clase conțin iteratori compatibili cu <span class="caps">STL</span>, cât și iteratori inspirați din Java. Iteratorii sunt obiecte care sunt utilizate pentru a se deplasa în cadrul unui container și pentru a obține acces la datele păstrate în el. Qt mai oferă de asemenea și cuvântul cheie '''foreach''' care face foarte facilă iterarea prin elementele conținute de o clasă container. Qt oferă următoarele '''containere secvenţiale''':
# [http://doc.qt.nokia.com/4.7-snapshot/qlist.html QList] ''[doc.qt.nokia.com]''
# [http://doc.qt.nokia.com/4.7-snapshot/qlinkedlist.html QLinkedList] ''[doc.qt.nokia.com]''
# [http://doc.qt.nokia.com/4.7-snapshot/qvector.html QVector] ''[doc.qt.nokia.com]''
# [http://doc.qt.nokia.com/4.7-snapshot/qstack.html QStack] ''[doc.qt.nokia.com]''
# [http://doc.qt.nokia.com/4.7-snapshot/qqueue.html QQueue] ''[doc.qt.nokia.com]''
Pentru majoritatea aplicaţiilor '''QList''' este cel mai recomdat. Dacă aveți nevoide de o listă înlănțuită utlizați '''QLinkedList'''; dacă doriți ca elementele să ocupe locuri consecutive în memorie se utilizează '''QVector'''. '''QStack''' şi '''QQueue''' oferă containeri cu semantică ''<span class="caps">LIFO</span>'' și ''<span class="caps">FIFO</span>''.
Qt oferă de asemenea și '''containere asociative''':
# [http://doc.qt.nokia.com/4.7-snapshot/qmap.html QMap] ''[doc.qt.nokia.com]''
# [http://doc.qt.nokia.com/4.7-snapshot/qmultimap.html QMultiMap] ''[doc.qt.nokia.com]''
# [http://doc.qt.nokia.com/4.7-snapshot/qhash.html QHash] ''[doc.qt.nokia.com]''
# [http://doc.qt.nokia.com/4.7-snapshot/qmultimap.html QMultiHash] ''[doc.qt.nokia.com]''
# [http://doc.qt.nokia.com/4.7-snapshot/qset.html QSet] ''[doc.qt.nokia.com]''
Containerele ''multi'' furnizează suport pentru valori asociate mai multor chei. Containerele ''hash'' furnizează căutări mai rapide utilizând funcții ''hash'' în loc de căutări binare pe un set gata sortat. Containerele pot fi imbricate. De exemplu este perfect posibil să folosim un '''QMap&lt;QString,QList&lt;int&gt; &gt;''', unde cheia este '''QString''', iar valoarea este de tip '''QList&lt;int&gt;''' .
==Inserarea de elemente într-un QList==
Există mai multe metode de a adăuga elemente într-un QList. Putem folosi operatorul '''&lt;&lt;''', sau putem folosi una dintre metodele :
* '''void QList::prepend ( const QList&lt;T&gt; &amp; value )''' – pentru a adăuga valoarea value la începutul unei listei.
* '''void QList::append ( const QList&lt;T&gt; &amp; value )''' – pentru a adăuga valoarea value la sfârșitul unei listei.
* '''void QList::insert ( int i, const T &amp; value )''' – pentru a insera la poziția i valoarea value.
Un exemplu de aplicare al acestor metode îl aveți mai jos :<br />
<div class="cpp-qt geshi">
# <div class="de1">[http://doc.qt.io/QList.html <span class="kw5">QList</span>]<span class="sy0">&lt;</span>[http://doc.qt.io/QString.html <span class="kw5">QString</span>]<span class="sy0">&gt;</span> lista<span class="sy0">;</span></div>
# <div class="de1">lista <span class="sy0">&lt;&lt;</span> <span class="st0">"Romania"</span><span class="sy0">;</span></div>
# <div class="de1"><span class="kw2">qDebug</span><span class="br0">(</span><span class="br0">)</span> <span class="sy0">&lt;&lt;</span> lista<span class="sy0">;</span></div>
# <div class="de1">lista.<span class="me1">append</span><span class="br0">(</span><span class="st0">"Franta"</span><span class="br0">)</span><span class="sy0">;</span></div>
# <div class="de2"><span class="kw2">qDebug</span><span class="br0">(</span><span class="br0">)</span> <span class="sy0">&lt;&lt;</span> lista<span class="sy0">;</span></div>
# <div class="de1">lista.<span class="me1">prepend</span><span class="br0">(</span><span class="st0">"Italia"</span><span class="br0">)</span><span class="sy0">;</span></div>
# <div class="de1"><span class="kw2">qDebug</span><span class="br0">(</span><span class="br0">)</span> <span class="sy0">&lt;&lt;</span> lista<span class="sy0">;</span></div>
# <div class="de1">lista.<span class="me1">insert</span><span class="br0">(</span><span class="nu0">1</span><span class="sy0">,</span> <span class="st0">"Olanda"</span><span class="br0">)</span><span class="sy0">;</span></div>
# <div class="de1"><span class="kw2">qDebug</span><span class="br0">(</span><span class="br0">)</span> <span class="sy0">&lt;&lt;</span> lista<span class="sy0">;</span></div>
# <div class="de2">lista.<span class="me1">insert</span><span class="br0">(</span><span class="nu0">4</span><span class="sy0">,</span> <span class="st0">"Grecia"</span><span class="br0">)</span><span class="sy0">;</span></div>
# <div class="de1"><span class="kw2">qDebug</span><span class="br0">(</span><span class="br0">)</span> <span class="sy0">&lt;&lt;</span> lista<span class="sy0">;</span></div>
</div>
După fiecare operație efectuată asupra listei, afișăm conținutul listei și vom avea :<br />
<div class="cpp-qt geshi">
# <div class="de1"><span class="br0">(</span><span class="st0">"Romania"</span><span class="br0">)</span></div>
# <div class="de1"><span class="br0">(</span><span class="st0">"Romania"</span><span class="sy0">,</span> <span class="st0">"Franta"</span><span class="br0">)</span>  </div>
# <div class="de1"><span class="br0">(</span><span class="st0">"Italia"</span><span class="sy0">,</span> <span class="st0">"Romania"</span><span class="sy0">,</span> <span class="st0">"Franta"</span><span class="br0">)</span></div>
# <div class="de1"><span class="br0">(</span><span class="st0">"Italia"</span><span class="sy0">,</span> <span class="st0">"Olanda"</span><span class="sy0">,</span> <span class="st0">"Romania"</span><span class="sy0">,</span> <span class="st0">"Franta"</span><span class="br0">)</span></div>
# <div class="de2"><span class="br0">(</span><span class="st0">"Italia"</span><span class="sy0">,</span> <span class="st0">"Olanda"</span><span class="sy0">,</span> <span class="st0">"Romania"</span><span class="sy0">,</span> <span class="st0">"Franta"</span><span class="sy0">,</span> <span class="st0">"Grecia"</span><span class="br0">)</span></div>
</div>
==Folosirea iteratorilor într-un QList==
Pentru a accesa elementele din cadrul unei liste avem la dispoziție 3 variante. Putem folosi
* iteratorul inspirat din Java
* iteratorul inspirat din <span class="caps">STL</span> sau
* cuvântul cheie '''foreach'''.
Un exemplu de folosire al iteratorului inspirat din Java este mai jos :
<div class="cpp-qt geshi">
# <div class="de1">[http://doc.qt.io/QListIterator.html <span class="kw5">QListIterator</span>]<span class="sy0">&lt;</span>[http://doc.qt.io/QString.html <span class="kw5">QString</span>]<span class="sy0">&gt;</span> i<span class="br0">(</span>lista<span class="br0">)</span><span class="sy0">;</span></div>
# <div class="de1"><span class="kw1">while</span><span class="br0">(</span>i.<span class="me1">hasNext</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span> <span class="kw2">qDebug</span><span class="br0">(</span><span class="br0">)</span> <span class="sy0">&lt;&lt;</span> i.<span class="me1">next</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div>
</div>
În exemplul de mai sus se iterează de la începutul listei până la sfârșitul ei, dar la fel de bine această iterație se putea face de la sfârșitul listei până la începtul ei precum în exemplul următor :
<div class="cpp-qt geshi">
# <div class="de1">[http://doc.qt.io/QListIterator.html <span class="kw5">QListIterator</span>]<span class="sy0">&lt;</span>[http://doc.qt.io/QString.html <span class="kw5">QString</span>]<span class="sy0">&gt;</span> i<span class="br0">(</span>lista<span class="br0">)</span><span class="sy0">;</span></div>
# <div class="de1">i.<span class="me1">toBack</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div>
# <div class="de1"><span class="kw1">while</span><span class="br0">(</span>i.<span class="me1">hasPrevious</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="kw2">qDebug</span><span class="br0">(</span><span class="br0">)</span> <span class="sy0">&lt;&lt;</span> i.<span class="me1">previous</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div>
</div>
Aceleași operații de iterație se pot face cu iteratorii inspirați din <span class="caps">STL</span>. Putem fie itera de la începutul listei până la sfârșitul ei precum în exemplu următor :
<div class="cpp-qt geshi">
# <div class="de1">[http://doc.qt.io/QList.html <span class="kw5">QList</span>]<span class="sy0">&lt;</span>[http://doc.qt.io/QString.html <span class="kw5">QString</span>]<span class="sy0">&gt;::</span><span class="me2">iterator</span> i<span class="sy0">;</span></div>
# <div class="de1"><span class="kw1">for</span><span class="br0">(</span>i <span class="sy0">=</span> list.<span class="me1">begin</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span> i <span class="sy0">!=</span> list.<span class="me1">end</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span> <span class="sy0">++</span>i<span class="br0">)</span><span class="kw2">qDebug</span><span class="br0">(</span><span class="br0">)</span> <span class="sy0">&lt;&lt;</span> <span class="br0">(</span><span class="sy0">*</span>i<span class="br0">)</span><span class="sy0">;</span></div>
</div>
, fie de la sfârșitul listei până la începutul acesteia :
<div class="cpp-qt geshi">
# <div class="de1">[http://doc.qt.io/QList.html <span class="kw5">QList</span>]<span class="sy0">&lt;</span>[http://doc.qt.io/QString.html <span class="kw5">QString</span>]<span class="sy0">&gt;::</span><span class="me2">iterator</span> i <span class="sy0">=</span> list.<span class="me1">end</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div>
# <div class="de1"><span class="kw1">while</span><span class="br0">(</span>i <span class="sy0">!=</span> list.<span class="me1">begin</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span>  <span class="sy0">--</span>i<span class="sy0">;</span> <span class="kw2">qDebug</span><span class="br0">(</span><span class="br0">)</span> <span class="sy0">&lt;&lt;</span> <span class="br0">(</span><span class="sy0">*</span>i<span class="br0">)</span><span class="sy0">;</span> <span class="br0">}</span></div>
</div>
Dacă doriți să iterați peste toate elementele conținute de o listă puteți folosi cuvântul cheie propriu frameworkului Qt '''foreach'''. El reprezintă un adaos la limbajul C++ și este implementat folosind preprocesorul. Sintaxa sa este* foreach('''''variabilă'',''container''''')*. Un exemplu de folosire îl găsiți mai jos :
<div class="cpp-qt geshi">
# <div class="de1"><span class="kw2">foreach</span><span class="br0">(</span>[http://doc.qt.io/QString.html <span class="kw5">QString</span>] unElement<span class="sy0">,</span>list<span class="br0">)</span> <span class="br0">{</span> <span class="kw2">qDebug</span><span class="br0">(</span><span class="br0">)</span> <span class="sy0">&lt;&lt;</span> unElement<span class="sy0">;</span>  <span class="br0">}</span></div>
</div>
==Complexitatea algoritmică==
Din punctul de vedere al complexității algoritmice, ne preocupă rapiditatea în execuție a funcțiilor specifice diferitelor clase container. De exemplu inserarea unui element la mijlocul unui '''QLinkedList''' este o operație extrem de rapidă, indiferent de numărul de element conținute de această clasă. În schimb inserarea aceluiași element la mijlocul unui '''QVector''' este extrem de lent, mai ales în cazul în care '''QVector''' conține mai multe elemente, din moment ce jumătate dintre elemente trebuie mutate o poziție. Atunci când ne alegem un container este recomandat să ținem cont de complexitatea algoritmică a diferitelor operații. În următorul tabel se facel un bilanț al complexității algoritmice a claselor de tip container secvențial.
[[Image:tabel2_Complexitate_container_secvential.JPG|Tabelul 1. Bilant al complexitatii algoritmice a claselor de tip container secvential]]
'''Tabelul 1. Bilanț al complexității algoritmice a claselor de tip container secvențial'''
Dar sunt anumite situații în care trebuie să folosim clase de tip container asociativ. În acest caz consultăm un tabel al bilanțurilor complexității algoritmice al acestor clase.
[[Image:tabel1_Complexitate_container_asociativ.JPG|Tabelul 2. Bilant al complexitatii algoritmice a claselor de tip container secvential]]
'''Tabelul 2. Bilanț al complexității algoritmice a claselor de tip container asociativ'''

Revision as of 14:00, 25 February 2015

Containere și iteratori

Generalități

Qt are clase pentru a înlocui clasele C + + STL. Containerele Qt sunt clase șablon și pot conține orice alte clase mutabile. Aceste clase container au fost concepute pentru a fi mai compacte, mai sigure și mai ușor de folosit decât containerele STL. Ele sunt partajate implicit [doc.qt.nokia.com] și pot fi apelate din mai multe threaduri. Există o largă gamă de containere, incluzând aici liste, stive, cozi, vectori asociativi și liste hash. Aceste clase conțin iteratori compatibili cu STL, cât și iteratori inspirați din Java. Iteratorii sunt obiecte care sunt utilizate pentru a se deplasa în cadrul unui container și pentru a obține acces la datele păstrate în el. Qt mai oferă de asemenea și cuvântul cheie foreach care face foarte facilă iterarea prin elementele conținute de o clasă container. Qt oferă următoarele containere secvenţiale:

  1. QList [doc.qt.nokia.com]
  2. QLinkedList [doc.qt.nokia.com]
  3. QVector [doc.qt.nokia.com]
  4. QStack [doc.qt.nokia.com]
  5. QQueue [doc.qt.nokia.com]

Pentru majoritatea aplicaţiilor QList este cel mai recomdat. Dacă aveți nevoide de o listă înlănțuită utlizați QLinkedList; dacă doriți ca elementele să ocupe locuri consecutive în memorie se utilizează QVector. QStack şi QQueue oferă containeri cu semantică LIFO și FIFO.

Qt oferă de asemenea și containere asociative:

  1. QMap [doc.qt.nokia.com]
  2. QMultiMap [doc.qt.nokia.com]
  3. QHash [doc.qt.nokia.com]
  4. QMultiHash [doc.qt.nokia.com]
  5. QSet [doc.qt.nokia.com]

Containerele multi furnizează suport pentru valori asociate mai multor chei. Containerele hash furnizează căutări mai rapide utilizând funcții hash în loc de căutări binare pe un set gata sortat. Containerele pot fi imbricate. De exemplu este perfect posibil să folosim un QMap<QString,QList<int> >, unde cheia este QString, iar valoarea este de tip QList<int> .

Inserarea de elemente într-un QList

Există mai multe metode de a adăuga elemente într-un QList. Putem folosi operatorul <<, sau putem folosi una dintre metodele :

  • void QList::prepend ( const QList<T> & value ) – pentru a adăuga valoarea value la începutul unei listei.
  • void QList::append ( const QList<T> & value ) – pentru a adăuga valoarea value la sfârșitul unei listei.
  • void QList::insert ( int i, const T & value ) – pentru a insera la poziția i valoarea value.

Un exemplu de aplicare al acestor metode îl aveți mai jos :

  1. QList<QString> lista;
  2. lista << "Romania";
  3. qDebug() << lista;
  4. lista.append("Franta");
  5. qDebug() << lista;
  6. lista.prepend("Italia");
  7. qDebug() << lista;
  8. lista.insert(1, "Olanda");
  9. qDebug() << lista;
  10. lista.insert(4, "Grecia");
  11. qDebug() << lista;

După fiecare operație efectuată asupra listei, afișăm conținutul listei și vom avea :

  1. ("Romania")
  2. ("Romania", "Franta")  
  3. ("Italia", "Romania", "Franta")
  4. ("Italia", "Olanda", "Romania", "Franta")
  5. ("Italia", "Olanda", "Romania", "Franta", "Grecia")

Folosirea iteratorilor într-un QList

Pentru a accesa elementele din cadrul unei liste avem la dispoziție 3 variante. Putem folosi

  • iteratorul inspirat din Java
  • iteratorul inspirat din STL sau
  • cuvântul cheie foreach.

Un exemplu de folosire al iteratorului inspirat din Java este mai jos :

  1. while(i.hasNext()) qDebug() << i.next();

În exemplul de mai sus se iterează de la începutul listei până la sfârșitul ei, dar la fel de bine această iterație se putea face de la sfârșitul listei până la începtul ei precum în exemplul următor :

  1. i.toBack();
  2. while(i.hasPrevious())qDebug() << i.previous();

Aceleași operații de iterație se pot face cu iteratorii inspirați din STL. Putem fie itera de la începutul listei până la sfârșitul ei precum în exemplu următor :

  1. QList<QString>::iterator i;
  2. for(i = list.begin(); i != list.end(); ++i)qDebug() << (*i);

, fie de la sfârșitul listei până la începutul acesteia :

  1. QList<QString>::iterator i = list.end();
  2. while(i != list.begin()) {  --i; qDebug() << (*i); }

Dacă doriți să iterați peste toate elementele conținute de o listă puteți folosi cuvântul cheie propriu frameworkului Qt foreach. El reprezintă un adaos la limbajul C++ și este implementat folosind preprocesorul. Sintaxa sa este* foreach(variabilă,container)*. Un exemplu de folosire îl găsiți mai jos :

  1. foreach(QString unElement,list) { qDebug() << unElement;  }

Complexitatea algoritmică

Din punctul de vedere al complexității algoritmice, ne preocupă rapiditatea în execuție a funcțiilor specifice diferitelor clase container. De exemplu inserarea unui element la mijlocul unui QLinkedList este o operație extrem de rapidă, indiferent de numărul de element conținute de această clasă. În schimb inserarea aceluiași element la mijlocul unui QVector este extrem de lent, mai ales în cazul în care QVector conține mai multe elemente, din moment ce jumătate dintre elemente trebuie mutate o poziție. Atunci când ne alegem un container este recomandat să ținem cont de complexitatea algoritmică a diferitelor operații. În următorul tabel se facel un bilanț al complexității algoritmice a claselor de tip container secvențial.

Tabelul 1. Bilant al complexitatii algoritmice a claselor de tip container secvential

Tabelul 1. Bilanț al complexității algoritmice a claselor de tip container secvențial

Dar sunt anumite situații în care trebuie să folosim clase de tip container asociativ. În acest caz consultăm un tabel al bilanțurilor complexității algoritmice al acestor clase.

Tabelul 2. Bilant al complexitatii algoritmice a claselor de tip container secvential

Tabelul 2. Bilanț al complexității algoritmice a claselor de tip container asociativ