diff --git a/ZeroLevel.HNSW/Services/BinaryHeap.cs b/ZeroLevel.HNSW/Services/BinaryHeap.cs
new file mode 100644
index 0000000..675f541
--- /dev/null
+++ b/ZeroLevel.HNSW/Services/BinaryHeap.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ZeroLevel.HNSW.Services
+{
+ ///
+ /// Binary heap wrapper around the
+ /// It's a max-heap implementation i.e. the maximum element is always on top.
+ /// But the order of elements can be customized by providing instance.
+ ///
+ /// The type of the items in the source list.
+ public class BinaryHeap
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The buffer to store heap items.
+ public BinaryHeap(IList buffer)
+ : this(buffer, Comparer.Default)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The buffer to store heap items.
+ /// The comparer which defines order of items.
+ public BinaryHeap(IList buffer, IComparer comparer)
+ {
+ if (buffer == null)
+ {
+ throw new ArgumentNullException(nameof(buffer));
+ }
+
+ this.Buffer = buffer;
+ this.Comparer = comparer;
+ for (int i = 1; i < this.Buffer.Count; ++i)
+ {
+ this.SiftUp(i);
+ }
+ }
+
+ ///
+ /// Gets the heap comparer.
+ ///
+ public IComparer Comparer { get; private set; }
+
+ ///
+ /// Gets the buffer of the heap.
+ ///
+ public IList Buffer { get; private set; }
+
+ ///
+ /// Pushes item to the heap.
+ ///
+ /// The item to push.
+ public void Push(T item)
+ {
+ this.Buffer.Add(item);
+ this.SiftUp(this.Buffer.Count - 1);
+ }
+
+ ///
+ /// Pops the item from the heap.
+ ///
+ /// The popped item.
+ public T Pop()
+ {
+ if (this.Buffer.Any())
+ {
+ var result = this.Buffer.First();
+
+ this.Buffer[0] = this.Buffer.Last();
+ this.Buffer.RemoveAt(this.Buffer.Count - 1);
+ this.SiftDown(0);
+
+ return result;
+ }
+
+ throw new InvalidOperationException("Heap is empty");
+ }
+
+ ///
+ /// Restores the heap property starting from i'th position down to the bottom
+ /// given that the downstream items fulfill the rule.
+ ///
+ /// The position of item where heap property is violated.
+ private void SiftDown(int i)
+ {
+ while (i < this.Buffer.Count)
+ {
+ int l = (2 * i) + 1;
+ int r = l + 1;
+ if (l >= this.Buffer.Count)
+ {
+ break;
+ }
+
+ int m = r < this.Buffer.Count && this.Comparer.Compare(this.Buffer[l], this.Buffer[r]) < 0 ? r : l;
+ if (this.Comparer.Compare(this.Buffer[m], this.Buffer[i]) <= 0)
+ {
+ break;
+ }
+
+ this.Swap(i, m);
+ i = m;
+ }
+ }
+
+ ///
+ /// Restores the heap property starting from i'th position up to the head
+ /// given that the upstream items fulfill the rule.
+ ///
+ /// The position of item where heap property is violated.
+ private void SiftUp(int i)
+ {
+ while (i > 0)
+ {
+ int p = (i - 1) / 2;
+ if (this.Comparer.Compare(this.Buffer[i], this.Buffer[p]) <= 0)
+ {
+ break;
+ }
+
+ this.Swap(i, p);
+ i = p;
+ }
+ }
+
+ ///
+ /// Swaps items with the specified indicies.
+ ///
+ /// The first index.
+ /// The second index.
+ private void Swap(int i, int j)
+ {
+ var temp = this.Buffer[i];
+ this.Buffer[i] = this.Buffer[j];
+ this.Buffer[j] = temp;
+ }
+ }
+}