Einführung in Algorithmen und Datenstrukturen in C#
Algorithmen und Datenstrukturen sind die Grundlage, auf der jede qualitativ hochwertige Software aufbaut. Im .NET-Ökosystem und der Sprache C# ermöglicht das Verständnis dieser Konzepte nicht nur, effizienteren Code zu schreiben, sondern auch die richtigen Werkzeuge aus der umfangreichen Standardbibliothek (BCL – Base Class Library) auszuwählen. Von der Wahl der Datenstruktur hängen die Geschwindigkeit der Anwendung, der Speicherverbrauch und letztendlich die Benutzererfahrung ab.
In diesem Artikel werden wir die wichtigsten Datenstrukturen und Algorithmen behandeln, die jeder C#-Entwickler kennen sollte. Wir betrachten ihre Implementierung, Leistungsmerkmale (Big O-Notation) und praktische Codebeispiele. Der Artikel eignet sich sowohl für Anfänger als auch für erfahrene Programmierer, die ihr Wissen systematisieren möchten.
Grundlegende Datenstrukturen in C#
Arrays und Listen (Array vs List)
Array ist eine feste Datenstruktur, die Elemente desselben Typs in einem zusammenhängenden Speicherbereich speichert. Der Zugriff über den Index erfolgt in O(1), aber das Einfügen und Löschen von Elementen (außer am Ende) erfordert O(n) aufgrund der Verschiebung.
int[] numbers = new int[5] { 10, 20, 30, 40, 50 };Console.WriteLine(numbers[2]); // 30List<T> ist ein dynamisches Array. Es erhöht automatisch seine Kapazität beim Hinzufügen von Elementen. Intern wird ein Array verwendet, daher ist die Zugriffsgeschwindigkeit über den Index ebenfalls O(1). Das Einfügen in die Mitte oder am Anfang ist jedoch O(n).
List<string> names = new List<string>() { "Anna", "Boris" };names.Add("Viktor");names.Insert(1, "Gleb"); // O(n)Console.WriteLine(names[0]); // AnnaStack und Queue (Stack und Queue)
Stack<T> (Stapel) arbeitet nach dem LIFO-Prinzip (Last In, First Out). Es wird für Traversierungsalgorithmen, Ausdrucksauswertung und Aufrufverwaltung verwendet.
Stack<int> stack = new Stack<int>();stack.Push(1);stack.Push(2);stack.Push(3);int top = stack.Pop(); // 3Queue<T> (Warteschlange) arbeitet nach dem FIFO-Prinzip (First In, First Out). Es wird in Aufgabenverarbeitungssystemen und Datenpufferung verwendet.
Queue<string> queue = new Queue<string>();queue.Enqueue("Aufgabe 1");queue.Enqueue("Aufgabe 2");string next = queue.Dequeue(); // "Aufgabe 1"Beide Strukturen sind auf Basis eines Arrays (Ringpuffer) implementiert und bieten Einfüge- und Löschoperationen im Durchschnitt mit O(1).
Dictionary (Dictionary)
Dictionary<TKey, TValue> ist eine Hashtabelle. Sie ermöglicht das Suchen, Einfügen und Löschen von Elementen über einen Schlüssel im Durchschnitt mit O(1) (bei guter Hashfunktion). Dies ist eine der am häufigsten verwendeten Datenstrukturen in C#.
Dictionary<string, int> ages = new Dictionary<string, int>();ages["Alice"] = 30;ages["Bob"] = 25;
if (ages.ContainsKey("Alice")){ Console.WriteLine(ages["Alice"]); // 30}Wichtig: Schlüssel im Dictionary müssen eindeutig sein und das Interface IEquatable<T> implementieren oder korrekt überschriebene GetHashCode()- und Equals()-Methoden haben.
Verkettete Liste (LinkedList)
LinkedList<T> ist eine doppelt verkettete Liste. Im Gegensatz zu List erfolgt das Einfügen und Löschen in der Mitte der Liste in O(1) (wenn Sie einen Verweis auf den Knoten haben). Der Zugriff über den Index ist jedoch O(n). Sie wird seltener verwendet, ist aber unverzichtbar für Warteschlangen mit bidirektionalem Zugriff und LRU-Caches.
LinkedList<int> list = new LinkedList<int>();list.AddLast(1);list.AddLast(2);list.AddFirst(0);
LinkedListNode<int> node = list.Find(1);list.AddAfter(node, 10); // O(1)Sortier- und Suchalgorithmen in C#
Schnelle Sortierung (QuickSort)
QuickSort –