Skip to content

binary heap impl #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions Algorithms/Algorithms.Tests/BinaryHeapTests/BinaryHeapTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System.Collections.Generic;
using System.Data;
using Xunit;

namespace Algorithms.Tests
{
public class BinaryHeapTests
{
[Fact]
public void Can_not_remove_root_from_empty_heap()
{
var heap = new BinaryHeap<int>();
Assert.Throws<DataException>(() => heap.RemoveRoot());
}

[Fact]
public void Heap_size_should_increase_after_add()
{
var heap = new BinaryHeap<int>();
heap.Add(42);
Assert.True(heap.Size == 1);
}

[Fact]
public void Heap_size_should_decrease_after_remove()
{
var heap = new BinaryHeap<int>(new List<int>{1, 2, 3});
heap.RemoveRoot();
Assert.True(heap.Size == 2);
}

[Theory]
[InlineData(new int[] {}, 0)]
[InlineData(new [] {1, 2, 3}, 3)]
[InlineData(new [] {42}, 1)]
public void Heap_size_should_be_equal_to_array_length(int[] source, int expectedSize)
{
var heap = new BinaryHeap<int>(source);
Assert.True(heap.Size == expectedSize);
}

[Theory]
[InlineData(new [] {1}, 1)]
[InlineData(new [] {1, 2, 3}, 3, 2, 1)]
[InlineData(new [] {42, 3, 67, -10}, 67, 42)]
public void Root_should_always_be_max_in_MaxHeap(int[] data, params int[] expectedValues)
{
var heap = new BinaryHeap<int>(data, HeapType.MaxHeap);
foreach (var value in expectedValues)
{
Assert.True(heap.RemoveRoot() == value);
}
}

[Theory]
[InlineData(new [] {1}, 1)]
[InlineData(new [] {1, 2, 3}, 1, 2, 3)]
[InlineData(new [] {7, 1, 54, 3, -42}, -42, 1, 3, 7, 54)]
public void Root_should_always_be_min_in_MinHeap(int[] data, params int[] expectedValues)
{
var heap = new BinaryHeap<int>(data, HeapType.MinHeap);
foreach (var value in expectedValues)
{
Assert.True(heap.RemoveRoot() == value);
}
}
}
}
114 changes: 114 additions & 0 deletions Algorithms/Algorithms/BinaryHeap/BinaryHeap.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

namespace Algorithms
{
public class BinaryHeap<T> : IBinaryHeap<T>
where T : IComparable
{
private readonly List<T> _data;
private readonly HeapType _type;

public BinaryHeap(HeapType type = HeapType.MaxHeap)
{
_data = new List<T>();
_type = type;
}

public BinaryHeap(IEnumerable<T> elems, HeapType type = HeapType.MaxHeap)
{
_data = elems.ToList();
_type = type;
BuildHeap(_data);
}

/// <summary>
/// Returns true if elements are ordered, as it's required by HeapType
/// </summary>
private Func<T, T, bool> Cmp
{
get
{
if (_type is HeapType.MaxHeap) return (a, b) => a.CompareTo(b) > 0;
return (a, b) => a.CompareTo(b) <= 0;
}
}

/// <summary>
/// Returns size of the heap
/// </summary>
public int Size => _data.Count;

/// <summary>
/// Adds element to the heap
/// </summary>
public void Add(T item)
{
_data.Add(item);
var current = Size - 1;
var parent = (current - 1) / 2;

while (current > 0 && !Cmp(_data[parent], _data[current]))
{
(_data[parent], _data[current]) = (_data[current], _data[parent]);
current = parent;
parent = (current - 1) / 2;
}
}

/// <summary>
/// Removes and returns root of the heap
/// </summary>
/// <exception cref="DataException">Thrown when trying to remove from empty heap</exception>
public T RemoveRoot()
{
if (Size == 0) throw new DataException("Heap is empty");
var result = _data[0];
_data[0] = _data[Size - 1];
_data.RemoveAt(Size - 1);
Heapify(_data, 0);
return result;
}

/// <summary>
/// Builds heap from an unordered set of data
/// </summary>
private void BuildHeap(IList<T> data)
{
for (var i = Size / 2; i >= 0; --i)
Heapify(data, i);
}

/// <summary>
/// Turns unordered array into heap, with root in data[index]
/// </summary>
/// <param name="data">Array representation of heap</param>
/// <param name="index">Element, that is considered to be root</param>
private void Heapify(IList<T> data, int index)
{
while (true)
{
var l = 2 * index + 1;
var r = 2 * index + 2;
var max = index;
if (l < Size && !Cmp(data[max], data[l])) max = l;
if (r < Size && !Cmp(data[max], data[r])) max = r;
if (max == index) return;

(data[max], data[index]) = (data[index], data[max]);
index = max;
}
}
}

/// <summary>
/// Indicates type of heap: either its root is maximum or minimum
/// </summary>
public enum HeapType
{
MaxHeap,
MinHeap
}
}
11 changes: 11 additions & 0 deletions Algorithms/Algorithms/BinaryHeap/IBinaryHeap.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace Algorithms
{
internal interface IBinaryHeap<T>
where T : IComparable
{
void Add(T item);
T RemoveRoot();
}
}