Lesson 6. Types Equality and Identity. Collections. Programming in C# Lesson 6. Types Equality and Identity. Collections.
Comparing Objects
Equality vs Identity
Object.Equals
Check for Identity
Check for Equality The method checks objects for identity, then for nulls and then relies on the corresponding instance Equals method implementation.
Operator == For reference types by default checks for identity For value types must be overridden
Overriding Equals for value types
Overriding Equals for reference types
IEquatable<T> Interface
Overriding Operator ==
GetHashCode Method Always override GetHashCode when overriding Equals!
Comparing Objects
Comparing Objects: IComparable, IComparable<T>
Comparing Objects: IComparer, IComparer<T>
Comparing Strings
Comparing Strings
Collections List Stack Queue Dictionary (Hash Table) Tree
Lists A data structure that contains a sequence of elements Unlike arrays lists may have variable size Elements are arranged linearly There are two main implementations of lists: Using resizable arrays (List<T>) Linked Lists (LinkedList<T>)
Implementing a list using an array
Implementing a linked list
Stacks
Stacks LIFO (Last In First Out) data structure Elements inserted (via ‘push’ operation) at the top of the stack Elements removed (via ‘pop’ operation) from the top of the stack Time of these operations is O(1) Stacks can be implemented in two main ways: Static (using an array) Dynamic (linked implementation) Represented in .NET by class Stack<T>
Static (array based) Stack implementation
Dynamic (pointer based) Stack implementation
Queues
Queues FIFO (First In First Out) data structure Elements inserted (via ‘enqueue’ operation) at the tail of the queue Elements removed (via ‘dequeue’ operation) from the head of the queue Time of these operations is O(1) Queues can be implemented in two main ways: Static (using an array) Dynamic (linked implementation) Represented in .NET by class Queue<T>
IEnumerable, IEnumerable<T>, IEnumerator, IEnumerator<T> interfaces Ienumerable, IEnumerable<T> – Expose an enumerator, which supports a simple iteration over a collection of elements. Ienumerator, IEnumerator<T> – Support a simple iteration over a collection of elements These are useful when you need to create custom collections or types that need to be enumerated.
Dictionaries (Hash Tables)
Dictionaries Data structure that maps keys to values AKA ‘maps’ and ‘associative arrays’ Keys are unique Supports three main operations: Add FindByKey Remove Average time of all operations is O(1) Can be implemented as array, list, hash table, balanced tree Represented in .NET by classe Dictionary<T, V>
Hash Table: Main Idea
Hashing h: k -> 0..m-1 T h(k) Hashing is a process of mapping a key to a position in a table: h: k -> 0..m-1 0 1 2 3 4 5 … m-1 … … … … … … … … T h(k)
Hashing Functions Perfect hashing function provides one-to-one mapping of each key to a slot in the range [0..m-1] Finding a perfect hashing function is in most cases impossible A good hash function: Is easy to compute Distributes data evenly Should minimize collisions
h(k1) = h(k2) for k1 <> k2 Collisions A collision is the situation when different keys have the same hash value: h(k1) = h(k2) for k1 <> k2 There are several collision resolution strategies: Chaining Open addressing Re-hashing and more...
Collisions resolution via chaining
Trees
Trees A hierarchical data structure A tree usually consists of a root and sub-trees of children, represented as a set of linked nodes Main operations over a tree are: Search Insert Delete In case of balanced trees the average time of all the operations is O(log N) There are many types of trees: Binary trees, BS trees, self-balanced trees (Red-Black tree, 2-3 tree, etc.) Represented in .NET by class SortedDictionary<T, V>
Unbalanced Tree vs Balanced Tree Unbalanced Balanced Height of a balanced tree is log2N
Implementing a Tree
Implementing a Tree
Tree Traversal Tree traversal is a process of visiting each node in a tree exactly once and in particular order There are two main types of traversal: Depth-first search (usually implemented via recursion or using a stack) – can be done “pre-order”, “in-order” or “post-order”. Breadth-first search (usually implemented using a queue)
Depth-first search vs Breadth-first search
Binary Tree Binary Tree is a tree in which each node can have at most two children usually referred as the left and the right
Implementing Binary Tree
Binary Search Tree Binary Search Tree is a ordered binary tree in which for each node X the left sub-tree has values <= X and the right sub-tree has values > X