9 minute read

Static and Dynamic Data Structure

Array (Static at Runtime) / List (Dynamic at Runtime)

using System;
using Animals;

// namespace
namespace MyBusiness
{
    // main program
    class Program
    {
        static void Main(string[] args)
        {
            Cat[] catArray = new Cat[3];
            List<Cat> catList = new List<Cat>();

            // Initialize an array
            catArray[0] = new Cat("Nana");
            catArray[1] = new Cat("Coffee");
            catArray[2] = new Cat("Kiwi");

            // Iterate the array to create cats
            catList.Add(new Cat("Nana"));
            catList.Add(new Cat("Coffee"));
            catList.Add(new Cat("Kiwi"));
        }
    }
}
/*
The animal namespace
*/
namespace Animals
{
    public class Cat
    {
        public string Name{ get; set; }

        public Cat()
        {
            this.Name = "unknown";
        }
        public Cat( string name )
        {
            this.Name = name;
        }
    }
}

Collections

If you need to store multiple values in a variable, then you can use a collection. A collection is a data structure in memory that can manage multiple items in different ways. In comparison to an array, collections enable dynamic changes.

System.Collections.Generic Namespace Doc

  • System.Collections: Interfaces and base classes used by collections.
  • System.Collections.Generic: Introduced in C# 2.0 with .NET Framework 2.0. These collections allow you to specify the type you want to store using a generic type parameter (which is safer, faster, and more efficient).
  • System.Collections.Concurrent
  • System.Collections.Immutable

Common Features of All Collections

All collections implement the ICollection interface; this means that they must have a Count property to tell you how many objects are in them.

int listCount = catList.Count;
Console.WriteLine($"The total elements in the list is {listCount}.");

All collections implement the IEnumerable interface, which means that they must have a GetEnumerator method that returns an object that implements IEnumerator; this means that the returned object must have a MoveNext method and a Current property so that they can be iterated using the foreach statement.

// The foreach statement
foreach (Cat cat in catList)
{
    // do something with each cat
    Console.WriteLine($"The name of the cat is {cat.Name}.");
}

List Class Doc

Represents a strongly typed list of objects that can be accessed by index. Provides methods to search, sort, and manipulate lists. Lists are a good choice when you want to manually control the order of items in a collection.

Non-generic type: ArrayList Doc

Index Item
0 Austria
1 Taiwan
2 Austria
3 Germany
using System;
using Animals;

// namespace
namespace MyBusiness
{
    // main program
    class Program
    {
        static void Main(string[] args)
        {
            List<string> countryList = new List<string>();
            countryList.Add("Austria");
            countryList.Add("Taiwan");
            countryList.Add("Austria");
            countryList.Add("Germany");

            // Print the current list
            foreach (string item in countryList)
            {
                Console.WriteLine(item);
            }

            // Contain method
            Console.WriteLine(countryList.Contains("Taiwan"));

            // Insert method
            countryList.Insert(2, "Japan");

            // Print the current list
            foreach (string item in countryList)
            {
                Console.WriteLine(item);
            }

            // Insert method
            countryList.Remove("Japan");
            // countryList.RemoveAt(2);

            // Print the current list
            foreach (string item in countryList)
            {
                Console.WriteLine(item);
            }
        }
    }
}
$ Austria
$ Taiwan
$ Austria
$ Germany

$ True

$ Austria
$ Taiwan
$ Japan
$ Austria
$ Germany

$ Austria
$ Taiwan
$ Austria
$ Germany

Dictionary<TKey, TValue> Class Doc

Non-generic type: HashTable Doc

using System;
using System.Collections.Generic;

