using System; using System.Collections; using System.Collections.Generic; namespace Developpez.Dotnet.Collections { /// /// Représente une collection de type pile (dernier entré, premier sorti, LIFO), /// où chaque élément n'est présent qu'une fois. /// /// Type des éléments de la collection /// Si un élément déjà présent est ajouté à nouveau, il est replacé au sommet de la pile public class StackSet : ICollection { private readonly LinkedList _items; private readonly Dictionary> _nodes; private readonly IEqualityComparer _comparer; /// /// Crée une nouvelle instance de StackSet<T> avec le comparateur d'égalité par défaut /// public StackSet() : this(null) { } /// /// Crée une nouvelle instance de StackSet<T> avec le comparateur d'égalité spécifié /// /// Comparateur à utiliser pour tester l'égalité des éléments public StackSet(IEqualityComparer comparer) { _comparer = comparer ?? EqualityComparer.Default; _items = new LinkedList(); _nodes = new Dictionary>(_comparer); } /// /// Ajoute une élément au sommet de la pile. Si l'élément est déjà présent, il est replacé au sommet de la pile. /// /// Élément à ajouter /// true si l'élément a été ajouté, false s'il était déjà présent /// Cette méthode est proche d'une opération en O(1) si la capacité interne est suffisante. /// Si la capacité doit être augmentée, cette méthode devient une opération en O(n). public bool Push(T item) { LinkedListNode node; if (_nodes.TryGetValue(item, out node)) { if (node.Previous != null) // i.e. not already on top of the stack { _items.Remove(node); node = _items.AddFirst(item); _nodes[item] = node; } return false; } node = _items.AddFirst(item); _nodes[item] = node; return true; } /// /// Supprime et retourne l'élément se trouvant au sommet de la pile. /// /// L'élément qui se trouvait au sommet de la pile /// Cette méthode est proche d'une opération en O(1) public T Pop() { var node = _items.First; if (node == null) throw new InvalidOperationException("The stack was empty"); T item = node.Value; _items.RemoveFirst(); _nodes.Remove(item); return item; } /// /// Retourne l'élément se trouvant au sommet de la pile, sans le supprimer /// /// L'élément se trouvant au sommet de la pile /// Cette méthode est une opération en O(1). public T Peek() { var node = _items.First; if (node == null) throw new InvalidOperationException("The stack was empty"); return node.Value; } #region Implementation of IEnumerable /// /// Renvoie un énumérateur pour parcourir les éléments de la collection /// /// Un énumérateur pour parcourir les éléments de la collection public IEnumerator GetEnumerator() { return _items.GetEnumerator(); } /// /// Renvoie un énumérateur pour parcourir les éléments de la collection /// /// Un énumérateur pour parcourir les éléments de la collection IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion #region Implementation of ICollection /// /// Ajoute un élément à la collection /// /// Élément à ajouter void ICollection.Add(T item) { Push(item); } /// /// Supprime un élément de la collection /// /// Élément à supprimer /// true si l'élément a été supprimé, false s'il n'appartenait pas à la collection bool ICollection.Remove(T item) { LinkedListNode node; if (_nodes.TryGetValue(item, out node)) { _items.Remove(node); _nodes.Remove(item); return true; } return false; } /// /// Supprime tous les éléments de la collection /// /// Cette méthode est une opération en O(n). public void Clear() { _items.Clear(); _nodes.Clear(); } /// /// Indique si l'élément est présent dans la collection /// /// Élément recherché /// true si l'élément est présent dans la collection, sinon false /// Cette méthode est proche d'une opération en O(1). public bool Contains(T item) { return _nodes.ContainsKey(item); } /// /// Copie les éléments de la collection vers le tableau spécifié /// /// Tableau vers lequel les éléments sont copiés /// Position dans le tableau à laquelle la copie commence /// Cette méthode est une opération en O(n). public void CopyTo(T[] array, int arrayIndex) { _items.CopyTo(array, arrayIndex); } /// /// Renvoie le nombre d'éléments dans la collection /// /// Obtenir la valeur de cette propriété est une opération en O(1). public int Count { get { return _items.Count; } } /// /// Indique si la collection est en lecture seule /// /// Obtenir la valeur de cette propriété est une opération en O(1). public bool IsReadOnly { get { return false; } } #endregion } }