Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

PRIORITY QUEUE


Information sur la source

Catégorie :Maths & Algorithmes Source .NET ( DotNet ) Classé sous : queue, priority, algorithme, arbre, binaire Niveau : Débutant Date de création : 10/05/2007 Date de mise à jour : 13/05/2007 11:13:22 Vu / téléchargé: 7 669 / 122

Note :
8,5 / 10 - par 2 personnes
8,50 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (18)
Ajouter un commentaire et/ou une note


Description

Priority Queue C#

J'imagine que tout le monde connait la class Queue du framework qui permet de faire des piles FIFO.
J'ai cherché une PriorityQueue dans le framework, mais je n'ai rien trouvé à ce sujet... Voici donc une classe générique TRES simple qui met cette fonctionnalité en place.

Les Enqueues et les Dequeues se font dans une complexité d'ordre O(log n) grâce à un arbre binaire, ce qui est assez rapide.
Une priority queue peut être utile quand certains éléments doivent absolument passer avant les autres. Par exemple, un prof qui veut imprimer un document avant des étudiants (si y'a 100 fichiers d'étudiants dans la liste d'attentes, le prof passera devant tout le monde :D).

Suite à la discussion dans les commentaires de cette source, j'ajoute que cet algorithme n'est peut-être pas le meilleur au niveau des performances (ceci dit on a quand même un O(log n) ce qui est très bien) mais il reste (comparé à d'autres solutions plus rapide) très simple à mettre en place. De plus, la place prise en mémoire est très faible (un tableau de n élément suffit).
 

Source

  • using System;
  • using System.Collections.Generic;
  • using System.Text;
  • /*************************************************************************************
  • *
  • * PriorityQueue
  • * Author : Bidou (http://www.csharpfr.com/auteurdetail.aspx?ID=13319)
  • * Blog : http://blogs.developpeur.org/bidou/
  • * Date : May 2007
  • *
  • *************************************************************************************/
  • namespace PriorityQueue
  • {
  • /// ---------------------------------------------------------------------------------
  • /// <summary>
  • /// PriorityQueue.
  • ///
  • /// Note: Insertion are done in O(log n)
  • /// Note: Removal are done in O(log n)
  • /// </summary>
  • /// <typeparam name="T"> The type to store in the priority queue. This type needs to
  • /// implement the IComparable interface. </typeparam>
  • /// ---------------------------------------------------------------------------------
  • public class PriorityQueue<T> where T : IComparable<T>
  • {
  • private List<InnerItem> _innerList = new List<InnerItem>();
  • private int _innerIndex = -1;
  • /// ---------------------------------------------------------------------------------
  • /// <summary>
  • /// Enqueue a new item.
  • /// </summary>
  • /// <param name="item"> The item to enqueue. </param>
  • /// ---------------------------------------------------------------------------------
  • public void Enqueue(T item)
  • {
  • this._innerList.Add(new InnerItem(++this._innerIndex, item));
  • if (this._innerList.Count > 1) this.UpHeap(); // Reorder the tree if needed
  • }
  • /// ---------------------------------------------------------------------------------
  • /// <summary>
  • /// Dequeue.
  • /// </summary>
  • /// <returns> Return the first item in the queue. </returns>
  • /// ---------------------------------------------------------------------------------
  • public T Dequeue()
  • {
  • T first = this.Peek();
  • int count = this._innerList.Count - 1;
  • this._innerList[0] = this._innerList[count];
  • this._innerList.RemoveAt(count);
  • this._innerIndex--;
  • this.DownHeap();
  • return first;
  • }
  • /// ---------------------------------------------------------------------------------
  • /// <summary>
  • /// Get the first item in the queue.
  • /// </summary>
  • /// <returns> The first item. </returns>
  • /// ---------------------------------------------------------------------------------
  • public T Peek()
  • {
  • return this._innerList.Count > 0 ? this._innerList[0].Item : default(T);
  • }
  • /// ---------------------------------------------------------------------------------
  • /// <summary>
  • /// Reorder the tree (down->up).
  • /// </summary>
  • /// ---------------------------------------------------------------------------------
  • private void UpHeap()
  • {
  • int current = this._innerList.Count - 1;
  • int parent = (current - 1) / 2;
  • while (this._innerList[current].Item.CompareTo(this._innerList[parent].Item) < 0)
  • {
  • this.SwitchElements(current, parent);
  • current = parent;
  • parent = (current - 1) / 2;
  • }
  • }
  • /// ---------------------------------------------------------------------------------
  • /// <summary>
  • /// Reorder the tree (up->down).
  • /// </summary>
  • /// ---------------------------------------------------------------------------------
  • private void DownHeap()
  • {
  • int best = 0; int current = -1;
  • int left = 0; int right = 0;
  • while(best != current)
  • {
  • current = best;
  • left = 2 * best + 1;
  • right = left + 1;
  • if (this._innerList.Count > left)
  • {
  • int x = this._innerList[best].Item.CompareTo(this._innerList[left].Item);
  • if (x > 0 || (x == 0 && this._innerList[left].Index < this._innerList[best].Index)) best = left;
  • }
  • if (this._innerList.Count > right)
  • {
  • int x = this._innerList[best].Item.CompareTo(this._innerList[right].Item);
  • if (x > 0 || (x == 0 && this._innerList[right].Index < this._innerList[best].Index)) best = right;
  • }
  • if(best != current) this.SwitchElements(best, current);
  • }
  • }
  • /// ---------------------------------------------------------------------------------
  • /// <summary>
  • /// Switch two elements
  • /// </summary>
  • /// <param name="item1"> The first element. </param>
  • /// <param name="item2"> The second element. </param>
  • /// ---------------------------------------------------------------------------------
  • private void SwitchElements(int item1, int item2)
  • {
  • InnerItem item = this._innerList[item1];
  • this._innerList[item1] = this._innerList[item2];
  • this._innerList[item2] = item;
  • }
  • /// ---------------------------------------------------------------------------------
  • /// <summary>
  • /// Hold the element (add an index to keep FIFO order with same keys).
  • /// </summary>
  • /// ---------------------------------------------------------------------------------
  • private class InnerItem
  • {
  • private T _item = default(T);
  • private int _index = 0;
  • /// ---------------------------------------------------------------------------------
  • /// <summary>
  • /// Represents an item (a Node in the tree).
  • /// </summary>
  • /// <param name="index"> The index of the Node. </param>
  • /// <param name="item"> The item. </param>
  • /// ---------------------------------------------------------------------------------
  • public InnerItem(int index, T item)
  • {
  • this._index = index;
  • this._item = item;
  • }
  • /// ---------------------------------------------------------------------------------
  • /// <summary>
  • /// Get or set the item.
  • /// </summary>
  • /// ---------------------------------------------------------------------------------
  • public T Item
  • {
  • get { return this._item; }
  • set { this._item = value; }
  • }
  • /// ---------------------------------------------------------------------------------
  • /// <summary>
  • /// Get or set the index of the item.
  • /// </summary>
  • /// ---------------------------------------------------------------------------------
  • public int Index
  • {
  • get { return this._index; }
  • set { this._index = value; }
  • }
  • }
  • }
  • }
using System;
using System.Collections.Generic;
using System.Text;

/*************************************************************************************
 *
 *  PriorityQueue
 *  Author : Bidou (http://www.csharpfr.com/auteurdetail.aspx?ID=13319)
 *  Blog   : http://blogs.developpeur.org/bidou/
 *  Date   : May 2007
 * 
 *************************************************************************************/

namespace PriorityQueue
{
    /// ---------------------------------------------------------------------------------
    /// <summary>
    /// PriorityQueue.
    /// 
    /// Note: Insertion are done in O(log n)
    /// Note: Removal are done in O(log n) 
    /// </summary>
    /// <typeparam name="T"> The type to store in the priority queue. This type needs to
    /// implement the IComparable interface. </typeparam>
    /// ---------------------------------------------------------------------------------
    public class PriorityQueue<T> where T : IComparable<T>
    {
        private List<InnerItem> _innerList = new List<InnerItem>();
        private int _innerIndex = -1;

        /// ---------------------------------------------------------------------------------
        /// <summary>
        /// Enqueue a new item.
        /// </summary>
        /// <param name="item"> The item to enqueue. </param>
        /// ---------------------------------------------------------------------------------
        public void Enqueue(T item)
        {
            this._innerList.Add(new InnerItem(++this._innerIndex, item));
            if (this._innerList.Count > 1) this.UpHeap(); // Reorder the tree if needed
        }

        /// ---------------------------------------------------------------------------------
        /// <summary>
        /// Dequeue.
        /// </summary>
        /// <returns> Return the first item in the queue. </returns>
        /// ---------------------------------------------------------------------------------
        public T Dequeue()
        {
            T first = this.Peek();
            int count = this._innerList.Count - 1;
            this._innerList[0] = this._innerList[count];
            this._innerList.RemoveAt(count);
            this._innerIndex--;
            this.DownHeap();
            return first;
        }

        /// ---------------------------------------------------------------------------------
        /// <summary>
        /// Get the first item in the queue.
        /// </summary>
        /// <returns> The first item. </returns>
        /// ---------------------------------------------------------------------------------
        public T Peek()
        {
            return this._innerList.Count > 0 ? this._innerList[0].Item : default(T);
        }

        /// ---------------------------------------------------------------------------------
        /// <summary>
        /// Reorder the tree (down->up).
        /// </summary>
        /// ---------------------------------------------------------------------------------
        private void UpHeap()
        {
            int current = this._innerList.Count - 1;
            int parent = (current - 1) / 2;
            while (this._innerList[current].Item.CompareTo(this._innerList[parent].Item) < 0)
            {
                this.SwitchElements(current, parent);
                current = parent;
                parent = (current - 1) / 2;
            }
        }

        /// ---------------------------------------------------------------------------------
        /// <summary>
        /// Reorder the tree (up->down).
        /// </summary>
        /// ---------------------------------------------------------------------------------
        private void DownHeap()
        {
            int best = 0; int current = -1;
            int left = 0; int right = 0;

            while(best != current)
            {
                current = best;
                left = 2 * best + 1;
                right = left + 1;

                if (this._innerList.Count > left)
                {
                    int x = this._innerList[best].Item.CompareTo(this._innerList[left].Item);
                    if (x > 0 || (x == 0 && this._innerList[left].Index < this._innerList[best].Index)) best = left;
                }
                if (this._innerList.Count > right)
                {
                    int x = this._innerList[best].Item.CompareTo(this._innerList[right].Item);
                    if (x > 0 || (x == 0 && this._innerList[right].Index < this._innerList[best].Index)) best = right;
                }
                if(best != current) this.SwitchElements(best, current);
            }
        }

        /// ---------------------------------------------------------------------------------
        /// <summary>
        /// Switch two elements
        /// </summary>
        /// <param name="item1"> The first element. </param>
        /// <param name="item2"> The second element. </param>
        /// ---------------------------------------------------------------------------------
        private void SwitchElements(int item1, int item2)
        {
            InnerItem item = this._innerList[item1];
            this._innerList[item1] = this._innerList[item2];
            this._innerList[item2] = item;
        }

        /// ---------------------------------------------------------------------------------
        /// <summary>
        /// Hold the element (add an index to keep FIFO order with same keys).
        /// </summary>
        /// ---------------------------------------------------------------------------------
        private class InnerItem
        {
            private T _item = default(T);
            private int _index = 0;

            /// ---------------------------------------------------------------------------------
            /// <summary>
            /// Represents an item (a Node in the tree).
            /// </summary>
            /// <param name="index"> The index of the Node. </param>
            /// <param name="item"> The item. </param>
            /// ---------------------------------------------------------------------------------
            public InnerItem(int index, T item)
            {
                this._index = index;
                this._item = item;
            }

            /// ---------------------------------------------------------------------------------
            /// <summary>
            /// Get or set the item.
            /// </summary>
            /// ---------------------------------------------------------------------------------
            public T Item
            {
                get { return this._item; }
                set { this._item = value; }
            }

            /// ---------------------------------------------------------------------------------
            /// <summary>
            /// Get or set the index of the item.
            /// </summary>
            /// ---------------------------------------------------------------------------------
            public int Index
            {
                get { return this._index; }
                set { this._index = value; }
            }
        }
    }
}

Fichier Zip

Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

Historique

13 mai 2007 11:13:22 :
Les éléments de même priorités restent classés dans un ordre FIFO. Quelques modifications dans la description du code.

Commentaires et avis

signaler à un administrateur
Commentaire de SharpMao le 11/05/2007 09:33:01

Intéressant, mais pourquoi ne pas avoir utilisé une SortedList au lieu de la list. De cette manière, tu évites le tri manuel.

signaler à un administrateur
Commentaire de Warny le 11/05/2007 10:31:27

Je pense que tu t'embête beaucoup à classer tes élements.
Une priorityqueue est avant tout une liste de queue dont certaines doivent être traités avant les autres.
Tu peux dont faire une liste de queue et revoyer le premier élement de la première queue non vide.

signaler à un administrateur
Commentaire de Bidou le 11/05/2007 11:58:23 administrateur CS

SharpMao> Une SortedList est un dictionary trié, ce qui ne m'arrange pas trop pour ma liste générique (il faudrait forcé de dérivé d'une interface pour qu'on soit sûr que l'object contient par exemple une property Key). De plus, comme c'est un dictionary, il n'accepte pas les doublons (alors qu'une Priority queue, peut avoir des éléments avec une clef identique).

Pour finir, si on utilise le tris automatique de la SortedList, on se retrouve certainement (pas vérifié) avec une complexité de l'ordre de O(n^2) voire O(n log n) alors que mon implémentation avec un arbre binaire (un heap en fait) travail en O(log n) ce qui est bien meilleur (on tend presque à avoir un temps constant pour une grosse quantité d'éléments).

Warny> En utilisant ta manière, non seulement on a une place utilisée en mémoire beaucoup plus grande, mais en plus on a une complexité à coucher dehors (au moins O(n^2) je dirais au premier abord).

J'espère ne pas m'être trompé dans mes calculs, mais ça devrait être correct.

signaler à un administrateur
Commentaire de Warny le 11/05/2007 12:04:19

Non, la complexité obtenu est en O(n). En fait, tu ne fais pas de classement.
Si un document en priorité 1 doit passer forcement avant un document en priorité 2, tu mets ton document dans la file d'attente de priorité 1 et tu lis cette file en premier. Quand elle est vide tu lis la file de priorité 2 et ainsi de suite.
L'écriture se fait toujours à la fin de la file et la lecture se fait toujours au début. Je ne classe donc jamais les élements.

signaler à un administrateur
Commentaire de Bidou le 11/05/2007 12:07:42 administrateur CS

Supposons que tu aies raisons... (j'ai pas vérifié mais je te fais confiance).
Mon arbre binaire est toujours beaucoup beaucoup plus rapide avec O(log n) que ton O(n)... (en fait, incomparablement plus rapide pour des listes avec beaucoup d'éléments).

signaler à un administrateur
Commentaire de Warny le 11/05/2007 12:14:20

tu te trompe de calcul. O(log(n)) signifie que tu ne compare pas tous les élements.
Comme tu fais un tri à bulle, tu compares tous les élements à l'ensemble des autres, ce qui te fait une complexité en O(n^2)
La méthode de tri la plus rapide est le tri-fusion qui approche le O(n*log(n)) - c'est une moyenne -
La méthode de classement (et plus de tri) la plus rapide et l'arbre de classement qui permet de ranger un élement dans un arbre en fonction de sa valeur et sa complexité est en O(n) et plus précisement x*n ou x est la longueur de la valeur à classer. C'est ce que j'utilise pour répondre à ce problème.

signaler à un administrateur
Commentaire de Bidou le 11/05/2007 13:02:16 administrateur CS

Le but est justement de ne pas tout comparer pour être plus rapide! Puisque les éléments sont triés dans un arbre binaire (et trié selon l'implémentation du CompareTo) on obtient une insertion triée (enqueue) en O(log n) et une supression (dequeue) en O(log n) également car on ne doit justement pas parcourir tous les éléments de l'arbre !

Tu peux faire une recherche sur le net, tu verras qu'effectivement je ne te raconte pas de bêtise et qu'un enqueue et dequeue se font bien en O(log n) si on implémente un Heap (ce qui est, encore une fois, bien plus rapide que ton O(n) que tu proposes...)

signaler à un administrateur
Commentaire de Warny le 11/05/2007 13:21:54

je compte O(n) avec n étant le nombre d'élément que j'insère dans ma queue. Si je ne m'interresse qu'à 1 élement je suis en O(1) (je ne peux pas faire mieux).
De la même façon, en moyenne en insertion pour 1 élement tu est en O(log(n)) ou n est le nombre d'éléments déjà présents dans ta queue. Si tu dois classer l'ensemble des éléments que tu insère, il faut compter au moins une fois chaque élément O(n) que tu classes O(log(n)). Soit au total O(n*log(n)).
Pour récapituler :
+ pour 1 élement :
  - tri-insertion : O(log(n))
  - classement-arbre : O(1)
+ pour n élements :
  - tri-insertion : O(n*log(n))
  - classement-arbre : O(n)

signaler à un administrateur
Commentaire de Bidou le 11/05/2007 13:37:43 administrateur CS

Je ne comprend pas trop où tu veux en venir. La solution que je propose pour implémenter une PriorityQueue n'est pas révolutionnaire, c'est la méthode qui est recommandé (car la plus rapide). Je n'ai pas inventé l'algorithme HeapSort...

Si tu insères sans trié, tu insères en O(1) mais il te faut O(n) pour faire sortir l'élément
IN : O(1)
OUT: O(n)

Si tu insères trié, tu insères en O(n) mais il te faut O(1) pour faire sortir l'élément
IN : O(n)
OUT: O(1)

Si tu utilises un Heap, tu insères en O(log n) et tu fais sortir l'élément en O(log n) également
IN : O(log n)
OUT: O(log n)


Il est évident que la dernière solution est de loin la meilleure, car même si tu insères (respectivement sort) en O(1) tu vas sortir (respectivement insérer) en O(n). C'est à dire que tu sera un tout petit peu meilleur avec ton O(1) mais largement largué ensuite par ton O(n) (plus n sera élevé, plus tu seras largué)

Exemple avec 1000 éléments:

Ma solution:
IN : ~O(10)
OUT: ~O(10)

la tienne:

IN : O(1) respectivement O(1000)
OUT: O(1000) respectivement O(1)

T'es un tout petit peu meilleur avec O(1) par rapport à O(10), mais clairement très loin derrière pour O(1000) comparé à un O(10).
Je ne sais pas si tu me suis ???

signaler à un administrateur
Commentaire de Warny le 11/05/2007 14:07:57

Mon principe est de faire une queue par niveau de priorité :
Queue[0]
Queue[1]
Queue[2]
Queue[3]
Queue[4]
...
Eventuellement créées dynamiquement (c'est pas la peine de créer 65535 queues si tu a ce nombre de niveaux de priorités) et détruites dynamiquement quand elles sont vides.
Si tu as un niveau de priorité 4 à mettre, tu le mets dans la liste 4 soit O(1)
Tu ne peux lire dans la liste 4 que si les listes précédente sont vides. Si c'est le cas ta complexité est... O(1). Tu prends toujours le premier élement de la première liste.
Y a pas plus efficace.
La question est pourquoi trier quand on peut classer ?

signaler à un administrateur
Commentaire de SharpMao le 11/05/2007 14:16:38

Hello,

Pour les SortedList, tu as raison.
Par contre, corrige-moi si je me trompe, mais cette méthode ne donne pas de queue FIFO avec des éléments de même priorité.

signaler à un administrateur
Commentaire de Bidou le 11/05/2007 14:21:08 administrateur CS

Warny> Imaginons que j'aie 1000 éléments, 500 clefs différentes. Tu as 500 queues à construire (dynamiquement si tu veux...). Le temps que tu construises tes 500 queues en boucles, j'ai déjà eu le temps de traiter quelques centaines de millieurs d'élément... Ma solution n'utilise effectivement qu'une List de taille n.

SharpMao> Oui, tu as raison ;-)

signaler à un administrateur
Commentaire de Warny le 11/05/2007 14:34:20

C'est pas faux, mais dans les faits j'aurais difficilement plus de 5 à 10 niveaux de priorités.
De plus si je suis dans le cas que tu décris et que je dois vraiment optimiser le classement, j'utiliserai un algorithme B-TREE et je serais toujours plus efficace.
Pour l'instant le seul problème pour lequel je suis obligé d'utiliser un algo de classement, c'est quand je fais de la 3D et que je dois classer des polygones, parce que leur définition utilise plus d'une dimension.
Dans le cas où mes élements n'ont qu'une dimension, je peux les classer. Dans le cas d'une queue à priorité, mon élément de priorité a rarement plus d'une dimension et mon algo, éventuellement classé en arbre, est toujours plus rapide.

signaler à un administrateur
Commentaire de Bidou le 11/05/2007 15:03:32 administrateur CS

Autre chose: comment tu fais pour ajouter une Queue dans ta liste de queues?
Tu es obligé de vérifier si elle est existante ou pas, non? Donc tu dois itérer à travers toutes tes queues pour voir si elle existe? même chose quand tu en supprimes une?

signaler à un administrateur
Commentaire de Warny le 11/05/2007 15:16:04

Non, c'est pas la peine, va voir cet excelent article de wikipédia : http://fr.wikipedia.org/wiki/B-Arbre
et notamment le lien de visualisation d'un b-arbre pour te faire une idée. C'est la méthode utilisée pour insérer les élements dans une base de données.

signaler à un administrateur
Commentaire de Bidou le 11/05/2007 15:34:55 administrateur CS

Euh j'ai pas trop le temps de regarder en détail pour le moment. Si tu as une classe générique qui s'occupe de ça, je serais curieux de faire quelques teste pour voir la différence entre les deux...

signaler à un administrateur
Commentaire de Warny le 11/05/2007 15:59:11

Je n'ai pas de classe toute faite, c'est peut-être l'occasion justement.

signaler à un administrateur
Commentaire de Bidou le 13/05/2007 11:14:49 administrateur CS

SharpMao> J'ai mis à jour pour que les éléments de même priorités restent dans un ordre FIFO.

Ajouter un commentaire

Discussions en rapport avec ce code source dans le forum

Je comprends pas cette algorithme [ par kaiwoo ] private bool AUneVirgule (double nb){long tmp = (long)nb;if (tmp == nb)return false;elsereturn true;}Pour info, il a été fait par un super membre du f Création d'un arbre [ par redpooka ] Comment fait-on en C# un arbre de donnée ? lire un fichier binaire [ par ultrafil ] Salut, j'ai besoin de lire des données dans un fichier binaire.Mon problème c'est que je n'arrive pas à faire de conversion en byte[]Je m'explique, j' Algorithme de placement [ par oberown ] Je cherche des noms d'algorithmes ou des idées, pour résoudre ce genre de problème.On a trois jours, et chaque jours 2 personnes peut se présenter. On Binaire non Binaire [ par cpetter ] BonjourJe suis en train de créer un bout de code pour écrire en binaire dans un fichier. Et à ma grande surprise, il n'écrit pas en binaire mais en te Récupérer répertoire où s'éxecute le binaire ? [ par floorfi ] Bonjour !Voilà, je suis entrain de concevoir une application de transfert de fichiers en C#, j'aurais voulu savoir comment je pouvais faire pour récup Représentation binaire d'un entier [ par bucherb ] Tchô!J'aime pas les math et là je me casse la tête..Est-ce que qqun connait une formule mathématique pour calculer sur combien de bits est représenté Algorithme Mot Caché [ par nuns ] Salut tout le monde,Je voudrais savoir si il y a quelqu ' un qui aurait un générateur de mot Caché, le jeux, avec les grille ou il faut chercher les m Fichier Binaire [ par abdoulax ] Bon voil&#224; mon pb :En fait je suis en train de faire un pgm pour envoyer un fichier. Le pb c que parfois il arrive que certain byte ne soit pas en Lecture fichier binaire et conversion hexa --> string [ par kineton ] Bonjour &#224; tous, Je suis d&#233;veloppeur en vc++ 6.0 et je commence juste &#224; programmer en C# avec VS.Net.Je cherche &#224; lire un fichier b


Nos sponsors

Sondage...

CalendriCode

Juillet 2009
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Téléchargements

Logiciels à télécharger sur le même thème :

Comparez les prix Nouvelle version

Photothèque Nouveau !



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,624 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.