// namespace
namespace MyBusiness
{
    // main program
    class Program
    {
        static void Main(string[] args)
        {
            // Create a new dictionary of strings, with string keys.
            Dictionary<int, string> numberNames = new Dictionary<int, string>();

            /*
            Add
            */
            // Adding a key/value using the Add() method
            numberNames.Add(1, "One");
            numberNames.Add(2, "Two");
            numberNames.Add(3, "Three");
            // Runtime error: An item with the same key has already been added.
            // numberNames.Add(3, "Three");

            foreach (KeyValuePair<int, string> kvp in numberNames)
                Console.WriteLine("Key: {0}, Value: {1}", kvp.Key, kvp.Value);

            //creating a dictionary using collection-initializer syntax
            Dictionary<string, string> cities = new Dictionary<string, string>(){
                {"UK", "London, Manchester, Birmingham"},
                {"USA", "Chicago, New York, Washington"},
                {"India", "Mumbai, New Delhi, Pune"}
            };

            // foreach (KeyValuePair<string, string> kvp in cities)
            foreach (var kvp in cities)
            {
                Console.WriteLine("Key: {0}, Value: {1}", kvp.Key, kvp.Value);
            }

            /*
            Access elements
            */
            //prints value of UK key
            Console.WriteLine(cities["UK"]);
            // run-time exception: Key does not exist      
            // Console.WriteLine(cities["France"]);       
            //use ContainsKey() to check for an unknown key
            if (cities.ContainsKey("France"))
            {
                Console.WriteLine(cities["France"]);
            }
            else
            {
                Console.WriteLine("The key \"France\" does not exist!");
            }

            //use ElementAt() to retrieve key-value pair using index
            for (int i = 0; i < cities.Count; i++)
            {
                Console.WriteLine("Key: {0}, Value: {1}",
                                                        cities.ElementAt(i).Key,
                                                        cities.ElementAt(i).Value);
            }

            /*
            Update Dictionary
            */
            if (cities.ContainsKey("USA"))
            {
                cities["USA"] = "Seattle";
            }
            foreach (var kvp in cities)
            {
                Console.WriteLine("Key: {0}, Value: {1}", kvp.Key, kvp.Value);
            }
        }
    }
}
$ Key: 1, Value: One
$ Key: 2, Value: Two
$ Key: 3, Value: Three

$ Key: UK, Value: London, Manchester, Birmingham
$ Key: USA, Value: Chicago, New York, Washington
$ Key: India, Value: Mumbai, New Delhi, Pune

$ London, Manchester, Birmingham
$ The key "France" does not exist!

$ Key: UK, Value: London, Manchester, Birmingham
$ Key: USA, Value: Chicago, New York, Washington
$ Key: India, Value: Mumbai, New Delhi, Pune

$ Key: UK, Value: London, Manchester, Birmingham
$ Key: USA, Value: Seattle
$ Key: India, Value: Mumbai, New Delhi, Pune

HashSet Class Doc

using System;
using System.Collections.Generic;

// namespace
namespace MyBusiness
{
    // main program
    class Program
    {
        static void Main(string[] args)
        {
            // Create a new dictionary of strings, with string keys.
            HashSet<int> evenNumbers = new HashSet<int>();
            HashSet<int> oddNumbers = new HashSet<int>();

            /*
            Add
            */
            // Adding a key/value using the Add() method
            for (int i = 0; i < 5; i++)
            {
                // Populate numbers with just even numbers.
                evenNumbers.Add(i * 2);

                // Populate oddNumbers with just odd numbers.
                oddNumbers.Add((i * 2) + 1);
            }

            /*
            Count method
            */
            Console.Write("evenNumbers contains {0} elements: ", evenNumbers.Count);
            DisplaySet(evenNumbers);

            Console.Write("oddNumbers contains {0} elements: ", oddNumbers.Count);
            DisplaySet(oddNumbers);

            /*
            Set operation union
            */
            // Create a new HashSet populated with even numbers.
            HashSet<int> numbers = new HashSet<int>(evenNumbers);
            Console.WriteLine("numbers UnionWith oddNumbers...");
            numbers.UnionWith(oddNumbers);
            // numbers.IntersectWith(oddNumbers);

            Console.Write("numbers contains {0} elements: ", numbers.Count);
            DisplaySet(numbers);

            // Local function
            void DisplaySet(HashSet<int> collection)
            {
                Console.Write("{");
                foreach (int i in collection)
                {
                    Console.Write(" {0}", i);
                }
                Console.WriteLine(" }");
            }
        }
    }
}
$ evenNumbers contains 5 elements: { 0 2 4 6 8 }
$ oddNumbers contains 5 elements: { 1 3 5 7 9 }
$ numbers UnionWith oddNumbers...
$ numbers contains 10 elements: { 0 2 4 6 8 1 3 5 7 9 }

SortedList<TKey,TValue> Class Doc

using System;
using System.Collections.Generic;

