forked from mirror/DotRecast
added RcBinaryMinHeapTest
This commit is contained in:
parent
8a655528c3
commit
89214accfb
|
@ -1,161 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DotRecast.Core.Collections
|
|
||||||
{
|
|
||||||
public sealed class RcBinaryHeap<T>
|
|
||||||
{
|
|
||||||
public int Count => _count;
|
|
||||||
public int Capacity => _values.Length;
|
|
||||||
|
|
||||||
public T this[int index] => _values[index];
|
|
||||||
|
|
||||||
private T[] _values;
|
|
||||||
private int _count;
|
|
||||||
|
|
||||||
private Comparison<T> _comparision;
|
|
||||||
|
|
||||||
public RcBinaryHeap(Comparison<T> comparison) : this(8, comparison)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public RcBinaryHeap(int capacity, Comparison<T> comparison)
|
|
||||||
{
|
|
||||||
if (capacity <= 0)
|
|
||||||
throw new ArgumentException("capacity must greater than zero");
|
|
||||||
|
|
||||||
_values = new T[capacity];
|
|
||||||
_comparision = comparison;
|
|
||||||
_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Push(T val)
|
|
||||||
{
|
|
||||||
EnsureCapacity();
|
|
||||||
|
|
||||||
_values[_count++] = val;
|
|
||||||
|
|
||||||
UpHeap(_count - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Pop()
|
|
||||||
{
|
|
||||||
if (_count == 0)
|
|
||||||
{
|
|
||||||
Throw();
|
|
||||||
|
|
||||||
static void Throw() =>
|
|
||||||
throw new InvalidOperationException("no element to pop");
|
|
||||||
}
|
|
||||||
|
|
||||||
Swap(0, --_count);
|
|
||||||
DownHeap(1);
|
|
||||||
|
|
||||||
return _values[_count];
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public T Top()
|
|
||||||
{
|
|
||||||
return _values[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Modify(T node)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _count; i++)
|
|
||||||
{
|
|
||||||
if (_values[i].Equals(node))
|
|
||||||
{
|
|
||||||
UpHeap(i);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
Array.Clear(_values, 0, _count);
|
|
||||||
_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void FastClear()
|
|
||||||
{
|
|
||||||
_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T[] ToArray()
|
|
||||||
{
|
|
||||||
var copy = new T[_count];
|
|
||||||
Array.Copy(_values, copy, _count);
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ReBuild()
|
|
||||||
{
|
|
||||||
for (int i = _count / 2; i >= 1; i--)
|
|
||||||
{
|
|
||||||
DownHeap(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EnsureCapacity()
|
|
||||||
{
|
|
||||||
if (_values.Length <= _count)
|
|
||||||
{
|
|
||||||
var newValues = new T[Capacity * 2];
|
|
||||||
Array.Copy(_values, newValues, _count);
|
|
||||||
_values = newValues;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpHeap(int i)
|
|
||||||
{
|
|
||||||
int p = (i - 1) / 2;
|
|
||||||
while (p >= 0)
|
|
||||||
{
|
|
||||||
if (_comparision(_values[p], _values[i]) <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
Swap(p, i);
|
|
||||||
|
|
||||||
i = p;
|
|
||||||
p = (i - 1) / 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DownHeap(int i)
|
|
||||||
{
|
|
||||||
T d = _values[i - 1];
|
|
||||||
int child;
|
|
||||||
while (i <= _count / 2)
|
|
||||||
{
|
|
||||||
child = i * 2;
|
|
||||||
if (child < _count && _comparision(_values[child - 1], _values[child]) > 0)
|
|
||||||
child++;
|
|
||||||
|
|
||||||
if (_comparision(d, _values[child - 1]) <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
_values[i - 1] = _values[child - 1];
|
|
||||||
i = child;
|
|
||||||
}
|
|
||||||
_values[i - 1] = d;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private void Swap(int x, int y)
|
|
||||||
{
|
|
||||||
if (x == y)
|
|
||||||
return;
|
|
||||||
(_values[y], _values[x]) = (_values[x], _values[y]);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool IsEmpty()
|
|
||||||
{
|
|
||||||
return _count == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace DotRecast.Core.Collections
|
||||||
|
{
|
||||||
|
public sealed class RcBinaryMinHeap<T>
|
||||||
|
{
|
||||||
|
private readonly List<T> _items;
|
||||||
|
private readonly Comparison<T> _comparision;
|
||||||
|
|
||||||
|
public int Count => _items.Count;
|
||||||
|
public int Capacity => _items.Capacity;
|
||||||
|
|
||||||
|
public RcBinaryMinHeap(Comparison<T> comparision)
|
||||||
|
{
|
||||||
|
_items = new List<T>();
|
||||||
|
_comparision = comparision;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RcBinaryMinHeap(int capacity, Comparison<T> comparison) : this(comparison)
|
||||||
|
{
|
||||||
|
if (capacity <= 0)
|
||||||
|
throw new ArgumentException("capacity must greater than zero");
|
||||||
|
|
||||||
|
_items = new List<T>(capacity);
|
||||||
|
_comparision = comparison;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Push(T val)
|
||||||
|
{
|
||||||
|
_items.Add(val);
|
||||||
|
SiftUp(_items.Count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Pop()
|
||||||
|
{
|
||||||
|
var min = Peek();
|
||||||
|
RemoveMin();
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveMin()
|
||||||
|
{
|
||||||
|
if (_items.Count == 0)
|
||||||
|
{
|
||||||
|
Throw();
|
||||||
|
static void Throw() => throw new InvalidOperationException("no element to pop");
|
||||||
|
}
|
||||||
|
|
||||||
|
int last = _items.Count - 1;
|
||||||
|
Swap(0, last);
|
||||||
|
_items.RemoveAt(last);
|
||||||
|
|
||||||
|
MinHeapify(0, last - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public T Top()
|
||||||
|
{
|
||||||
|
return _items[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public T Peek()
|
||||||
|
{
|
||||||
|
if (IsEmpty())
|
||||||
|
{
|
||||||
|
throw new Exception("Heap is empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return _items[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool Modify(T node)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _items.Count; i++)
|
||||||
|
{
|
||||||
|
if (_items[i].Equals(node))
|
||||||
|
{
|
||||||
|
SiftUp(i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_items.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool IsEmpty()
|
||||||
|
{
|
||||||
|
return 0 == _items.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SiftUp(int nodeIndex)
|
||||||
|
{
|
||||||
|
int parent = (nodeIndex - 1) / 2;
|
||||||
|
while (_comparision.Invoke(_items[nodeIndex], _items[parent]) < 0)
|
||||||
|
{
|
||||||
|
Swap(parent, nodeIndex);
|
||||||
|
nodeIndex = parent;
|
||||||
|
parent = (nodeIndex - 1) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void MinHeapify(int nodeIndex, int lastIndex)
|
||||||
|
{
|
||||||
|
int left = (nodeIndex * 2) + 1;
|
||||||
|
int right = left + 1;
|
||||||
|
int smallest = nodeIndex;
|
||||||
|
|
||||||
|
if (left <= lastIndex && _comparision.Invoke(_items[left], _items[nodeIndex]) < 0)
|
||||||
|
smallest = left;
|
||||||
|
|
||||||
|
if (right <= lastIndex && _comparision.Invoke(_items[right], _items[smallest]) < 0)
|
||||||
|
smallest = right;
|
||||||
|
|
||||||
|
if (smallest == nodeIndex)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Swap(nodeIndex, smallest);
|
||||||
|
MinHeapify(smallest, lastIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private void Swap(int x, int y)
|
||||||
|
{
|
||||||
|
if (x == y)
|
||||||
|
return;
|
||||||
|
|
||||||
|
(_items[y], _items[x]) = (_items[x], _items[y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public T[] ToArray()
|
||||||
|
{
|
||||||
|
return _items.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<T> ToList()
|
||||||
|
{
|
||||||
|
return new List<T>(_items);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,9 +52,9 @@ public class PriorityQueueBenchmarks
|
||||||
{
|
{
|
||||||
[Params(10, 100, 1000, 10000)] public int Count;
|
[Params(10, 100, 1000, 10000)] public int Count;
|
||||||
|
|
||||||
private RcSortedQueue<Node> _rcQueue;
|
private RcSortedQueue<Node> _sq;
|
||||||
private RcBinaryHeap<Node> _heap;
|
private RcBinaryMinHeap<Node> _bmHeap;
|
||||||
private PriorityQueue<Node, Node> _pqueue;
|
private PriorityQueue<Node, Node> _pq;
|
||||||
|
|
||||||
private float[] _priority;
|
private float[] _priority;
|
||||||
|
|
||||||
|
@ -75,26 +75,24 @@ public class PriorityQueueBenchmarks
|
||||||
return x.id.CompareTo(y.id);
|
return x.id.CompareTo(y.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
_rcQueue = new(Comp);
|
_sq = new(Comp);
|
||||||
_heap = new(Count, Comp);
|
_bmHeap = new(Count, Comp);
|
||||||
_pqueue = new(Count, Comparer<Node>.Create(Comp));
|
_pq = new(Count, Comparer<Node>.Create(Comp));
|
||||||
|
|
||||||
_priority = new float[Count];
|
_priority = new float[Count];
|
||||||
for (int i = 0; i < Count; i++)
|
for (int i = 0; i < Count; i++)
|
||||||
{
|
{
|
||||||
_priority[i] = (float)Random.Shared.NextDouble() * 100f;
|
_priority[i] = (float)Random.Shared.NextDouble() * 100f;
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("111");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void Enqueue_rcQueue()
|
public void Enqueue_RcSortedQueue()
|
||||||
{
|
{
|
||||||
_rcQueue.Clear();
|
_sq.Clear();
|
||||||
for (int i = 0; i < Count; i++)
|
for (int i = 0; i < Count; i++)
|
||||||
{
|
{
|
||||||
_rcQueue.Enqueue(new Node
|
_sq.Enqueue(new Node
|
||||||
{
|
{
|
||||||
id = i,
|
id = i,
|
||||||
total = _priority[i],
|
total = _priority[i],
|
||||||
|
@ -103,12 +101,12 @@ public class PriorityQueueBenchmarks
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void Enqueue_heap()
|
public void Enqueue_RcBinaryMinHeap()
|
||||||
{
|
{
|
||||||
_heap.Clear();
|
_bmHeap.Clear();
|
||||||
for (int i = 0; i < Count; i++)
|
for (int i = 0; i < Count; i++)
|
||||||
{
|
{
|
||||||
_heap.Push(new Node
|
_bmHeap.Push(new Node
|
||||||
{
|
{
|
||||||
id = i,
|
id = i,
|
||||||
total = _priority[i],
|
total = _priority[i],
|
||||||
|
@ -117,9 +115,9 @@ public class PriorityQueueBenchmarks
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void Enqueue_pqueue()
|
public void Enqueue_PriorityQueue()
|
||||||
{
|
{
|
||||||
_pqueue.Clear();
|
_pq.Clear();
|
||||||
for (int i = 0; i < Count; i++)
|
for (int i = 0; i < Count; i++)
|
||||||
{
|
{
|
||||||
var node = new Node
|
var node = new Node
|
||||||
|
@ -127,52 +125,52 @@ public class PriorityQueueBenchmarks
|
||||||
id = i,
|
id = i,
|
||||||
total = _priority[i],
|
total = _priority[i],
|
||||||
};
|
};
|
||||||
_pqueue.Enqueue(node, node);
|
_pq.Enqueue(node, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void DequeueAll_rcQueue()
|
public void DequeueAll_RcSortedQueue()
|
||||||
{
|
{
|
||||||
_rcQueue.Clear();
|
_sq.Clear();
|
||||||
for (int i = 0; i < Count; i++)
|
for (int i = 0; i < Count; i++)
|
||||||
{
|
{
|
||||||
_rcQueue.Enqueue(new Node
|
_sq.Enqueue(new Node
|
||||||
{
|
{
|
||||||
id = i,
|
id = i,
|
||||||
total = _priority[i],
|
total = _priority[i],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
while (_rcQueue.Count() > 0)
|
while (_sq.Count() > 0)
|
||||||
{
|
{
|
||||||
_rcQueue.Dequeue();
|
_sq.Dequeue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void DequeueAll_heap()
|
public void DequeueAll_RcBinaryMinHeap()
|
||||||
{
|
{
|
||||||
_heap.Clear();
|
_bmHeap.Clear();
|
||||||
for (int i = 0; i < Count; i++)
|
for (int i = 0; i < Count; i++)
|
||||||
{
|
{
|
||||||
_heap.Push(new Node
|
_bmHeap.Push(new Node
|
||||||
{
|
{
|
||||||
id = i,
|
id = i,
|
||||||
total = _priority[i],
|
total = _priority[i],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
while (_heap.Count > 0)
|
while (_bmHeap.Count > 0)
|
||||||
{
|
{
|
||||||
_heap.Pop();
|
_bmHeap.Pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void DequeueAll_pqueue()
|
public void DequeueAll_PriorityQueue()
|
||||||
{
|
{
|
||||||
_pqueue.Clear();
|
_pq.Clear();
|
||||||
for (int i = 0; i < Count; i++)
|
for (int i = 0; i < Count; i++)
|
||||||
{
|
{
|
||||||
var node = new Node
|
var node = new Node
|
||||||
|
@ -180,52 +178,52 @@ public class PriorityQueueBenchmarks
|
||||||
id = i,
|
id = i,
|
||||||
total = _priority[i],
|
total = _priority[i],
|
||||||
};
|
};
|
||||||
_pqueue.Enqueue(node, node);
|
_pq.Enqueue(node, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (_pqueue.Count > 0)
|
while (_pq.Count > 0)
|
||||||
{
|
{
|
||||||
_pqueue.Dequeue();
|
_pq.Dequeue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void EnqueueDequeue_rcQueue()
|
public void EnqueueDequeue_RcSortedQueue()
|
||||||
{
|
{
|
||||||
_rcQueue.Clear();
|
_sq.Clear();
|
||||||
for (int i = 0; i < Count; i++)
|
for (int i = 0; i < Count; i++)
|
||||||
{
|
{
|
||||||
_rcQueue.Enqueue(new Node
|
_sq.Enqueue(new Node
|
||||||
{
|
{
|
||||||
id = i,
|
id = i,
|
||||||
total = _priority[i],
|
total = _priority[i],
|
||||||
});
|
});
|
||||||
|
|
||||||
_rcQueue.Dequeue();
|
_sq.Dequeue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void EnqueueDequeue_heap()
|
public void EnqueueDequeue_RcBinaryMinHeap()
|
||||||
{
|
{
|
||||||
_heap.Clear();
|
_bmHeap.Clear();
|
||||||
for (int i = 0; i < Count; i++)
|
for (int i = 0; i < Count; i++)
|
||||||
{
|
{
|
||||||
_heap.Push(new Node
|
_bmHeap.Push(new Node
|
||||||
{
|
{
|
||||||
id = i,
|
id = i,
|
||||||
total = _priority[i],
|
total = _priority[i],
|
||||||
});
|
});
|
||||||
|
|
||||||
_heap.Pop();
|
_bmHeap.Pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void EnqueueDequeue_pqueue()
|
public void EnqueueDequeue_PriorityQueue()
|
||||||
{
|
{
|
||||||
_pqueue.Clear();
|
_pq.Clear();
|
||||||
for (int i = 0; i < Count; i++)
|
for (int i = 0; i < Count; i++)
|
||||||
{
|
{
|
||||||
var node = new Node
|
var node = new Node
|
||||||
|
@ -233,9 +231,9 @@ public class PriorityQueueBenchmarks
|
||||||
id = i,
|
id = i,
|
||||||
total = _priority[i],
|
total = _priority[i],
|
||||||
};
|
};
|
||||||
_pqueue.Enqueue(node, node);
|
_pq.Enqueue(node, node);
|
||||||
|
|
||||||
_pqueue.Dequeue();
|
_pq.Dequeue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,147 @@
|
||||||
|
using DotRecast.Core.Collections;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace DotRecast.Core.Test;
|
||||||
|
|
||||||
|
public class RcBinaryMinHeapTest
|
||||||
|
{
|
||||||
|
private static readonly RcAtomicLong Gen = new();
|
||||||
|
|
||||||
|
private class Node
|
||||||
|
{
|
||||||
|
public readonly long Id;
|
||||||
|
public long Value;
|
||||||
|
|
||||||
|
public Node(int value)
|
||||||
|
{
|
||||||
|
Id = Gen.IncrementAndGet();
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPush()
|
||||||
|
{
|
||||||
|
var minHeap = new RcBinaryMinHeap<Node>((x, y) => x.Value.CompareTo(y.Value));
|
||||||
|
|
||||||
|
minHeap.Push(new Node(5));
|
||||||
|
minHeap.Push(new Node(3));
|
||||||
|
minHeap.Push(new Node(7));
|
||||||
|
minHeap.Push(new Node(2));
|
||||||
|
minHeap.Push(new Node(4));
|
||||||
|
|
||||||
|
// Push 후 힙의 속성을 검증
|
||||||
|
AssertHeapProperty(minHeap.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPop()
|
||||||
|
{
|
||||||
|
var minHeap = new RcBinaryMinHeap<Node>((x, y) => x.Value.CompareTo(y.Value));
|
||||||
|
|
||||||
|
minHeap.Push(new Node(5));
|
||||||
|
minHeap.Push(new Node(3));
|
||||||
|
minHeap.Push(new Node(7));
|
||||||
|
minHeap.Push(new Node(2));
|
||||||
|
minHeap.Push(new Node(4));
|
||||||
|
|
||||||
|
// Pop을 통해 최소 값부터 순서대로 제거하면서 검증
|
||||||
|
Assert.That(minHeap.Pop().Value, Is.EqualTo(2));
|
||||||
|
Assert.That(minHeap.Pop().Value, Is.EqualTo(3));
|
||||||
|
Assert.That(minHeap.Pop().Value, Is.EqualTo(4));
|
||||||
|
Assert.That(minHeap.Pop().Value, Is.EqualTo(5));
|
||||||
|
Assert.That(minHeap.Pop().Value, Is.EqualTo(7));
|
||||||
|
|
||||||
|
// 모든 요소를 Pop한 후에는 비어있어야 함
|
||||||
|
Assert.That(minHeap.IsEmpty(), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestTop()
|
||||||
|
{
|
||||||
|
var minHeap = new RcBinaryMinHeap<Node>((x, y) => x.Value.CompareTo(y.Value));
|
||||||
|
|
||||||
|
minHeap.Push(new Node(5));
|
||||||
|
minHeap.Push(new Node(3));
|
||||||
|
minHeap.Push(new Node(7));
|
||||||
|
|
||||||
|
Assert.That(minHeap.Top().Value, Is.EqualTo(3));
|
||||||
|
AssertHeapProperty(minHeap.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestModify()
|
||||||
|
{
|
||||||
|
var minHeap = new RcBinaryMinHeap<Node>((x, y) => x.Value.CompareTo(y.Value));
|
||||||
|
|
||||||
|
var node7 = new Node(7);
|
||||||
|
minHeap.Push(new Node(5));
|
||||||
|
minHeap.Push(new Node(3));
|
||||||
|
minHeap.Push(node7);
|
||||||
|
minHeap.Push(new Node(2));
|
||||||
|
minHeap.Push(new Node(4));
|
||||||
|
|
||||||
|
node7.Value = 1;
|
||||||
|
var result = minHeap.Modify(node7); // Modify value 7 to 1
|
||||||
|
var result2 = minHeap.Modify(new Node(4));
|
||||||
|
|
||||||
|
Assert.That(result, Is.EqualTo(true));
|
||||||
|
Assert.That(result2, Is.EqualTo(false));
|
||||||
|
Assert.That(minHeap.Top().Value, Is.EqualTo(1));
|
||||||
|
AssertHeapProperty(minHeap.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCount()
|
||||||
|
{
|
||||||
|
var minHeap = new RcBinaryMinHeap<Node>((x, y) => x.Value.CompareTo(y.Value));
|
||||||
|
|
||||||
|
minHeap.Push(new Node(5));
|
||||||
|
minHeap.Push(new Node(3));
|
||||||
|
minHeap.Push(new Node(7));
|
||||||
|
|
||||||
|
Assert.That(minHeap.Count, Is.EqualTo(3));
|
||||||
|
|
||||||
|
minHeap.Pop();
|
||||||
|
|
||||||
|
Assert.That(minHeap.Count, Is.EqualTo(2));
|
||||||
|
|
||||||
|
minHeap.Clear();
|
||||||
|
|
||||||
|
Assert.That(minHeap.Count, Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestIsEmpty()
|
||||||
|
{
|
||||||
|
var minHeap = new RcBinaryMinHeap<Node>((x, y) => x.Value.CompareTo(y.Value));
|
||||||
|
|
||||||
|
Assert.That(minHeap.IsEmpty(), Is.True);
|
||||||
|
|
||||||
|
minHeap.Push(new Node(5));
|
||||||
|
|
||||||
|
Assert.That(minHeap.IsEmpty(), Is.False);
|
||||||
|
|
||||||
|
minHeap.Pop();
|
||||||
|
|
||||||
|
Assert.That(minHeap.IsEmpty(), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AssertHeapProperty(Node[] array)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < array.Length / 2; i++)
|
||||||
|
{
|
||||||
|
int leftChildIndex = 2 * i + 1;
|
||||||
|
int rightChildIndex = 2 * i + 2;
|
||||||
|
|
||||||
|
// 왼쪽 자식 노드가 있는지 확인하고 비교
|
||||||
|
if (leftChildIndex < array.Length)
|
||||||
|
Assert.That(array[i].Value, Is.LessThanOrEqualTo(array[leftChildIndex].Value));
|
||||||
|
|
||||||
|
// 오른쪽 자식 노드가 있는지 확인하고 비교
|
||||||
|
if (rightChildIndex < array.Length)
|
||||||
|
Assert.That(array[i].Value, Is.LessThanOrEqualTo(array[rightChildIndex].Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue