Parcours de Graham 578010 31345866 2008-07-06T13:12:58Z SieBot 236006 robot Ajoute: [[ru:Алгоритм Грэхема]] Le '''''parcours de Graham''''' est un [[algorithme]] déterminant l'[[enveloppe convexe]] d'un ensemble de points. Son principal intérêt est sa [[complexité algorithmique]] en O(n log n). Cet algorithme doit son nom à [[Ronald Graham]], a publié l'algorithme original en [[1972 en science|1972]]<ref>(en) Graham, R.L. (1972). [http://www.sciencedirect.com/science?_ob=IssueURL&_tockey=%23TOC%235645%231972%23999989995%23299179%23FLP%23&_auth=y&view=c&_acct=C000050221&_version=1&_urlVersion=0&_userid=10&md5=5d4861b6aa0cc6f286e142e7d22047c1 An Efficient Algorithm for Determining the Convex Hull of a Finite Planar Set]. Information Processing Letters 1, 132-133</ref>. ==Algorithme== {| class="infobox" style="align: center; width: 160px; font-size: 90%;" |+ '''Illustration''' | [[Image:Graham_scan.png]]<br> Comme on peut le voir, passer de A à B ou de B à C se fait dans le sens opposé aux aiguilles d'une montre, mais ce n'est pas le cas pour passer de C à D. L'algorithme détecte cette situation et rejette les segments précédemment choisis jusqu'à ce que le tournant pris soit dans le sens opposé aux aiguilles d'une montre (B à D dans ce cas). |- |} La première étape de cet algorithme consiste à rechercher le point de plus petite [[ordonnée]]. S'il y a égalité entre un ou plusieurs points, l'algorithme choisit parmi eux le point de plus petite [[abscisse]]. Nommons P ce point. La complexité en temps de cette étape est en O(n), n étant le nombre de points de l'ensemble. L'ensemble des points (P compris) est ensuite trié en fonction de l'angle que chacun d'entre eux et le point P font avec l'axe des abscisses. N'importe quel algorithme de tri convient pour cela, par exemple le [[tri par tas]] (qui a une complexité de O(n log n)). Dans le but d'accélérer les calculs, on peut se dispenser de calculer l'angle réel que ces points font avec l'axe des abscisses. Il suffit en effet de calculer la [[tangente]] de cet angle, ce qui est réalisable par arithmétique simple. À l'issue de cette étape, on dispose d'un tableau T contenant les points ainsi triés. L'algorithme considère ensuite successivement les séquences de trois points contigus dans le tableau T, vus comme deux couples successifs. Pour chacun de ces paires de couples, il décide si passer du premier couple au second constitue un « tournant à gauche » ou un « tournant à droite ». Si c'est un « tournant à droite », cela signifie que l'avant dernier point considéré (le deuxième des trois) ne fait pas partie de l'enveloppe convexe, et qu'il doit être rejeté de T. Cette analyse se répète ensuite, tant que l'ensemble des trois derniers points est un « tournant à droite ». Dès que l'on rencontre un « tournant à gauche », l'algorithme passe au point suivant de T. (Si l'on rencontre trois points [[colinéaire]]s, à quelque étape que ce soit, on peut choisir de conserver ou de rejeter le point considéré, au choix, suivant la définition que l'on choisit pour l'enveloppe convexe : en effet certaines applications requièrent que tous les points sur l'enveloppe soient compris dans l'enveloppe). Ici encore, déterminer si trois points constituent un « tournant à gauche » ou un « tournant à droite » ne requiert pas de calculer l'angle réel entre les deux [[segment]]s, et peut être réalisé par simple arithmétique. Pour trois points (x<sub>1</sub>,y<sub>1</sub>), (x<sub>2</sub>,y<sub>2</sub>) et (x<sub>3</sub>,y<sub>3</sub>), il suffit de calculer le sens du [[produit vectoriel]] des deux [[vecteur]]s définis par les points (x<sub>1</sub>,y<sub>1</sub>), (x<sub>2</sub>,y<sub>2</sub>) et (x<sub>1</sub>,y<sub>1</sub>), (x<sub>3</sub>,y<sub>3</sub>), donné par le signe de l'expression (x<sub>2</sub>-x<sub>1</sub>)(y<sub>3</sub>-y<sub>1</sub>)-(y<sub>2</sub>-y<sub>1</sub>)(x<sub>3</sub>-x<sub>1</sub>). Si le résultat est nul, les points sont colinéaires. S'il est positif, les trois points constituent un « tournant à gauche », dans le cas contraire c'est un « tournant à droite ». Ce processus retournera finalement au point auquel il a commencé, auquel cas l'algorithme sera terminé, et T contiendra alors les points formant l'enveloppe convexe, dans l'ordre inverse des aiguilles d'une montre. ==Complexité algorithmique== Le tri des points peut se faire avec une complexité en temps en O(n log n). La complexité de la boucle principale peut sembler être O(n²), parce que l'algorithme revient en arrière à chaque point pour évaluer si l'un des points précédents est un « tournant à droite ». Mais elle est en fait en O(n), parce que chaque point n'est considéré qu'une seule fois. Ainsi, chaque point analysé ou bien termine la sous-boucle, ou bien est retiré de T et n'est donc plus jamais considéré. La complexité globale de l'algorithme est donc en O(n log n), puisque la complexité du tri domine la complexité du calcul effectif de l'enveloppe convexe. == Pseudo-code== Soit Points l'ensemble de points à examiner, sous la forme d'un tableau indexé à partir de un, et Pile une [[pile (informatique)|pile]] qui contiendra le résultat final. <pre> Trouver le pivot P; Trier les points par angle (les points d'angle égal seront triés par rapport à leur abscisse); # Points[1] est le pivot, Points[longueur] aussi (fin du circuit) Pile.empiler(Points[1]); Pile.empiler(Points[2]); POUR i = 3 A Points.longueur TANT QUE Produit_vectoriel(Pile.second, Pile.haut, Points[i]) <= 0 et Pile.hauteur >= 2 Pile.dépiler; FIN TANT QUE Pile.entrer(Points[i]); FIN POUR FUNCTION Produit_vectoriel(p1, p2, p3) RENVOYER(p2.x - p1.x)*(p3.y - p1.y) - (p3.x - p1.x)*(p2.y - p1.y); FIN FONCTION </pre> Note: pour gérer les cas dégénérés où l'enveloppe convexe a moins de trois points, un seul point devrait être entré dans la pile au départ, et si jamais la pile a moins de deux points (elle en aura au moins toujours un), alors le haut de la pile devrait être également sorti si le nouveau point est le point considéré. En d'autres termes, la condition du « tant que » devrait être : :<code>Pile.hauteur >= 2 ? Produit_vectoriel(Pile.second, Pile.haut, Points[i]<= 0 : Pile.haut == Points[i]</code>. == Notes et références de l'article == <references/> *{{Traduction/Référence|en|Graham scan|168305787}} == Voir aussi == <!--=== Articles connexes === * [[À remplacer]]--> === Liens et documents externes === * {{en}} Thomas H. Cormen, Charles E. Leiserson, [[Ronald L. Rivest]], et Clifford Stein. ''Introduction to Algorithms'', Deuxième édition. MIT Press et McGraw-Hill, 2001. ISBN 0-262-03293-7. Pages 949&ndash;955 de la section 33.3: Finding the convex hull. * {{en}} [http://www.partow.net/projects/fastgeo/index.html Implémentations du parcours de Graham en C++ et en Pascal Objet] [[Catégorie:Algorithme d'infographie]] [[Catégorie:Algorithmique et convexité]] {{Convexité}} {{Portail|géométrie|mathématiques|informatique}} [[de:Graham Scan]] [[en:Graham scan]] [[he:הסריקה של גראהם]] [[pl:Algorytm Grahama]] [[pt:Exame de Graham]] [[ru:Алгоритм Грэхема]] [[sr:Грахамово скенирање]]