About

This is an implementation of Binary Heap Tree using generics and arrays as backend storage in C#.

Code

using System;
 
namespace Heap
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var heap = new MaxHeap<int>(new[] {9, 10, 2, 7, 8, 9, 20, 21});
 
            heap.PrintTree();
            Console.ReadKey();
        }
 
        ///////////////////////////////////////////////////////////////////////////
        //  Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3      //
        //  Please see: http://www.gnu.org/licenses/gpl.html for legal details,  //
        //  rights of fair usage, the disclaimer and warranty conditions.        //
        ///////////////////////////////////////////////////////////////////////////
        /// <summary>
        ///     A max-heap implementation.
        /// </summary>
        private class MaxHeap<T> where T : IComparable
        {
            private readonly int size;
            private readonly T[] store;
            private int count;
 
            /// <summary>
            ///     Initializes a store of a given size.
            /// </summary>
            /// <param name="size"></param>
            public MaxHeap(int size)
            {
                store = new T[size];
                this.size = size;
            }
 
            /// <summary>
            ///     Initializes a store from an array of values.
            /// </summary>
            /// <param name="values">the values to add to the store</param>
            /// <remarks>Uses Floyd's algorithm to heapify.</remarks>
            public MaxHeap(T[] values)
            {
                store = values;
                size = values.Length;
                count = values.Length;
                for (var i = values.Length - 1; i > -1; --i)
                {
                    TrickleDown(i);
                }
            }
 
            /// <summary>
            ///     Adds an item to the store.
            /// </summary>
            /// <param name="item">the item to add</param>
            public void Add(T item)
            {
                if (count + 1 > size)
                    throw new ArgumentOutOfRangeException();
 
                store[count] = item;
                TrickleUp(count);
                ++count;
            }
 
            /// <summary>
            ///     Extracts the root node.
            /// </summary>
            /// <returns>the root node</returns>
            public T Extract()
            {
                if (count == 0)
                    throw new ArgumentOutOfRangeException();
 
                var tmp = store[0];
                store[0] = store[count - 1];
                --count;
                TrickleDown(0);
                return tmp;
            }
 
            /// <summary>
            ///     Internal function to swap to items on the store.
            /// </summary>
            /// <param name="u">first index</param>
            /// <param name="v">second index</param>
            private void HeapSwap(int u, int v)
            {
                var t = store[u];
                store[u] = store[v];
                store[v] = t;
            }
 
            /// <summary>
            ///     Determines if the store is empty.
            /// </summary>
            /// <returns>true in case the store is empty</returns>
            public bool IsEmpty()
            {
                return count == 0;
            }
 
            /// <summary>
            ///     Trickles up a node at a given index.
            /// </summary>
            /// <param name="i">the index of the node</param>
            private void TrickleUp(int i)
            {
                if (i < 0) return;
 
                var p = (i - 1)/2;
 
                if (store[i].CompareTo(store[p]) <= 0) return;
 
                HeapSwap(p, i);
                TrickleUp(p);
            }
 
            /// <summary>
            ///     Trickles down a node at a given index.
            /// </summary>
            /// <param name="i">the index of the node</param>
            private void TrickleDown(int i)
            {
                var l = 2*i + 1;
                var r = 2*i + 2;
                var c = i;
 
                if (l < count && store[l].CompareTo(store[c]) > 0)
                    c = l;
                if (r < count && store[r].CompareTo(store[c]) > 0)
                    c = r;
 
                if (c == i) return;
 
                HeapSwap(c, i);
                TrickleDown(c);
            }
 
            /// <summary>
            ///     Calculates the depth of the store.
            /// </summary>
            /// <param name="i">the index from where to start counting</param>
            /// <returns>the depth of the store</returns>
            public int Depth(int i)
            {
                if (i >= count)
                    return 0;
 
                var l = Depth(2*i + 1);
                var r = Depth(2*i + 2);
 
                return l > r ? l + 1 : r + 1;
            }
 
            /// <summary>
            ///     Prints out the tree starting from an index and a level.
            /// </summary>
            /// <param name="i">the starting node</param>
            /// <param name="level">the level at which to start</param>
            private void PrintTree(int i, int level)
            {
                if (i >= count)
                    return;
 
                var l = 2*i + 1;
                var r = 2*i + 2;
 
                if (l < count)
                    PrintTree(l, level + 1);
 
                for (var t = level; t > 0; --t)
                {
                    Console.Write("\t");
                }
 
                Console.WriteLine(store[i]);
 
                if (r < count)
                    PrintTree(r, level + 1);
            }
 
            /// <summary>
            ///     Print out the entire tree.
            /// </summary>
            public void PrintTree()
            {
                PrintTree(0, 0);
            }
        }
    }
}