Algorithms and Data Structures in C#: Foundation for Efficient .NET Code
In modern .NET platform development, knowledge of algorithms and data structures is an essential skill for creating performant and scalable applications. Whether you are writing web services in ASP.NET Core, desktop applications in WPF, or mobile solutions in Xamarin, the correct choice of data structure directly impacts program speed and memory consumption. In this article, we will examine key data structures and algorithms in the C# language, accompanying each section with practical code examples.
1. Basic Data Structures in C#: Arrays and Lists
Let's start with the fundamentals. C# has several built-in types for storing collections, and understanding their internal workings is critically important.
Arrays (Array)
An array is a fixed sequence of elements of the same type. It provides the fastest index-based access (O(1)), but does not allow resizing after creation.
int[] numbers = new int[5] { 10, 20, 30, 40, 50 };// Index-based accessint thirdElement = numbers[2]; // 30// Changing an elementnumbers[3] = 100;Use arrays when the number of elements is known in advance and will not change (for example, for storing constants or fixed buffers).
List (List<T>)
List<T> is a dynamic array. It automatically expands when new elements are added. Internally, it uses a regular array which is recreated when capacity is exceeded.
List<string> fruits = new List<string>();fruits.Add("Apple");fruits.Add("Banana");fruits.Add("Orange");Console.WriteLine(fruits.Count); // 3fruits.RemoveAt(1); // Remove "Banana"List<T> is a universal choice for most tasks requiring sequential access and frequent collection size changes.
2. Stack and Queue: LIFO and FIFO Principles
These two data structures implement strict rules for adding and removing elements. They are indispensable for expression parsing, deferred task processing, and implementing traversal algorithms.
Stack (Stack<T>)
A stack operates on the "last in, first out" (LIFO) principle. In .NET, the stack is implemented as a generic collection.
Stack<int> stack = new Stack<int>();stack.Push(1);stack.Push(2);stack.Push(3);
int top = stack.Pop(); // 3int peek = stack.Peek(); // 2 (without removal)Real-world example: checking bracket correctness in a string or implementing the "Back" button in a browser.
Queue (Queue<T>)
A queue follows the "first in, first out" (FIFO) principle. This is an ideal choice for processing tasks in the order they arrive.
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"Queues are actively used in Producer-Consumer patterns, message processing, and logging systems.
3. Trees and Recursive Algorithms in C#
Trees are hierarchical structures where each node can have multiple child nodes. Binary Search Trees (BST) hold a special place, providing fast search, insertion, and deletion (O(log n) on average).
Binary Search Tree Implementation
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