Skip to content

Commit 742d9fc

Browse files
authored
Merge pull request #16 from madetara/binary_heap
binary heap impl
2 parents 9a6b6ef + d04a975 commit 742d9fc

File tree

3 files changed

+193
-0
lines changed

3 files changed

+193
-0
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using System.Collections.Generic;
2+
using System.Data;
3+
using Xunit;
4+
5+
namespace Algorithms.Tests
6+
{
7+
public class BinaryHeapTests
8+
{
9+
[Fact]
10+
public void Can_not_remove_root_from_empty_heap()
11+
{
12+
var heap = new BinaryHeap<int>();
13+
Assert.Throws<DataException>(() => heap.RemoveRoot());
14+
}
15+
16+
[Fact]
17+
public void Heap_size_should_increase_after_add()
18+
{
19+
var heap = new BinaryHeap<int>();
20+
heap.Add(42);
21+
Assert.True(heap.Size == 1);
22+
}
23+
24+
[Fact]
25+
public void Heap_size_should_decrease_after_remove()
26+
{
27+
var heap = new BinaryHeap<int>(new List<int>{1, 2, 3});
28+
heap.RemoveRoot();
29+
Assert.True(heap.Size == 2);
30+
}
31+
32+
[Theory]
33+
[InlineData(new int[] {}, 0)]
34+
[InlineData(new [] {1, 2, 3}, 3)]
35+
[InlineData(new [] {42}, 1)]
36+
public void Heap_size_should_be_equal_to_array_length(int[] source, int expectedSize)
37+
{
38+
var heap = new BinaryHeap<int>(source);
39+
Assert.True(heap.Size == expectedSize);
40+
}
41+
42+
[Theory]
43+
[InlineData(new [] {1}, 1)]
44+
[InlineData(new [] {1, 2, 3}, 3, 2, 1)]
45+
[InlineData(new [] {42, 3, 67, -10}, 67, 42)]
46+
public void Root_should_always_be_max_in_MaxHeap(int[] data, params int[] expectedValues)
47+
{
48+
var heap = new BinaryHeap<int>(data, HeapType.MaxHeap);
49+
foreach (var value in expectedValues)
50+
{
51+
Assert.True(heap.RemoveRoot() == value);
52+
}
53+
}
54+
55+
[Theory]
56+
[InlineData(new [] {1}, 1)]
57+
[InlineData(new [] {1, 2, 3}, 1, 2, 3)]
58+
[InlineData(new [] {7, 1, 54, 3, -42}, -42, 1, 3, 7, 54)]
59+
public void Root_should_always_be_min_in_MinHeap(int[] data, params int[] expectedValues)
60+
{
61+
var heap = new BinaryHeap<int>(data, HeapType.MinHeap);
62+
foreach (var value in expectedValues)
63+
{
64+
Assert.True(heap.RemoveRoot() == value);
65+
}
66+
}
67+
}
68+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Data;
4+
using System.Linq;
5+
6+
namespace Algorithms
7+
{
8+
public class BinaryHeap<T> : IBinaryHeap<T>
9+
where T : IComparable
10+
{
11+
private readonly List<T> _data;
12+
private readonly HeapType _type;
13+
14+
public BinaryHeap(HeapType type = HeapType.MaxHeap)
15+
{
16+
_data = new List<T>();
17+
_type = type;
18+
}
19+
20+
public BinaryHeap(IEnumerable<T> elems, HeapType type = HeapType.MaxHeap)
21+
{
22+
_data = elems.ToList();
23+
_type = type;
24+
BuildHeap(_data);
25+
}
26+
27+
/// <summary>
28+
/// Returns true if elements are ordered, as it's required by HeapType
29+
/// </summary>
30+
private Func<T, T, bool> Cmp
31+
{
32+
get
33+
{
34+
if (_type is HeapType.MaxHeap) return (a, b) => a.CompareTo(b) > 0;
35+
return (a, b) => a.CompareTo(b) <= 0;
36+
}
37+
}
38+
39+
/// <summary>
40+
/// Returns size of the heap
41+
/// </summary>
42+
public int Size => _data.Count;
43+
44+
/// <summary>
45+
/// Adds element to the heap
46+
/// </summary>
47+
public void Add(T item)
48+
{
49+
_data.Add(item);
50+
var current = Size - 1;
51+
var parent = (current - 1) / 2;
52+
53+
while (current > 0 && !Cmp(_data[parent], _data[current]))
54+
{
55+
(_data[parent], _data[current]) = (_data[current], _data[parent]);
56+
current = parent;
57+
parent = (current - 1) / 2;
58+
}
59+
}
60+
61+
/// <summary>
62+
/// Removes and returns root of the heap
63+
/// </summary>
64+
/// <exception cref="DataException">Thrown when trying to remove from empty heap</exception>
65+
public T RemoveRoot()
66+
{
67+
if (Size == 0) throw new DataException("Heap is empty");
68+
var result = _data[0];
69+
_data[0] = _data[Size - 1];
70+
_data.RemoveAt(Size - 1);
71+
Heapify(_data, 0);
72+
return result;
73+
}
74+
75+
/// <summary>
76+
/// Builds heap from an unordered set of data
77+
/// </summary>
78+
private void BuildHeap(IList<T> data)
79+
{
80+
for (var i = Size / 2; i >= 0; --i)
81+
Heapify(data, i);
82+
}
83+
84+
/// <summary>
85+
/// Turns unordered array into heap, with root in data[index]
86+
/// </summary>
87+
/// <param name="data">Array representation of heap</param>
88+
/// <param name="index">Element, that is considered to be root</param>
89+
private void Heapify(IList<T> data, int index)
90+
{
91+
while (true)
92+
{
93+
var l = 2 * index + 1;
94+
var r = 2 * index + 2;
95+
var max = index;
96+
if (l < Size && !Cmp(data[max], data[l])) max = l;
97+
if (r < Size && !Cmp(data[max], data[r])) max = r;
98+
if (max == index) return;
99+
100+
(data[max], data[index]) = (data[index], data[max]);
101+
index = max;
102+
}
103+
}
104+
}
105+
106+
/// <summary>
107+
/// Indicates type of heap: either its root is maximum or minimum
108+
/// </summary>
109+
public enum HeapType
110+
{
111+
MaxHeap,
112+
MinHeap
113+
}
114+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
3+
namespace Algorithms
4+
{
5+
internal interface IBinaryHeap<T>
6+
where T : IComparable
7+
{
8+
void Add(T item);
9+
T RemoveRoot();
10+
}
11+
}

0 commit comments

Comments
 (0)