Welcome to the practical segment of our C# programming journey! Today, we'll apply the knowledge from past lessons to solve two practice problems using advanced C# data structures: queues
, deques
, and sorted dictionaries
with custom class keys.
Consider an event-driven system, like a restaurant. Orders arrive, and they must be handled in the order they were received, following the First In, First Out (FIFO) principle. This principle makes it a perfect scenario for a queue
or deque
implementation in C#.
C#1using System; 2using System.Collections.Generic; 3 4class Queue 5{ 6 private LinkedList<string> buffer; 7 8 public Queue() 9 { 10 // Initializing an empty queue 11 buffer = new LinkedList<string>(); 12 } 13 14 // Adding (enqueueing) an item to the queue 15 public void Enqueue(string val) 16 { 17 buffer.AddLast(val); 18 } 19 20 // Removing (dequeuing) an item from the queue 21 public string Dequeue() 22 { 23 if (IsEmpty()) 24 { 25 throw new InvalidOperationException("Queue is empty"); 26 } 27 string value = buffer.First.Value; 28 buffer.RemoveFirst(); 29 return value; 30 } 31 32 // Checking if the queue is empty 33 public bool IsEmpty() 34 { 35 return buffer.Count == 0; 36 } 37 38 // Checking the size (number of items) in the queue 39 public int Size() 40 { 41 return buffer.Count; 42 } 43 44 public static void Main(string[] args) 45 { 46 Queue restaurantQueue = new Queue(); 47 48 restaurantQueue.Enqueue("Order 1"); 49 restaurantQueue.Enqueue("Order 2"); 50 51 Console.WriteLine("Dequeued: " + restaurantQueue.Dequeue()); 52 Console.WriteLine("Dequeued: " + restaurantQueue.Dequeue()); 53 } 54}
This code demonstrates the creation and operation of a Queue
class, which leverages LinkedList<T>
to efficiently implement a queue. The Queue
class includes methods to Enqueue
(add) an item, Dequeue
(remove) an item, check if the queue is empty, and return the queue's size. Enqueue operations add an item to the end of the deque (simulating the arrival of a new order), while dequeue operations remove an item from the front (simulating the serving of an order), maintaining the First In, First Out (FIFO) principle.
We've mimicked a real-world system by implementing a queue
using C#'s LinkedList<T>
. The enqueuing of an item adheres to the FIFO principle, similar to the action of receiving a new order at the restaurant. The dequeuing serves an order, reflecting the preparation and delivery of the order.
For the second problem, envision a leaderboard for a video game. Players with their scores can be represented as objects of a custom class, then stored in a sorted dictionary
for easy and efficient access.
C#1using System; 2using System.Collections.Generic; 3 4class Player : IComparable<Player> 5{ 6 public string Name { get; } 7 public int Score { get; } 8 9 public Player(string name, int score) 10 { 11 Name = name; 12 Score = score; 13 } 14 15 public int CompareTo(Player other) 16 { 17 int scoreComparison = Score.CompareTo(other.Score); 18 if (scoreComparison == 0) 19 { 20 return Name.CompareTo(other.Name); 21 } 22 return scoreComparison; 23 } 24 25 public override bool Equals(object obj) 26 { 27 if (this == obj) return true; 28 if (obj == null || GetType() != obj.GetType()) return false; 29 Player player = (Player)obj; 30 return Score == player.Score && Name == player.Name; 31 } 32 33 public override int GetHashCode() 34 { 35 unchecked 36 { 37 int hash = 17; 38 hash = hash * 23 + Name.GetHashCode(); 39 hash = hash * 23 + Score.GetHashCode(); 40 return hash; 41 } 42 } 43 44 public override string ToString() 45 { 46 return $"({Name}, {Score})"; 47 } 48 49 public static void Main(string[] args) 50 { 51 SortedDictionary<Player, int> scores = new SortedDictionary<Player, int>(); 52 53 Player player1 = new Player("John", 900); 54 Player player2 = new Player("Doe", 1000); 55 56 // Adding players to the SortedDictionary 57 scores[player1] = player1.Score; 58 scores[player2] = player2.Score; 59 60 // Print SortedDictionary 61 foreach (var entry in scores) 62 { 63 Console.WriteLine(entry.Key); // e.g., (John, 900) 64 } 65 } 66}
This code snippet introduces a Player
class for representing players in a video game, implementing the IComparable<Player>
interface to allow sorting by score (primary) and name (secondary). Instances of this class are then used as keys in a SortedDictionary<Player, int>
, ensuring that players are stored in a manner that is sorted first by their scores and then by their names if scores are equal. This is essential for functionalities like leaderboards, where players need to be ranked efficiently according to their performance.
In our leaderboard system, we used a Player
custom class with comparator methods for sorting. We stored instances of Player
in a sorted dictionary with their corresponding scores. The SortedDictionary<Player, int>
allows us to access player scores in a sorted order efficiently, a common requirement in a competitive gaming system.
We've successfully employed C#'s built-in data structures — queues
, deques
, and sorted dictionaries
— to solve real-world problems. This hands-on approach enables us to better understand these concepts. More exercises to cement your understanding are coming up next. Happy coding!