Data structures are the basis for the efficient and optimized development of web applications in ASP.NET Core. In this first part, we will learn about the simplest types of data structures and how we can implement them using the C# programming language.
ASP.NET Core development relies on manipulating, storing and retrieving data. A solid understanding of data structures allows developers to design and implement web applications that can handle large volumes of data and quickly respond to requests, scaling the applications efficiently.
Whether managing user sessions, caching data or optimizing database queries, data structures play a crucial role in improving the performance and reliability of ASP.NET Core applications, making them more competitive and capable of meeting the demands of modern web development.
In this post, we will cover the simplest topics in data structure in the context of ASP.NET Core, implementing an example of each and understanding each approach’s meaning.
Data represents a unit or element of information and can take different forms such as text, numbers, dates, images, videos and others.
ASP.NET Core uses the C# (C-Sharp) programming language, which has a wide variety of data types. The main types are:
- Primitive types:
- Composite types:
Dictionary<TKey, TValue>
class represents a collection of key-value pairs, where each key is unique. It allows efficient retrieval of values based on their keys.Data structures are a fundamental concept in computer science and programming. They are a way of organizing and storing data in a structured and efficient way so that it can be accessed and manipulated easily.
Data structures define how data is organized, stored and operated in a computer’s memory.
Next, we will understand the concept behind each of these data structures and how they can be implemented in C# within the context of ASP.NET Core. You can access the source code of the examples here: Practicing Data Structure source code.
An array is a data structure used to store a collection of elements of the same data type under a single variable name. These elements are stored in contiguous memory locations, making their access and manipulation efficient. Each element in an array is identified by an index or position, starting from 0 for the first element, 1 for the second, and so on.
Arrays are commonly used to store lists of data, such as numbers, strings or objects. They offer several advantages, including:
However, arrays also have some limitations, mainly with regard to size. In some scenarios, it may be necessary to use more complex data structures, such as dynamic lists.
Different programming languages have their own syntax for defining and working with arrays.
In C#, arrays can be declared as follows:
int[] intArray = { 3, 5, 10, 7, 12 }; // Integer type element
string[] stringArray = { "Apple", "Banana", "Cherry", "strawberry", "Fig" }; // Sting type element
int[] definedSizeArray = new int[5] { 3, 5, 10, 7, 12 }; // Array with defined size
int[] dynamicSizeArray = new int[] { }; // Array with dynamic size
- One-dimensional arrays (1-D arrays):
Also known as a vector, it is an array with only one dimension. Elements are organized linearly.
int[] vector = new int[5]; // Creates an array with 5 integer elements
vector[0] = 1;
vector[1] = 2;
vector[2] = 3;
vector[3] = 4;
vector[4] = 5;
- Two-dimensional arrays (2-D arrays):
Also called a matrix, a two-dimensional array is organized into rows and columns. It can be viewed as a table or grid.
int[,] matrix = new int[3, 3]; // Creates a 3x3 matrix of integers
matrix[0, 0] = 1;
matrix[0, 1] = 2;
matrix[0, 2] = 3;
matrix[1, 0] = 4;
matrix[1, 1] = 5;
matrix[1, 2] = 6;
matrix[2, 0] = 7;
matrix[2, 1] = 8;
matrix[2, 2] = 9;
- Three-dimensional array (3-D arrays):
A three-dimensional array is organized into layers, rows and columns. It can be useful for representing three-dimensional data, such as cubes.
int[,,] cube = new int[3, 3, 3]; // Creates a 3x3x3 cube of integers
cube[0, 0, 0] = 1;
cube[0, 0, 1] = 2;
cube[0, 0, 2] = 3;
cube[0, 1, 0] = 4;
cube[0, 1, 1] = 5;
cube[0, 1, 2] = 6;
cube[0, 2, 0] = 7;
cube[0, 2, 1] = 8;
cube[0, 2, 2] = 9;
// And so on for the other layers of the cube
Arrays are fundamental data structures in C# and are used in various applications to store and manipulate collections of data. Below are some common applications of arrays in C#:
These are just a few examples of how arrays are applied in C# programming. Arrays are versatile and serve as the basis for many data storage and manipulation tasks in various software applications.
A linked list is a data structure consisting of a sequence of elements, where each element (node) contains a value and a reference (or link) to the next element in the sequence.
Thus we can define that each node contains the following elements:
Next
.Head
.In C#, there are three main types of linked lists:
In a singly linked list, each node contains a value and a reference to the next node in the list. The last node in the list usually has a reference to null, indicating the end of the list.
Singly linked lists are efficient for operations that involve adding or removing elements from the beginning of the list, but less efficient for operations that involve accessing elements by index.
To create a singly-linked list in C#, create a web application with the command: dotnet new web -o PracticingDataStructure
.
Open the project and create a new folder called “Models” and inside it create the classes below:
namespace PracticingDataStructures.Models;
public class Node<T>
{
public T Data { get; set; }
public Node<T> Next { get; set; }
public Node(T data)
{
Date = date;
Next = null;
}
}
namespace PracticingDataStructures.Models;
public class MyLinkedList<T>
{
private Node<T> head;
public void Add(T data)
{
Node<T> newNode = new Node<T>(data);
if (head == null)
{
head = newNode;
}
else
{
Node<T> current = head;
while (current.Next != null)
{
current = current.Next;
}
current.Next = newNode;
}
}
public void Display()
{
Node<T> current = head;
while (current != null)
{
Console.Write(current.Data + " -> ");
current = current.Next;
}
Console.WriteLine("null");
}
}
Then in the Program.cs file, add the code below:
using PracticingDataStructures.Models;
MyLinkedList<int> myList = new MyLinkedList<int>();
myList.Add(1);
myList.Add(2);
myList.Add(3);
Console.WriteLine("Singly Linked List:");
Console.WriteLine("");
myList.Display();
Console.WriteLine("");
Finally, in the terminal, execute the following command to run the application: dotnet run
Thus, you will have the following result, which shows exactly the structure of a linked list.
In the code above we defined a class Node<T>
, which represents a single element in the linked list. It contains a Data
property to store the element’s value and a Next
property to point to the next element.
We define a class MyLinkedList<T>
, which represents the linked list itself and has a head property to point to the first element of the list.
The Add
method in the MyLinkedList<T>
class allows you to add elements to the end of the list, while the Display
method displays the list elements.
In the “Program.cs” file, we create a linked list of integers, add some elements to it, and then display the contents of the linked list.
In a doubly linked list, each node contains two links—the first points to the previous node, and the second points to the next node in the sequence.
The previous pointer of the first node and the next pointer of the last node will point to null, as demonstrated in the image below:
In C#, you can use the LinkedList<T>
class from the System.Collections.Generic
namespace to work with doubly linked lists. Here is an example of how to use the built-in LinkedList<T>
class:
//Doubly linked list
// Create a LinkedList of integers
LinkedList<int> myDoublyList = new LinkedList<int>();
// Add elements to the list
myDoublyList.AddLast(1);
myDoublyList.AddLast(2);
myDoublyList.AddLast(3);
// Display the elements in the list
Console.WriteLine("Doubly LinkedList:");
foreach (int item in myDoublyList)
{
Console.Write(item + " <-> ");
}
Console.WriteLine("null");
In the code above, we create a LinkedList<int>
called myDoublyList
and add elements to it, then the list items are displayed through a for-each loop.
If you run the application you will have the following result in the console:
A circular linked list is a type of linked list in which the last element (node) of the list points back to the first element, forming a closed loop or cycle.
In other words, unlike a traditional linear linked list, where the “next” pointer to the last element is typically set to null, in a circular linked list, the “next” pointer to the last element points to the first element of the list as shown in the image below:
To create a circular linked list, inside the “Models” folder add the class below:
namespace PracticingDataStructures.Models;
public class MyCircularLinkedList<T>
{
private Node<T> head;
private Node<T> tail;
public void Add(T data)
{
Node<T> newNode = new Node<T>(data);
if (head == null)
{
head = newNode;
tail = newNode;
tail.Next = head; // Make it circular
}
else
{
newNode.Next = head;
tail.Next = newNode;
tail = newNode;
}
}
public void Display()
{
if (head == null)
{
Console.WriteLine("Circular Linked List is empty.");
return;
}
Node<T> current = head;
do
{
Console.Write(current.Data + " -> ");
current = current.Next;
} while (current != head);
Console.WriteLine(" (Back to head)");
}
}
And in the Program.cs file add the following code:
// Circular Linked List
var circularLinkedList = new MyCircularLinkedList<int>();
circularLinkedList.Add(1);
circularLinkedList.Add(2);
circularLinkedList.Add(3);
Console.WriteLine("Circular Linked List:");
circularLinkedList.Display();
In the code above we defined a CircularLinkedList<T>
class to represent a circular linked list, where we used the Node<T>
class to represent the list elements.
The CircularLinkedList
class has head and tail properties, which represent the first and last nodes. When adding elements, we make sure to close the loop by pointing the tail Next
back to the head.
The Display
method allows you to display the elements of the circular linked list.
In the Program.cs file, we create a circular linked list of integers, add some elements and display the contents of the list.
So if you run the application, you will have the following result in the console:
A “stack” is an abstract data type that follows the Last-In-First-Out (LIFO) principle and is represented by a collection of elements that has three main operations:
Stacks are commonly used to manage data collections where insertion and removal order is important.
The most recently added item is the first to be removed. Think of it like a stack of dishes: you can only add or remove dishes from the top.
The image below represents the concept of a stack in C#:
Additionally, there is a third operation called Peek (or Top): This operation allows you to view the top element of the stack without removing it.
In the context of C#, we can implement a stack data structure using the System.Collections.Generic.Stack<T>
class, where T
is the type of elements you want to store on the stack. This class provides Push, Pop and Peek methods to perform the stack operations.
In the Program.cs file add the code below:
Stack<int> stack = new Stack<int>();
// Pushing elements onto the stack
stack.Push(1);
stack.Push(2);
stack.Push(3);
// Peeking at the top element without removing it
int topElement = stack.Peek();
Console.WriteLine("Top element: " + topElement);
// Popping elements from the stack
int poppedElement1 = stack.Pop();
int poppedElement2 = stack.Pop();
Console.WriteLine("Popped element 1: " + poppedElement1);
Console.WriteLine("Popped element 2: " + poppedElement2);
// Peek again to see the new top element
topElement = stack.Peek();
Console.WriteLine("Top element after popping: " + topElement);
In the code above, we create a stack of integers using Stack<int>
, then push three integers (1, 2 and 3) onto the stack using the Push method.
Then we use the Peek method to see the top element without removing it. We then use the Pop method to remove and retrieve elements from the stack. After highlighting two elements, we peek again to see the new top element.
If you run the application, you will have the following result in the console:
A queue is a structure that represents a collection of elements, where elements are added to one end (back) and removed from the other end (front).
A queue follows the “first in, first out” (FIFO) principle, which means that the element that has been in the queue the longest is the first to be removed. In other words, it works like a real queue of people waiting in line, where whoever enters the queue first is the first to be served.
A queue has two main operations:
In addition to these fundamental operations, queues often also provide methods for checking whether the queue is empty and for inspecting the element in front without removing it, commonly called “peek” or “front.”
We can use queues in a wide variety of scenarios, including:
In C# we can define queues using the System.Collections.Generic.Queue<T>
class. The code below demonstrates how to implement a queue and how to perform both Enqueue and Dequeue operations.
// Create a new queue of integers
Queue<int> myQueue = new Queue<int>();
// Enqueue elements to the queue
myQueue.Enqueue(1);
myQueue.Enqueue(2);
myQueue.Enqueue(3);
myQueue.Enqueue(4);
myQueue.Enqueue(5);
// Dequeue and process elements in FIFO order
while (myQueue.Count > 0)
{
int item = myQueue.Dequeue();
Console.WriteLine($"Dequeued: {item}");
}
In the code above we declare a Queue<int>
called myQueue
to store integers. Then, we use the Enqueue method to add elements to the end of the queue.
We then use a while loop to repeatedly dequeue elements using the Dequeue method until the queue is empty. The elements removed from the queue are processed in FIFO order.
You can also use other methods provided by the Queue<T>
class, such as Peek to view the front element without removing it and Count to check the number of elements in the queue.
If you run this piece of code you will get the result shown in the image below:
Learning data structures is essential for solving software problems efficiently. In this first part, we check the simplest types of structures in the context of ASP.NET Core where it is not necessary to install any type of external resource as ASP.NET Core has a set of built-in classes that help the developer to deal with structures simplest to the most complex.
In this post we saw four types of data structures: arrays, linked lists, stacks and queues. In the next part, we will implement more complex types of data structures such as trees, heaps and graphs.