// namespace
namespace MyBusiness
{
    // main program
    class Program
    {
        static void Main(string[] args)
        {
            //SortedList of int keys, string values
            SortedList<int, string> numberNames = new SortedList<int, string>();

            //using collection-initializer syntax
            // SortedList<int, string> numberNames = new SortedList<int, string>()
            //                 {
            //                     {3, "Three"},
            //                     {1, "One"},
            //                     {2, "Two"},
            //                 };

            /*
            Add
            */
            numberNames.Add(3, "Three");
            numberNames.Add(1, "One");
            numberNames.Add(2, "Two");
            numberNames.Add(4, null);
            numberNames.Add(10, "Ten");
            numberNames.Add(5, "Five");

            //The following will throw exceptions
            //Compile-time error: key must be int type
            // numberNames.Add("Three", 3);
            //Run-time exception: duplicate key
            // numberNames.Add(1, "One");
            //Run-time exception: key cannot be null
            // numberNames.Add(null, "Five");

            /*
            Access
            */
            foreach (KeyValuePair<int, string> kvp in numberNames)
            {
                Console.WriteLine("key: {0}, value: {1}", kvp.Key, kvp.Value);
            }
            Console.WriteLine(numberNames[2]);
            // for (int i = 0; i < numberNames.Count; i++)
            // {
            //     Console.WriteLine("key: {0}, value: {1}", numberNames.Keys[i], numberNames.Values[i]);
            // }

            /*
            Remove
            */
            numberNames.Remove(1);
            numberNames.Remove(10);

            //removes key-value pair from index 0
            numberNames.RemoveAt(0);
            //run-time exception: ArgumentOutOfRangeException
            // numberNames.RemoveAt(10);

            foreach (KeyValuePair<int, string> kvp in numberNames)
            {
                Console.WriteLine("key: {0}, value: {1}", kvp.Key, kvp.Value);
            }
        }
    }
}
$ key: 1, value: One
$ key: 2, value: Two
$ key: 3, value: Three
$ key: 4, value:
$ key: 5, value: Five
$ key: 10, value: Ten
$ Two
$ key: 3, value: Three
$ key: 4, value:
$ key: 5, value: Five

SortedDictionary<TKey, TValue> Doc

using System;
using System.Collections.Generic;

// namespace
namespace MyBusiness
{
    // main program
    class Program
    {
        static void Main(string[] args)
        {
            // SortedDictionary of int keys, string values
            SortedDictionary<int, string> numberNames = new SortedDictionary<int, string>();

            // Using collection-initializer syntax
            // SortedDictionary<int, string> numberNames = new SortedDictionary<int, string>()
            //                 {
            //                     {3, "Three"},
            //                     {1, "One"},
            //                     {2, "Two"},
            //                 };

            /*
            Add
            */
            numberNames.Add(3, "Three");
            numberNames.Add(1, "One");
            numberNames.Add(2, "Two");
            numberNames.Add(4, null);
            numberNames.Add(10, "Ten");
            numberNames.Add(5, "Five");

            //The following will throw exceptions
            //Compile-time error: key must be int type
            // numberNames.Add("Three", 3);
            //Run-time exception: duplicate key
            // numberNames.Add(1, "One");
            //Run-time exception: key cannot be null
            // numberNames.Add(null, "Five");

            /*
            Access
            */
            foreach (KeyValuePair<int, string> kvp in numberNames)
            {
                Console.WriteLine("key: {0}, value: {1}", kvp.Key, kvp.Value);
            }
            Console.WriteLine(numberNames[2]);
            // Compile error!
            // for (int i = 0; i < numberNames.Count; i++)
            // {
            //     Console.WriteLine("key: {0}, value: {1}", numberNames.Keys[i], numberNames.Values[i]);
            // }

            /*
            Remove
            */
            numberNames.Remove(1);
            numberNames.Remove(10);

            // There is no RemoveAt method
            // numberNames.RemoveAt(0);

            foreach (KeyValuePair<int, string> kvp in numberNames)
            {
                Console.WriteLine("key: {0}, value: {1}", kvp.Key, kvp.Value);
            }
        }
    }
}
$ key: 1, value: One
$ key: 2, value: Two
$ key: 3, value: Three
$ key: 4, value:
$ key: 5, value: Five
$ key: 10, value: Ten
$ Two
$ key: 2, value: Two
$ key: 3, value: Three
$ key: 4, value:
$ key: 5, value: Five

SortedSet Doc

using System;
using System.Collections.Generic;

// namespace
namespace MyBusiness
{
    // main program
    class Program
    {
        static void Main(string[] args)
        {
            // SortedSet of string values
            SortedSet<string> sortedSetDemo = new SortedSet<string>();

            //using collection-initializer syntax
            // SortedSet<string> sortedSetDemo = new SortedSet<string>()
            //                 {
            //                     {"Mumbai"},
            //                     {"Surat"},
            //                     {"Vadodara"},
            //                     {"Dabhoi"},
            //                     {"Pune"},
            //                 };

            /*
            Add
            */
            sortedSetDemo.Add("Mumbai");
            sortedSetDemo.Add("Surat");
            sortedSetDemo.Add("Vadodara");
            sortedSetDemo.Add("Dabhoi");
            sortedSetDemo.Add("Pune");

            /*
            Access
            */
            foreach (var item in sortedSetDemo)
            {
                Console.WriteLine(item);
            }

            /*
            Remove
            */
            sortedSetDemo.Remove("Surat");

            foreach (var item in sortedSetDemo)
            {
                Console.WriteLine(item);
            }

            // Clean up the sortedSet
            sortedSetDemo.Clear();

            foreach (var item in sortedSetDemo)
            {
                Console.WriteLine(item);
            }
        }
    }
}
$ Dabhoi
$ Mumbai
$ Pune
$ Surat
$ Vadodara

