Algorithmen und Datenstrukturen in C#: Grundlage für effizienten .NET-Code
In der modernen .NET-Plattformentwicklung sind Kenntnisse über Algorithmen und Datenstrukturen eine wesentliche Fähigkeit, um leistungsstarke und skalierbare Anwendungen zu erstellen. Ob Sie Webdienste in ASP.NET Core, Desktop-Anwendungen in WPF oder mobile Lösungen in Xamarin schreiben, die richtige Wahl der Datenstruktur wirkt sich direkt auf die Programmgeschwindigkeit und den Speicherverbrauch aus. In diesem Artikel untersuchen wir wichtige Datenstrukturen und Algorithmen in der Sprache C# und begleiten jeden Abschnitt mit praktischen Codebeispielen.
1. Grundlegende Datenstrukturen in C#: Arrays und Listen
Beginnen wir mit den Grundlagen. C# verfügt über mehrere integrierte Typen zum Speichern von Sammlungen, und das Verständnis ihrer internen Funktionsweise ist entscheidend wichtig.
Arrays (Array)
Ein Array ist eine feste Sequenz von Elementen desselben Typs. Es bietet den schnellsten indexbasierten Zugriff (O(1)), erlaubt aber keine Größenänderung nach der Erstellung.
int[] numbers = new int[5] { 10, 20, 30, 40, 50 };// Indexbasierter Zugriffint thirdElement = numbers[2]; // 30// Ändern eines Elementsnumbers[3] = 100;Verwenden Sie Arrays, wenn die Anzahl der Elemente im Voraus bekannt ist und sich nicht ändert (z. B. zum Speichern von Konstanten oder festen Puffern).
Liste (List<T>)
List<T> ist ein dynamisches Array. Es wird automatisch erweitert, wenn neue Elemente hinzugefügt werden. Intern verwendet es ein reguläres Array, das neu erstellt wird, wenn die Kapazität überschritten wird.
List<string> fruits = new List<string>();fruits.Add("Apple");fruits.Add("Banana");fruits.Add("Orange");Console.WriteLine(fruits.Count); // 3fruits.RemoveAt(1); // Entfernt "Banana"List<T> ist eine universelle Wahl für die meisten Aufgaben, die sequentiellen Zugriff und häufige Größenänderungen der Sammlung erfordern.
2. Stapel und Warteschlange: LIFO- und FIFO-Prinzipien
Diese beiden Datenstrukturen implementieren strenge Regeln für das Hinzufügen und Entfernen von Elementen. Sie sind unverzichtbar für die Ausdrucksanalyse, die verzögerte Aufgabenverarbeitung und die Implementierung von Traversierungsalgorithmen.
Stapel (Stack<T>)
Ein Stapel arbeitet nach dem "last in, first out" (LIFO)-Prinzip. In .NET ist der Stapel als generische Sammlung implementiert.
Stack<int> stack = new Stack<int>();stack.Push(1);stack.Push(2);stack.Push(3);
int top = stack.Pop(); // 3int peek = stack.Peek(); // 2 (ohne Entfernung)Praxisbeispiel: Überprüfung der Klammerkorrektheit in einer Zeichenfolge oder Implementierung der "Zurück"-Schaltfläche in einem Browser.
Warteschlange (Queue<T>)
Eine Warteschlange folgt dem "first in, first out" (FIFO)-Prinzip. Dies ist eine ideale Wahl für die Verarbeitung von Aufgaben in der Reihenfolge ihres Eintreffens.
Queue<string> queue = new Queue<string>();queue.Enqueue("Task 1");queue.Enqueue("Task 2");queue.Enqueue("Task 3");
string task = queue.Dequeue(); // "Task 1"string nextTask = queue.Peek(); // "Task 2"Warteschlangen werden aktiv in Producer-Consumer-Mustern, der Nachrichtenverarbeitung und in Protokollierungssystemen eingesetzt.
3. Bäume und rekursive Algorithmen in C#
Bäume sind hierarchische Strukturen, in denen jeder Knoten mehrere Kindknoten haben kann. Binäre Suchbäume (BST) nehmen einen besonderen Platz ein, da sie schnelles Suchen, Einfügen und Löschen (durchschnittlich O(log n)) ermöglichen.
Implementierung eines binären Suchbaums
public class TreeNode{ public int Value; public TreeNode Left; public TreeNode Right;
public TreeNode(int value) { Value = value; }}
public class BinarySearchTree{ public TreeNode Root;
public void Insert(int value) { Root = InsertRec(Root, value); }
private TreeNode InsertRec(TreeNode root, int value) { if (root == nu