Télécharger la présentation
La présentation est en train de télécharger. S'il vous plaît, attendez
Publié parLotte Pujol Modifié depuis plus de 10 années
1
Cours ENSG 2A, Septembre 2002 Guillaume Caumon
Algorithmique Cours ENSG 2A, Septembre 2002 Guillaume Caumon
2
Introduction Un cours d’algorithmique a Géol… !???
Algorithme = suite d’actions que devra effectuer un automate pour arriver à partir d’un état initial, en un temps fini, à un résultat Ce cours est un approfondissement du cours d’info de C de 1ere année. Pourquoi faire de l’info a Geol ??? Modélisation de plus en plus employée dans l’industrie et la recherche. Elements finis (modélisation d’écoulements, déformations et rupture) Géostatistique et Analyse des données Modélisation géométrique Systèmes experts et recherche opérationnelle 20 % de la promo99 dans l’info… Cette année: TDs et projets 2A de programmation (Cf Christine Fay-Varnier) Eventuellement projet de labo
3
Plan Mémoire, pointeurs (1h) Organisation d’un programme (1h)
Structures de données: listes, arbres, tables... (8h) Algorithmique: exemple des tris (2h)
4
Partie I La mémoire
5
Les mémoires... RAM (Random Access Memory): 32 / 64 Mo
Le disque dur: quelques Go La mémoire virtuelle: temps d’accès 1000 fois plus long. La mémoire vive est donc limitée: un programme va donc avoir a gérer au mieux la mémoire disponible en fonction des besoins => allocations dynamiques, et usage de pointeurs.
6
Mémoire et exécution Code objet du programme Valeurs constantes
Données statiques Valeurs constantes Pile Piles d’appels de fonctions Pile: Pour chaque fonction empilée, sont stockés : les arguments la valeur de retour l’adresse de retour les variables locales Tas Allocation dynamique de mémoire
7
Intérêts des pointeurs
Gestion de l’espace mémoire en cours d’exécution Modifications de variables passées en paramètres de fonction Représentation de tableaux: accès direct et indexé Fonctions virtuelles: elles font intervenir des pointeurs de fonction, qui seront abordes dans les parcours d’arbres. Références croisées Fonctions virtuelles en programmation objet
8
Rappels sur les pointeurs
int* a; a Déclaration d’un pointeur vers un entier
9
Rappels sur les pointeurs
int* a; int* a = NULL; a Déclaration d’un pointeur vers un entier et initialisation à “NULL”
10
Rappels sur les pointeurs
malloc(3*sizeof(int)); Allocation dynamique de place mémoire (pour 3 entiers)
11
Rappels sur les pointeurs
int* a = malloc(3*sizeof(int)); int* a = (int*)malloc(3*sizeof(int)); a *a *a a[0] *(a+1) a[1] etc. int* a1 = &a[1] Allocation dynamique et assignement
12
Rappels sur les pointeurs
free(a); a = NULL; a *a Bilan: Un pointeur est une variable contenant l’adresse d’une zone de mémoire. Il permet de gérer la mémoire “a distance” en allouant/desallouant dynamiquement. Le type d’un pointeur est un raccourci pour parler du type d’élément pointé. En d’autres termes, un pointeur occupe une taille fixe (32 ou 64 bits, en général, la taille d’une adresse), alors que le type détermine la taille de l’élément pointé. Cela permet par exemple d’utiliser des pointeurs non typés (void*), pour référencer des zones de mémoire. Dans ce cas, c’est seulement au moment de l’accès a ces zones mémoire qu’on aura besoin de connaître le type d’élément stocké. Désallocation dynamique
13
Rappels sur les pointeurs
int* a = (int*)malloc(3*sizeof(int)); int* a = (int*)calloc(3, sizeof(int)); Pb de malloc pour les tableaux: pas d’initialisation. -> calloc Coût mémoire de realloc: Alloue un nouveau bloc de mémoire Copie les valeurs de l’ancien bloc dans le nouveau Libère l’ancien bloc Retourne l’adresse du nouveau bloc a = (int*)realloc(4*sizeof(int));
14
Partie II Survol d’architecture logicielle
15
Programme ?? Exécutable(s) Librairies et fichiers objets
bin Exécutable(s) a.out .exe lib .o .so .lib .dll Librairies et fichiers objets Programme include Fichiers de description (header) .h Description du point de vue du programmeur: Repertoire contenant un ensemble de fichiers src Fichiers d’implantation (source code) .c
16
But du Jeu Fichiers source = Instructions dans un langage de programmation Application, qui parle directement a l’ordinateur Hiérarchie des langages de programmation
17
Problèmes a résoudre Complexité, Coût de maintenance taille temps
La taille augmente… Corrections de bugs, pardon, de bogues. Changements de spécifications + maintien de la compatibilité avec les anciennes versions Nouvelles fonctionnalités temps
18
Organisation et réutilisation…
Organisation du code : En fonctions, structures, etc. En fichiers Réutilisation : Du code (fichiers source) Des fichiers binaires Réutilisation d’un programme à l’autre
19
Programmes et librairies
En C : Exécutable ↔ main() Pour la réutilisation, on utilise des bibliothèques (ou librairies) de fonctions : d’une description de chaque fonction (dans des fichier “.h” d’en-tête, ou header), et du code compilé correspondant (des “.lib” et “.dll” sous PC, des “.so” et “.a” sous UNIX) Analogie: Bibliothèque = voiture Interface (fichiers d’en-tête) {pédales d’accélérateur, de frein, d’embrayage, volant, levier de vitesse, etc.} Documentation code de la route et manuel d’utilisation code objet (librairies binaires (.dll, .so)) moteur, plaquettes et disques de freins, cardans, etc. Exemple de programmes utilisant la bibliothèque: Aller de Nancy à Paris Aller faire des courses Etc.
20
La Compilation : Résumé
Fichiers d’en-tête C Code source C .c .h Préprocesseur Code pré-processé Librairies Compilateur 1) Preprocessing : - Expansion des headers inclus Afin d’éviter les inclusions multiples, une fichier header doit commencer par: #ifndef myfile_h #define myfile_h /* Corps du fichier: déclaration de fonctions, structures, etc */ #endif C’est un bon exemple pour dérouler l’action du preprocesseur. Le preprocesseur effectue aussi des substitutions dans le code #define HUGE 2) Compilation: Chargée de générer le code machine; définition des symboles déclarés dans les fichiers d’en-tête. Le compilateur n’est pas votre ennemi, au contraire !!! 3) Edition de lien: mise en commun et recherche du code correspondant a tous le symboles Parler des types d’erreurs aux différentes étapes .lib .so Fichier(s) Objet Editeur de liens exécutable .o a.out .exe
21
Qualité d’un programme
Architecture claire Réutilisabilité Structures de données + Algorithmes + Documentation + Tests de robustesse +
22
Introduction aux structures de données
Partie III Introduction aux structures de données
23
“Comment Organiser au Mieux l’Information
Introduction Problème métaphysique: “Comment Organiser au Mieux l’Information dans un Programme ?” Tableaux int tab[10]; Structures de données struct Data_t { int index_; char* value_; } Data_t; Structures Problèmes récurrents: représenter de l’information avec les outils disponibles: variables, pointeurs, fonctions...
24
Les tableaux Accès indexé (de 0 à n-1 pour un tableau de n éléments)
Stockage compact Taille fixe, en général Réajustement de taille coûteux en temps Insertion d’élément onéreuse en temps.
25
Liste chaînée : Spécifications
Créer une liste vide Ajouter un élément (début / fin / milieu) Retirer un élément (début / fin / milieu) Détruire une liste Notre but est d’écrire une librairie de programmation qui pourra être utilise par du code client (n’importe quel programme qui a besoin d’utiliser des listes chaînées). Etapes: Spécifications : que veut-on faire ? Que veut-on fournir au code client ? Définition d’une structure de données adaptée aux spécifications Ecriture des fichiers d’en-tête correspondant A la structure de données choisie Aux spécifications choisies. Ecriture des fichiers d’implantation Compilation et tests Note sur les spécifications : on peut bien entendu effectuer ces opérations sur des tableaux, mais: C’est lourd a implémenter Cela risque de nécessiter beaucoup d’allocations/réallocations, ce qui peut prendre très longtemps pour des listes contenants de très gros objets. On va donc définir une nouvelle structure de données plus rapide pour répondre a ces spécifications. Remarque avancée: en pratique les tableaux sont couramment utilises pour l’implémentation de listes; en général, on utilise des heuristiques pour optimiser la taille des tableaux pour éviter un surdimensionnement aussi bien que de trop nombreuses réallocations. Un autre type de méthode très efficace consiste à utiliser une liste de tableaux pour profiter de la rapidité des tableaux et de la flexibilité des listes. L’implantation de telles structures nous mènerait trop loin, c’est pourquoi nous allons décrire une structure illustrant bien les concepts, quoique non optimale. Trier les éléments d’une liste
26
Liste chaînée : Structures
Noeud Tête Tête Noeud Exemple de structures satisfaisant aux critères. Liste chaînée (en haut) et liste doublement chaînée (en bas)
27
Liste chaînée : Structures
Node_t p_last p_data p_next nb_elements p_first List_t Data_t Un premier pas vers une formulation informatique
28
Liste chaînée : Header typedef struct List_t {
struct Node_t* p_first_; struct Node_t* p_last_; int nb_elements_; } List_t; typedef struct Node_t { struct Data_t* p_data_; struct Node_t* p_next_; } Node_t; « struct » est nécessaire, car le « typdef » n’est pas encore interprété entre les {} illustration de l’intérêt des pointeurs: sans pointeur, on aurait besoin de connaître la taille de l’élément; un pointeur a une taille fixe (taille d’une adresse), c’est la taille de la zone pointée qui est variable. typedef struct Data_t { ... } Data_t;
29
Liste chaînée : Header List_t* list_create( void );
int list_insert_item( List_t* list, Data_t* item ); int list_append_item( int list_insert_item_before( List_t* list, Data_t* to_insert, Data* list_item
30
Liste chaînée : Header int list_destroy( List_t* list );
int list_empty( List_t* list ); Data_t* list_remove_head( List_t* list ); Data_t* list_remove_tail( List_t* list ); int list_remove_item( List_t* list Data_t* item ); int list_sort( List_t* list );
31
Liste chaînée : Utilisation
Avant d’aller plus loin, vérifions si nos spécifications sont suffisantes... Pour cela, nous allons écrire un programme qui utilise les fonctions du fichier list.h, sans nous préoccuper de la façon dont elles sont implantées. But du programme: construire et trier une liste d’entiers par ordre croissant. Exemple de fichier main.c: Noter: le passage de paramètre par adresse avec la fonction scanf. les schémas de boucle while(...){...} do{...} while(...) L’allocation dynamique de chaque Data_t est nécessaire (sinon, les valeurs entrées sont perdues) Que se passe-t-il a la fin de la fonction ? Il n’y a aucune desallocation de mémoire !!! #include <list.h> #define TRUE 1 #define FALSE 0 typedef int Bool_t; typedef int Data_t; int main() { int value = 0; Data_t* p_data = NULL; List_t* p_list = list_create(); if( p_list == NULL ) { /* Message d’erreur */ return 1; } printf( “Entrez les valeurs positives; entrez –999 pour terminer\n” ); scanf( “%d”, &value ); while( value != -999 ) { p_data = MALLOC( Data_t ); *p_data = value; if( p_data == NULL ) { /* Erreur */ if( ! list_insert_item( p_list, p_data ) ) { return list_sort( p_list );
32
Liste chaînée : Implantation
Cf. code écrit au tableau; pour résumer les principales règles à suivre: Toujours tester la validité d’un pointeur avant de l’utiliser. S’assurer de ne jamais perdre l’adresse d’une zone allouée dynamiquement. Dans un programme, toute allocation par malloc ou calloc doit être suivie d’une désallocation par free Fichier list.c: #include “list.h” #include “defs.h” /** Dans defs.h : defs de Bool_t, #define MALLOC(T) (T*)malloc( sizeof(T) ), etc. */ void list_error( char* message ) { printf( “List Error: %s\n”, message ); } List_t* list_create( void ) { List_t* p_new_list = MALLOC( List_t ); if( p_new_list == NULL ) { list_error( “Could not allocate new list” ); return NULL; p_new_list->p_first_ = NULL; p_new_list->p_last_ = NULL; p_new_list->nb_elements_ = 0; retrurn p_new_list; int list_insert_item( List_t* p_list, Data_t* p_data ) { if( p_list == NULL || p_data == NULL ) { list_error( “NULL Parameter !” ); return FALSE; p_node = MALLOC( Node_t ); if( p_node == NULL ) { ... } p_node ->p_data_ = p_data; p_node->p_next_ = p_list->p_first_; p_list->p_first_ = p_node; p_list->nb_elements_++; return TRUE; etc.
33
Liste chaînée : Spécialisations
Pile, ou Tas (Stack): structure LIFO void push(Data_t*) Data_t* pop(void) Stockage temporaire d’information, tout en conservant une notion d’ordre. Usages: Parcours de graphes version itérative de la récursion: la pile système est limitée. Evaluation d’expressions parenthésées; exemple simplifié 5 * (3 + 4) push(5) * ( push(3) + push(4) ) => on peut evaluer le contenu des () push( pop() + pop() ) On peut evaluer le * Push( pop() * pop() ) => la pile contient le resultat. printf( “%d”, pop() );
34
Liste chaînée : Spécialisations
File, ou queue : structure FIFO void push(Data_t*) Data_t* pop(void) Principe des files d’attente. Variante: priority queue: tri des éléments au fur et a mesure de l’insertion. Exemple d’application: allocation de ressources en programmation système (multi tache)
35
Introduction à la complexité
Annuaire avec noms et coordonnées t = a · N2 temps t t = a · 2N t = a · N t = a · logN abonnes: algorithme en o(n) ~ secondes ~ 3 heures recherche d’un nom o( n2) ~ 10^8 secondes ~ 3000 heures : tri par ordre alphabétique bourrin o( 2n ) plusieurs siècles o( Log N ) ~ 4 secondes o( N log N ) ~ 12 heures tri par ordre alphabétique “quick sort” On aimerait bien écrire annuaire[“Guillaume”] = .... Au lieu de annuaire[4762] = ... => tables Lien avec les listes: insertion d’un élément: o(1) retrait en queue: o(N), lie à l’implantation: avec une liste doublement chaînée, on aurait o(1). => compromis entre place mémoire utilisée et performance. comparaison avec les tableaux. nombre d’abonnés N
36
Sets ou Bags et tables Stocker une seule fois le même élément
dans le conteneur. Pas d’ordre Accès rapide Tables : Associent une clé a un élément dans le conteneur. Fonction de hachage: f: espace des données -- [0, nb_elements-1] Réalisation : on utilise des opérateurs qui garantissent l’unicité du mapping clef / index. Besoin de fonctions de hachage
37
Structures de données linéaires
Taille fixe Accès direct Tableaux Taille variable Accès séquentiel Listes chaînées Unicité des éléments Accès rapide Sets, Bags Associe une clé unique et une valeur. Accès rapide Tables
38
Structures de données hiérarchiques: les Arbres
Racine B1 B2 B3 B7 B6 B5 B4 F2 F1 Defs: Racine : noeud sans parent Branche : noeud avec parent et enfants Feuilles : noeud sans enfants Types: binaires, ternaires, non structurés Applications: - arbre généalogiques - intelligence artificielle, - compression de données - Systèmes de fichiers, - Structures de données géométriques (octrees, etc.) et jeux Principalement utilise dans tous les algorithmes “diviser pour régner”: Recherche dans un arbre équilibré : O( log n ) B8 B10 B9 F4 F5 F3 F7 F8 F6 F10 F9
39
Arbres: Spécifications
Créer un arbre Parcours pre-order Parcours post-order Parcours in-order Ajout / retrait d’un noeud Détruire un arbre
40
Arbres: Structure de données
TreeNode_t p_parent p_first_child p_data p_next Structure proposée très générale: nombre variable d’enfants. Optimisations possibles pour des arbres binaires ou ternaires, par ex: pas besoin de p_next: Exemple, pour un arbre binaire: typedef struct TreeNode_t { struct TreeNode_t* p_parent_; struct TreeNode_t*p_children_[2]; // tableau de 2 pointeurs vers des TreeNode_t Data_t* p_data_; } TreeNode_t; Data_t
41
Tree.h typedef struct TreeNode_t { struct TreeNode_t* p_parent_;
struct TreeNode_t* p_first_child_; Data_t* p_data_; struct TreeNode_t* p_next_; } TreeNode_t; TreeNode_t* tree_add_node( TreeNode_t* p_parent, Data_t* p_data ); Fichier tree.c #include “tree.h” TreeNode_t* tree_add_node( TreeNode* p_parent, Data_t* p_data ) { TreeNode_t* p_new_node = NULL; TreeNode_t* p_prev = NULL; if( p_data == NULL ) { return NULL; } p_new_node = MALLOC( TreeNode_t ); if( p_new_node == NULL ) { return NULL; } p_new_node->p_parent_ = parent; p_new_node->p_first_child_ = NULL; p_new_node->p_data_ = p_data; if( parent != NULL ) { #ifdef INSERT_ITEM /* First strategy: insert the node in the list of children */ p_new_node->p_next_ = p_parent ->p_first_child_; p_parent -> p_first_child_ = p_node; } #endif #ifdef APPEND_ITEM /* Second strategy: append the node to the list of children */ p_new_node->p_next = NULL; p_prev = p_parent->p_first_child_; if( p_prev == NULL ) { p_parent->p_first_child_ = p_new_node; } else { while( p_prev->p_next_ != NULL ) { p_prev = p_prev->p_next_; p_prev->p_next_ = p_new_node; return p_new_node;
42
Tree.h TreeNode_t* tree_find_root( TreeNode_t* p_parent,
Data_t* p_data ); void tree_preorder( TreeNode_t* p_root, void(* do_it)( Data_t* ) ); TreeNode_t* tree_find_root( TreeNode_t* p_node ) { TreeNode_t* p_parent = p_node; if( p_parent == NULL ) { return NULL; } while( p_parent->p_parent_ != NULL ) { p_parent = p_parent->p_parent_; } void tree_postorder( TreeNode_t* p_root, void(* do_it)( Data_t* ) );
43
Tree.h void tree_inorder( TreeNode_t* p_root, void(* do_it)( Data_t* )
); TreeNode_t* tree_delete_branch( TreeNode_t* branch );
44
Arbres: parcours pre-order
1 2 5 3 4 6 10 Principe: depuis la racine, descendre la hiérarchie quand on arrive sur une feuille, on remonte jusqu’ à une branche non visitée auparavant. void tree_preorder( TreeNode_t* p_root, void(* do_it)( Data_t* ) ) { TreeNode_t* p_node = NULL; if( p_root == NULL ) { /* ... */ } (* do_it)( p_root->p_data_ ); p_node = root->p_first_child_; while( p_node != NULL ) { Tree_preorder( p_node, do_it ); p_node = p_node ->p_next_; } return; 7 8 9 Pointeurs de fonctions...
45
Arbres: parcours post-order
10 3 9 1 2 7 8 Principe: On opère d’abord sur les feuilles puis sur les branches. void tree_postorder( TreeNode_t* p_root, void (* do_it)( Data_t* ) ) { TreeNode_t* p_node = NULL; if( p_root == NULL ) { return; } p_node = p_root->p_first_child_; while( p_node != NULL ) { tree_postorder( p_node, do_it ); p_node = p_node->p_next_; } (*do_it)( p_root->p_data_ ); return; 4 5 6
46
Arbres: parcours in-order
4 2 9 1 3 6 10 Parcours de gauche à droite: Sur la position courante: l’enfant le plus à gauche a la priorité puis la position courante puis les autres enfants void tree_inorder( TreeNode_t* p_root, void (* do_it)( Data_t* ) ) { TreeNode_t* p_node = NULL; if( p_root == NULL ) { return; } /* p_root is a leaf */ if( p_root_->p_first_child_ == NULL ) { (*do_it)( p_root->p_data_ ); return; } tree_inorder( p_root->p_first_child_, do_it ); (*do_it) ( p_root->p_data_ ); p_node = root -> p_first_child_->p_next_; while( p_node != NULL ) { tree_inorder( p_node, do_it ); p_node = p_node->p_next_; 5 7 8
47
Structures de données complexes: Les Graphes
Types et définitions : ouvert, fermé, connexe, non connexe, Cyclique/acyclique orienté / non orienté valués / non valués Applications : Réseaux routiers/ferroviaires, aérien, Ordonnancement de taches en Recherche opérationnelle problèmes de flux (hydraulique, files d’attente, etc.) Opérations: chemin le plus court fermeture transitive tri topologique flux maximum ... N15 N16 N17 N18
48
Algorithmes et complexité :
Partie IV Algorithmes et complexité : exemple des tris
49
Exemple : Algorithmes de tri
Applications: bases de données géométrie algorithmique .... Tri d’un tableau de taille n : n! possibilités Fonctions: de comparaison “<“ d’echange Etude de diverses méthodes de tri: But: quantifier la quantité d’appels aux 2 fonctions de base, et en déduire la complexité de l’algorithme.
50
Tri par remplacement Besoins Algo
min_index, max_value, comp tableaux entree, sortie int max = max_value(entree) Pour i de 1 à n Faire: int j <- min_index(entree) sortie[i] <- entree[j] entree[j] <- max FinPour Algo /* Returns the highest value in the array ‘data’ */ int get_max_value( int* data, int nb_elements ) { int i = 0; int max_value = data[0]; for( i = 1; i < nb_elements; i++ ) { if( data[i] > max_value ) { max_value = data[i]; } return max_value; /* Returns the index of the lowest value in the array ‘data’ */ int get_min_id(int* data, int nb_elements ) { int min_i = 0; int min_value = data[0]; if( data[i] < min_value ) { min_value = data[i]; min_i = i; return min_i; int* sort( int* data, int nb_elements ) { int j = 0; int* sorted_data = CALLOC( int, nb_elements ); int max_value = get_max_value( data, nb_elements ); for( i = 0; i < nb_elements – 1; i++ ) { j = get_min_id( data ) sorted_data[i] = data[j]; data[j] = max_value; sorted_data[nb_elements-1] = max_value; return sorted_data; Complexité en temps : o(n(n-1)) ~ o(n2) Mémoire: duplication du tableau.
51
Tri par permutation Besoins Algo
min_index, swap, comp Tableau entrée Pour i de 1 à n Faire: int j <- min_index(entree,i) Si j ≠ i Faire swap(entree[i],entree[j]) FinSi FinPour Algo - min_index cherche uniquement dans la partie non triée du tableau - on va trier le tableau directement: coût mémoire plus faible Optimisation du tri précèdent: /** * Returns the index of the lowest value in the array ‘data’, between * items ‘top’ to ‘nb_element – 1’ */ int get_min_id(int* data, int top, int nb_elements ) { int i = 0; int min_i = 0; int min_value = data[top]; for( i = top; i < nb_elements; i++ ) { if( data[i] < min_value ) { min_value = data[i]; min_i = i; } return min_i; void sort( int* data, int dimension ) { j = get_min_id( data, i ); // search only from i to n for( i=0; i<dimension; i++ ) { int j = 0; if( j != i ) { swap( v[i], v[j] ) } Complexité en temps : o(n(n-1)/2) ~ o(n2) Mémoire: tableau non dupliqué
52
Tri à bulles: Principe Echange de deux éléments adjacents du tableau.
Besoins swap, comp Fonction de comparaison: peut être paramétrable; exemple: tri d’un annuaire: par entreprise par nom par numéro de téléphone par adresse
53
Tri à bulles: Algo Tableau tab Booleen permute <- vrai
int i <- 0 Tant que permute Faire permute = faux Pour j de n-1 à i + 1 Faire Si tab[j-1] > tab[j] Faire swap( tab[j-1], tab[j] ) permute = vrai FinSi FinPour i++ Finttque void sort( int* data, int nb_elements ) { Bool_t permutated = TRUE; int j = 0; int i = 0; for( j = nb_elements; j > i; j-- ) { permutated = FALSE; while( permutated ) { permutated = true; swap( v[j-1], v[j] ); if( data[j-1] > data[j] ) { } i += 1;
54
Tri à bulles: Commentaires
Complexité en temps : o(n(n-1)/2) ~ o(n2) Mémoire: tableau non dupliqué
55
Tri par sélection 4que On sépare le tableau en p ensembles.
On cherche un minimum pour chaque sous-ensemble On prend le minimum de ces minima. On échange cet élément avec le premier élément etc. trié sous-table 1 sous-table p ... n ( p + n/p ) tests o( n n ) pour p = n
56
Tri par segmentation (quicksort)
Méthode “diviser pour régner” : On recherche une valeur pivot Tj. On échange les valeurs de sorte que : tout élément de [T0,Tj-1] soit inférieur a Tj, tout élément de [Tj+1, Tn] soit supérieur a Tj On pivote récursivement sur [T0,Tj-1] et [Tj+1, Tn].
57
Tri par segmentation (quicksort)
seg (0,11) seg (0,4); seg (4,11) seg (0,2); seg(3,4); seg(5,11) seg (0,11) seg (0,4); seg (5,11) seg(5,10) seg(6,10) seg(7,10) 3 1 1 2 2 3 9 // splits the array in two parts around an arbitrary value (pivot) // the value is the min index value // Best results if the pivot is the median value of the array. int segmentation( int* data, int inf, int sup ) { int pivot = data[inf]; int i = inf+1; int j = sup; while( i <= j ) { if( data[i] <= pivot ) { i++; } else { while( data[j] > pivot ) { j--; } if( i < j ) { swap( data[i], data[j] ); swap( data[inf], data[j] ); return j; void quick_sort( int* data, int inf, int sup ) { if( inf < sup ) { int place = segmentation( v, inf, sup ); quick_sort( v, inf, place-1 ); quick_sort( v, place, sup ); 4 7 6 8 6 7 8 5
58
Tri par segmentation (quicksort)
Complexité dans le cas favorable : log2(n) nombre de segmentations 0 permutations o(n log2 n) comparaisons Complexité dans le cas défavorable : n nombre de segmentations o(n2) permutations o(n2) comparaisons
59
Conclusion Fonctionnement d’un programme et d’un ordinateur
Programmation en C Algorithmique et structures de données sont liées. Les exemples étudiés ont été implantés en C, mais le langage est plus un outil qu’une fin en soi. Les algorithmes ne sont qu’une partie des concepts impliques dans un programme, par ex: la structure, l’interface, le design avec des langages plus évolués, la documentation, etc. Bon courage pour vos projets !
60
References Web Aho et al. Structures de donnees et algorithmes, Addisson-Wesley / InterEditions Aho et Ullman. Concepts fondamentaux de l’informatique, Dunod Sedgewick. Algorithmes en C. Addisson-Wesley / InterEditions
61
Annexe: Pointeurs de fonction
But : paramétrer des fonctions par d’autres fonctions pour modifier leur actions. Déclaration : type (* nom_de_fonction) ([arguments]); Utilisation : (* nom_de_fonction) (arg1, arg2, arg3,...); Exemple: liste chaînée d’éléments: on peut définir une fonction générique qui parcours la liste est appelle une fonction sur chacun des éléments, par exemple: imprime le contenu du noeud a l’écran (sortie std) imprime le contenu du noeud dans un fichier imprime le contenu du noeud, de son prédécesseur et de son successeur etc.
62
Annexe: Pointeurs de fonction
short tab[10] short carre( short v ) { return a * a; } void imprimer( int nb_elems, short (* function )( short ) ) { for( i = 0; i < nb_elems; ++i ) { printf( “%d ”, (* function) ( tab[i] ) ); } int main() { for( i = 0; i < 10; i++ ) { tab[i] = n; imprimer( 10, carre ); Retour aux arbres
Présentations similaires
© 2024 SlidePlayer.fr Inc.
All rights reserved.