$ Dabhoi
$ Mumbai
$ Pune
$ Vadodara

Queue Doc

A queue is a collection of entities that are maintained in a sequence and can be modified by the addition of entities at one end of the sequence and the removal of entities from the other end of the sequence.

  • First-In First-Out
using System;
using System.Collections.Generic;

// namespace
namespace MyBusiness
{
    // main program
    class Program
    {
        static void Main(string[] args)
        {
            //Queue of int values
            Queue<int> intQueue = new Queue<int>();

            /*
            Add
            */
            intQueue.Enqueue(1);
            intQueue.Enqueue(2);
            intQueue.Enqueue(3);
            intQueue.Enqueue(4);

            /*
            Access
            */
            foreach (var id in intQueue)
            {
                Console.Write(id);
            }
            Console.WriteLine("");

            // Peek(): Return the first item from the queue without removing it.
            Console.WriteLine(intQueue.Peek());

            /*
            Remove
            */
            while (intQueue.Count > 0)
            {
                Console.WriteLine(intQueue.Dequeue());
            }
        }
    }
}
$ 1234
$ 1
$ 1
$ 2
$ 3
$ 4

Stack Doc

  • First-In Last-Out

A Stack is a linear data structure that follows the LIFO (Last-In-First-Out) principle. Stack has one end, whereas the Queue has two ends (front and rear). It contains only one pointer top pointer pointing to the topmost element of the stack.

using System;
using System.Collections.Generic;

// namespace
namespace MyBusiness
{
    // main program
    class Program
    {
        static void Main(string[] args)
        {
            //Stack of int values
            Stack<int> intStack = new Stack<int>();

            /*
            Add
            */
            intStack.Push(1);
            intStack.Push(2);
            intStack.Push(3);
            intStack.Push(4);

            /*
            Access
            */
            foreach (var id in intStack)
            {
                Console.Write(id);
            }
            Console.WriteLine("");

            // Peek(): Return the first item from the queue without removing it.
            Console.WriteLine(intStack.Peek());

            /*
            Remove
            */
            while (intStack.Count > 0)
            {
                Console.WriteLine(intStack.Pop());
            }
        }
    }
}
$ 4321
$ 4
$ 4
$ 3
$ 2
$ 1

LinkedList Doc

using System;
using System.Collections.Generic;

// namespace
namespace MyBusiness
{
    // main program
    class Program
    {
        static void Main(string[] args)
        {
            // LinkedList of int values
            LinkedList<int> list = new LinkedList<int>();

            /*
            Add
            */
            list.AddLast(1);
            list.AddLast(2);
            LinkedListNode<int> middle = list.AddLast(3);
            list.AddLast(4);
            list.AddLast(5);

            list.AddAfter(middle, 32);
            list.AddAfter(middle, 31);

            /*
            Access
            */
            foreach (int i in list)
            {
                Console.Write("{0}, ", i);
            }
            Console.WriteLine("");
            // Console.WriteLine(middle.Value);
            // Console.WriteLine(middle.Next.Value);

            /*
            Remove
            */
            list.Remove(middle);

            foreach (int i in list)
            {
                Console.Write("{0}, ", i);
            }
            Console.WriteLine("");
        }
    }
}
$ 1, 2, 3, 31, 32, 4, 5,
$ 1, 2, 31, 32, 4, 5,

Selected Theory

Complexity Theory

Sequential/Linear Search vs. Binary Search Doc

Big O Notation Doc

Big O notation is a mathematical notation that describes the limiting behavior of a function when the argument tends towards a particular value or infinity.

SortedList vs. SortedDictionary

The SortedDictionary<TKey, TValue> generic class is a binary search tree with O(log n) retrieval, where n is the number of elements in the dictionary. In this, it is similar to the SortedList<TKey, TValue> generic class. The two classes have similar object models, and both have O(log n) retrieval. Where the two classes differ is in memory use and speed of insertion and removal:

  • SortedList<TKey, TValue> uses less memory than SortedDictionary<TKey, TValue>.
  • SortedDictionary<TKey, TValue> has faster insertion and removal operations for unsorted data, O(log n) as opposed to O(n) for SortedList<TKey, TValue>.
  • If the list is populated all at once from sorted data, SortedList<TKey, TValue> is faster than SortedDictionary<TKey, TValue>.
Collection Indexed Keyed Value Addition Removal Memory
  lookup lookup lookup      
SortedList O(1) O(log n) O(n) O(n) O(n) Lesser
SortedDictionary O(n) O(log n) O(n) O(log n) O(log n) Greater

Updated: