User Tools

Site Tools


in204:tds:sujets:td4:part1

This is an old revision of the document!


Partie I – Manipulations d’itérateurs

TD4

Question n°1

Nous nous intéressons typiquement à la fonction suivante définie sur un tableau dynamique :

#include <vector>       // std::vector
 
template <class T>
int upper(std::vector<T> aVector, const T& theValue)
{
	for (int i = 0; i < aVector.size(); i++)
	{
		if (aVector[i] > theValue)
			return i;
	}
	return -1;
}

Cette fonction retourne l’indice du premier élément du tableau qui est plus grand que theValue.

Question n°1.1

Modifier cette fonction pour qu’elle fonctionne désormais avec des itérateurs et non plus un tableau.

Correction

Correction

  • l'itérateur theEndIterator faisant référence à l'itérateur marquant la fin de la séquence (ie. l'itérateur correspondant à l'itérateur obtenue en appliquant l'opérateur ++ sur l'itérateur faisant référence au dernier élément de la séquence),
  • une valeur aValue de référence qui défénit la valeur pivot.
  • La fonction accède aux éléments stockés dans le containeur de manière linéaire, en commençant par le premier élément et en continuant avec le deuxième, puis le troisième et ainsi de suite jusqu'à atteindre le dernier élément de la séquence.

    De ce fait, l'itérateur est supposé respecter que le contrat dénomé LegacyInputIterator. En fait, c'est le contrat définissant les exigences minimales et en conséquence si nous définissons un algorithme qui se contente de ces contraintes minimale, il est possible de l'utiliser avec l'ensemble des containeurs qui sont définis conformément aux exigences de la STL de C++.

    Dans ce cas, nous avons deux paramètres de type pour la fonction:

    1. le paramètre de type inputIterator correspondant au type des itérateurs theBeginIterator et theEndIterator,
    2. le paramètre de type T correspondant au type des valeurs pivots.

    La fonction upper retournait la position de la première valeur qui est plus grande que la valeur aValue ou -1 si toutes les valeurs sont plus petites. La généralisation à des itérateurs doit fournir les mêmes résultats. Pour la valeur la première valeur plus grande, il peut être retourné l'itérateur faisant référence à la première valeur la plus grande. Si aucune valeur n'est plus grande que la valeur aValue, il faut effectivement retourner un itérateur qui soit invalide. En fait, le seul itérateur qui ne désigne pas une valeur dans la séquence [theBeginIterator, theEndIterator( est l'itérateur theEndIterator qui désigne l'itéarateur marquant la fin de la séquence, donc faisant référence à quelque chose qui n'est plus dans la séquence.

    Par similitude, la fonction upper retournera donc :

    • l'itérateur faisant référence à la première valeur qui est plus grande que la valeur aValue,
    • l'itérateur theEndIterator si aucune valeur dans la séquence n'est plus grande que la valeur aValue.

    Ceci permet déslors de réécrire l'entête de la fonction comme suit :

    template<class inputIterator, class T>
    inputIterator upper(inputIterator theBeginIterator, inputIterator theEndIterator, const T& aValue)

    Dans le code, les éléments sont accèder de manière successive tant que l'itérateur theBeginIterator est différent de l'itérateur marquant la fin de la séquence. Ceci amène la reformulation du code de la fonction comme suit :

    template<class inputIterator, class T>
    inputIterator upper(inputIterator theBeginIterator, inputIterator theEndIterator, const T& aValue)
    {
        for(;theBeginIterator != theEndIterator; theBeginIterator ++)
        {
            if(*theBeginIterator > theValue)
                return theBeginIterator;
        }
        return theEndIterator;
    }

    Question n°1.2

    Tester cette fonction avec le code suivant :

    int testUpper() 
    {
    	int myints[] = { 10,20,30,30,20,10,10,20 };
    	std::vector<int> v(myints, myints + 8);
    	std::vector<int>::iterator up = upper(v.begin(), v.end(), 20); 
    	std::cout << "first value greater than 20  at position " 
                << (up - v.begin()) << '\n';
    	return 0;
    }

    Explication & correction

    Explication & correction

  •     template<class inputIterator>
        typename std::iterator_traits<inputIterator>::difference_type
            distance(inputIterator first, inputIterator last, std::random_access_iterator_tag)

    Cette fonction est la version spécialisée pour le type iteratorTag qui doit être égal à std::random_access_iterator_tag.

  • Comme la version spécialisée est prioritaire sur la version générique, si l'itérateur définit iterator_category comme étant std::random_access_iterator_tag, c'est la version spécialisée de la fonction qui sera appelé, sinon la version générique, ce qui permet d'avoir recours à la méthode optimale pour calculer la distance.

    Question n°2

    Dans la STL, de nombreux algorithmes sont fournis dont notamment des algorithmes de tri. Ces algorithmes sont présents dans le fichier d’entête :

    #include <algorithm>

    Nous trouvons par exemple l’algorithme de tri :

    template <class randomAccessIterator>
    void sort(randomAccessIterator first, randomAccessIterator last);

    ainsi que :

    template <class randomAccessIterator>
    void sort_heap(randomAccessIterator first, randomAccessIterator last);

    qui fournisse un tri rapide et tri sur le tas.

    Question n°2.1

    Nous souhaitons déterminer la position du premier élément dans notre tableau qui est plus grand que 20 avec d’ordonner le tableau. Ceci correspond au code de la fonction définie à la question 1.2, et nous souhaitons ensuite déterminer la position du premier élément qui est plus grand que 20 après avoir ordonner le tableau.

    Modifier le code de la fonction définie à la question 1.2 pour ajouter cette nouvelle opération en appelant soit la fonction sort soit la fonction sort_heap pour effectuer le tri de votre tableau.

    Correction

    Correction

    in204/tds/sujets/td4/part1.1602052588.txt.gz · Last modified: 2020/10/07 06:36 by bmonsuez

    Page Tools