🔹 1. Quelle est la différence entre List et ArrayList ?
| Critère | List | ArrayList |
|---|---|---|
| Namespace | System.Collections.Generic |
System.Collections |
| Type de données | Générique (type sûr) | Non générique (type object) |
| Sécurité de type | Compile-time (empêche les erreurs de cast) ✅ | Runtime (requiert des cast) ❌ |
| Performance | Meilleure (pas de boxing/unboxing) | Moins bonne (boxing des types valeur) |
| Exemple | List<int> list = new List<int>(); |
ArrayList list = new ArrayList(); |
🧩 Exemple :
List<int> list = new List<int> { 1, 2, 3 }; // ✅ Type-sûr
ArrayList arr = new ArrayList { 1, "abc", 3.5 }; // ❌ Types mélangés
🧠 Conclusion :
List<T>est préférée car elle est fortement typée, performante et moderne.
ArrayListest obsolète depuis l’introduction des collections génériques.
🔹 2. Pourquoi Dictionary<TKey, TValue> est-il plus rapide que List<KeyValuePair<TKey, TValue>> pour la recherche ?
-
Dictionary<TKey, TValue>utilise une table de hachage (hash table) pour stocker les éléments.-
La recherche (
ContainsKey,TryGetValue) s’effectue en O(1) en moyenne.
-
-
List<KeyValuePair<TKey, TValue>>effectue une recherche séquentielle sur chaque élément.-
La recherche est en O(n).
-
🧩 Exemple :
Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1, "Alice");
dict.Add(2, "Bob");
dict.TryGetValue(2, out var name); // O(1)
List<KeyValuePair<int, string>> list = new List<KeyValuePair<int, string>>();
list.Add(new KeyValuePair<int, string>(1, "Alice"));
list.Add(new KeyValuePair<int, string>(2, "Bob"));
var found = list.FirstOrDefault(x => x.Key == 2); // O(n)
🧠 Conclusion :
Dictionaryest optimisé pour la recherche rapide grâce à son mécanisme de hachage interne.
🔹 3. Différence entre Queue et Stack
| Collection | Type | Principe | Méthodes principales |
|---|---|---|---|
| Queue | File (FIFO) | First In, First Out | Enqueue(), Dequeue() |
| Stack | Pile (LIFO) | Last In, First Out | Push(), Pop() |
🧩 Exemple :
Queue<string> queue = new Queue<string>();
queue.Enqueue("A");
queue.Enqueue("B");
Console.WriteLine(queue.Dequeue()); // A (FIFO)
Stack<string> stack = new Stack<string>();
stack.Push("A");
stack.Push("B");
Console.WriteLine(stack.Pop()); // B (LIFO)
🧠 Conclusion :
Queue<T>gère les éléments dans l’ordre d’arrivée (ex : files d’attente).
Stack<T>gère les éléments en ordre inverse (ex : historique de navigation).
🔹 4. Qu'est-ce qu’un LinkedList et quand l’utiliser ?
✅ Définition :
LinkedList<T> est une liste doublement chaînée, où chaque élément contient un lien vers le précédent et le suivant.
✅ Avantages :
-
Insertion et suppression rapides en O(1) à n’importe quelle position si le nœud est connu.
-
Pas de redimensionnement comme dans un tableau.
⚠️ Inconvénients :
-
Accès à un élément par index coûteux (O(n)).
-
Consomme plus de mémoire (pointeurs supplémentaires).
🧩 Exemple :
LinkedList<string> list = new LinkedList<string>();
list.AddLast("A");
list.AddLast("B");
list.AddFirst("Start");
🧠 Quand l’utiliser :
Quand on a beaucoup d’insertion/suppression au milieu de la collection,
mais peu d’accès aléatoire par index.
🔹 5. Quelle est la complexité de recherche dans un HashSet ?
-
HashSet<T>stocke les éléments uniques en utilisant un algorithme de hachage. -
Complexité moyenne :
O(1) -
Pire cas (collisions extrêmes) :
O(n)
🧩 Exemple :
HashSet<int> set = new HashSet<int> { 1, 2, 3 };
bool exists = set.Contains(2); // O(1)
🧠 Conclusion :
HashSet<T>est idéal pour tester rapidement la présence ou l’unicité d’un élément.
🔹 6. Qu'est-ce que SortedList<TKey, TValue> et en quoi diffère-t-il de SortedDictionary<TKey, TValue> ?
| Critère | SortedList<TKey, TValue> | SortedDictionary<TKey, TValue> |
|---|---|---|
| Structure interne | Deux tableaux triés (TKey[], TValue[]) |
Arbre binaire équilibré (Red-Black Tree) |
| Mémoire | Moins de mémoire | Plus de mémoire |
| Insertion | Plus lente pour grands ensembles (O(n)) |
Plus rapide (O(log n)) |
| Accès par index | Oui | Non |
| Itération | Ordonnée par clé | Ordonnée par clé |
🧩 Exemple :
SortedList<int, string> list = new SortedList<int, string>();
list.Add(2, "B");
list.Add(1, "A");
SortedDictionary<int, string> dict = new SortedDictionary<int, string>();
dict.Add(2, "B");
dict.Add(1, "A");
🧠 Conclusion :
SortedListest meilleur pour petites collections triées.
SortedDictionaryest meilleur pour insertion/suppression fréquentes.
🔹 7. Quelle est la différence entre IEnumerable et IQueryable ?
| Critère | IEnumerable | IQueryable |
|---|---|---|
| Namespace | System.Collections.Generic |
System.Linq |
| Exécution | In-memory (C#) | Déférée (souvent base de données) |
| Filtrage | Fait en mémoire | Traduit en expression (SQL, etc.) |
| Source typique | Collections (List, Array) |
Entity Framework, LINQ to SQL |
| Performance | Moins optimisée pour DB | Optimisée pour la requête distante |
🧩 Exemple :
IEnumerable<User> users = db.Users.ToList().Where(u => u.Age > 30); // Filtrage en mémoire
IQueryable<User> query = db.Users.Where(u => u.Age > 30); // Filtrage côté SQL
🧠 Conclusion :
IQueryablepermet la traduction en requête distante (SQL),
alors queIEnumerablemanipule les données déjà chargées.
🔹 8. Comment fonctionne la méthode LINQ Select() et Where() ?
| Méthode | Rôle | Type de retour | Exemple |
|---|---|---|---|
| Where() | Filtrer les éléments selon une condition | IEnumerable<T> |
list.Where(x => x > 10) |
| Select() | Projeter / transformer chaque élément | IEnumerable<TResult> |
list.Select(x => x * 2) |
🧩 Exemple combiné :
List<int> numbers = new() { 1, 2, 3, 4, 5, 6 };
var result = numbers
.Where(x => x % 2 == 0) // Filtre (pairs)
.Select(x => x * x); // Projection (carré)
foreach (var n in result)
Console.WriteLine(n); // 4, 16, 36
🧠 Fonctionnement :
Ces méthodes utilisent l’exécution différée :
le traitement n’a lieu que lors de l’itération (foreach,ToList(), etc.).
📘 RÉCAPITULATIF SYNTHÉTIQUE
| Concept | Description | Complexité |
|---|---|---|
List<T> |
Collection générique, accès indexé | O(1) |
ArrayList |
Ancienne collection non typée | O(1) |
Dictionary<TKey, TValue> |
Table de hachage clé-valeur | O(1) |
Queue<T> |
File FIFO | O(1) |
Stack<T> |
Pile LIFO | O(1) |
LinkedList<T> |
Liste doublement chaînée | O(1) insertion |
HashSet<T> |
Ensemble unique, basé sur hachage | O(1) |
SortedList vs SortedDictionary |
Collections triées | O(log n) |
IEnumerable<T> |
Exécution en mémoire | n/a |
IQueryable<T> |
Exécution distante (SQL) | n/a |
🔹 1. Quelle est la différence entre SortedSet et HashSet ?
| Caractéristique | HashSet<T> |
SortedSet<T> |
|---|---|---|
| Ordre | Non trié | Toujours trié selon Comparer<T> |
| Recherche | O(1) en moyenne | O(log n) (arbre rouge-noir) |
| Complexité insertion | O(1) | O(log n) |
| Usage | Vérifier présence, collections uniques rapides | Collections uniques avec tri automatique |
🧩 Exemple :
var hashSet = new HashSet<int> { 3, 1, 2 };
var sortedSet = new SortedSet<int> { 3, 1, 2 };
Console.WriteLine(string.Join(",", hashSet)); // ordre indéfini
Console.WriteLine(string.Join(",", sortedSet)); // 1,2,3
🔹 2. Comment fonctionne un PriorityQueue en C# et quels sont ses avantages ?
✅ Définition :
PriorityQueue<TElement, TPriority> est une file avec priorité : l’élément avec la plus haute priorité (ou la plus basse selon comparaison) est servi en premier.
🧩 Exemple :
var pq = new PriorityQueue<string, int>();
pq.Enqueue("low", 5);
pq.Enqueue("high", 1);
Console.WriteLine(pq.Dequeue()); // "high" (priorité 1)
✅ Avantages :
-
Algorithme heap-based, O(log n) pour insertion et suppression
-
Idéal pour algorithmes de graphe (Dijkstra), gestion de tâches avec priorité
🔹 3. Pourquoi ImmutableDictionary<TKey, TValue> est-il utile ?
✅ Définition :
-
Dictionnaire immuable, toute modification crée une nouvelle instance.
-
Thread-safe par nature.
✅ Avantages :
-
Sécurité multi-thread
-
Prévisibilité (pas de modification inattendue)
-
Compatible avec architecture fonctionnelle / programmation réactive
🧩 Exemple :
var dict = ImmutableDictionary<string, int>.Empty;
var newDict = dict.Add("A", 1);
Console.WriteLine(dict.ContainsKey("A")); // false
Console.WriteLine(newDict.ContainsKey("A")); // true
🔹 4. Comment optimiser la recherche dans une liste avec BinarySearch ?
✅ Conditions :
-
La liste doit être triée
-
BinarySearchutilise un algorithme diviser-pour-régner, O(log n)
🧩 Exemple :
var list = new List<int> {1, 3, 5, 7, 9};
int index = list.BinarySearch(5); // 2
Si la liste n’est pas triée, trier d’abord avec
list.Sort().
🔹 5. Différence entre ConcurrentDictionary<TKey, TValue> et ImmutableDictionary<TKey, TValue>
| Caractéristique | ConcurrentDictionary |
ImmutableDictionary |
|---|---|---|
| Thread-safety | Oui, mutable | Oui, immuable |
| Modification | Possible directement | Chaque modification → nouvelle instance |
| Usage | Multi-thread performant | Multi-thread + sécurité immutabilité, architecture fonctionnelle |
🔹 6. Pourquoi et comment utiliser ObservableCollection ?
✅ Objectif :
Collection notifiant les changements (Add, Remove, Reset) à l’UI ou aux observateurs.
🧩 Exemple :
ObservableCollection<string> list = new();
list.CollectionChanged += (s, e) => Console.WriteLine(e.Action);
list.Add("Hello"); // déclenche l’événement CollectionChanged
Utilisé surtout en WPF / MVVM pour liaison dynamique à l’UI.
🔹 7. Meilleure structure pour stocker des données triées fréquemment mises à jour
-
SortedDictionary<TKey, TValue> ou SortedSet : insertion O(log n), tri automatique
-
Pour recherches fréquentes sans modification, ImmutableSortedDictionary pour thread-safety
-
Pour mutations fréquentes et performance multi-thread : combiner ConcurrentDictionary + tri au besoin
🔹 8. Différence entre IDictionary<TKey, TValue> et IReadOnlyDictionary<TKey, TValue>
| Caractéristique | IDictionary | IReadOnlyDictionary |
|---|---|---|
| Modification | Oui | Non |
| Lecture seule | Possible mais mutable | Garantie immuable |
| Usage | Collections générales | API exposant seulement lecture |
🧩 Exemple :
IDictionary<int, string> dict = new Dictionary<int, string>();
IReadOnlyDictionary<int, string> readOnly = dict;
🔹 9. Comment fonctionnent ReadOnlyMemory et ReadOnlySpan ?
| Type | Stockage | Mutable | Stack-only | Usage |
|---|---|---|---|---|
ReadOnlySpan<T> |
Référence sur mémoire | Non | ✅ | Slices rapides, parsing |
ReadOnlyMemory<T> |
Heap ou stack | Non | ❌ | Async-friendly, stockage plus long |
🧩 Exemple :
var array = new int[] {1,2,3,4};
ReadOnlySpan<int> span = array.AsSpan(0, 2); // [1,2]
ReadOnlyMemory<int> memory = array.AsMemory(0,2); // [1,2]
ReadOnlyMemory<T>peut être stocké ou passé àasynccontrairement àSpan<T>.
🔹 10. Comment fonctionne Tuple<T1, T2, ...> et pourquoi préférer ValueTuple<T1, T2, ...> ?
✅ Tuple<T1,T2,...>
-
Reference type
-
Immutable
-
Syntaxe plus lourde, moins lisible (
Item1,Item2) -
Allocation sur le heap
✅ ValueTuple<T1,T2,...>
-
Value type → pas d’allocation inutile
-
Compatible déconstruction
-
Syntaxe plus claire (
var (x,y) = GetValues();)
🧩 Exemple :
// Tuple classique
Tuple<int,string> t1 = Tuple.Create(1,"A");
// ValueTuple
var t2 = (1,"A");
var (id, name) = t2;
✅ Préférer
ValueTuplepour performance et lisibilité.
📘 Synthèse des Structures
| Collection | Usage principal | Performance | Particularité |
|---|---|---|---|
| HashSet | Unicité rapide | O(1) | Non trié |
| SortedSet | Unicité triée | O(log n) | Trie automatique |
| PriorityQueue | File avec priorité | O(log n) | Algorithme de heap |
| ImmutableDictionary | Sécurité thread / immutabilité | O(log n) | Nouvelle instance à chaque modification |
| ConcurrentDictionary | Multi-thread mutable | O(1) | Thread-safe |
| ObservableCollection | UI binding | O(1) | Notifie changements |
| ReadOnlySpan / ReadOnlyMemory | Slices mémoire | ⚡ très rapide | Span stack-only, Memory heap-async |
| Tuple / ValueTuple | Conteneur multi-valeurs | Heap vs stack | ValueTuple pour performance & lisibilité |
Aucun commentaire:
Enregistrer un commentaire