Changed RcSortedQueue.Remove() function to use binary search

This commit is contained in:
ikpil 2024-02-08 00:03:06 +09:00
parent a1b730da7d
commit 45e4426df6
6 changed files with 146 additions and 19 deletions

View File

@ -7,10 +7,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased] - yyyy-mm-dd ## [Unreleased] - yyyy-mm-dd
### Added ### Added
- Added DtNodeQueue UnitTest [@ikpil](https://github.com/ikpil)
- Added RcSortedQueue UnitTest [@ikpil](https://github.com/ikpil)
### Fixed ### Fixed
### Changed ### Changed
- Changed RcSortedQueue.Remove() function to use binary search.
- Update Microsoft.NET.Test.Sdk 17.8.0 to 17.9.0 - Update Microsoft.NET.Test.Sdk 17.8.0 to 17.9.0
### Removed ### Removed

View File

@ -27,12 +27,12 @@ namespace DotRecast.Core.Collections
{ {
private bool _dirty; private bool _dirty;
private readonly List<T> _items; private readonly List<T> _items;
private readonly Comparison<T> _comparison; private readonly Comparer<T> _comparer;
public RcSortedQueue(Comparison<T> comparison) public RcSortedQueue(Comparison<T> comp)
{ {
_items = new List<T>(); _items = new List<T>();
_comparison = (x, y) => comparison.Invoke(x, y) * -1; // reverse _comparer = Comparer<T>.Create((x, y) => comp.Invoke(x, y) * -1);
} }
public int Count() public int Count()
@ -40,16 +40,22 @@ namespace DotRecast.Core.Collections
return _items.Count; return _items.Count;
} }
public bool IsEmpty()
{
return 0 == _items.Count;
}
public void Clear() public void Clear()
{ {
_items.Clear(); _items.Clear();
_dirty = false;
} }
private void Balance() private void Balance()
{ {
if (_dirty) if (_dirty)
{ {
_items.Sort(_comparison); // reverse _items.Sort(_comparer); // reverse
_dirty = false; _dirty = false;
} }
} }
@ -57,13 +63,13 @@ namespace DotRecast.Core.Collections
public T Peek() public T Peek()
{ {
Balance(); Balance();
return _items[_items.Count - 1]; return _items[^1];
} }
public T Dequeue() public T Dequeue()
{ {
var node = Peek(); var node = Peek();
_items.Remove(node); _items.RemoveAt(_items.Count - 1);
return node; return node;
} }
@ -73,19 +79,17 @@ namespace DotRecast.Core.Collections
_dirty = true; _dirty = true;
} }
public void Remove(T item) public bool Remove(T item)
{ {
int idx = _items.FindLastIndex(x => item.Equals(x)); Balance();
int idx = _items.BinarySearch(item, _comparer);
if (0 > idx) if (0 > idx)
return; return false;
_items.RemoveAt(idx); _items.RemoveAt(idx);
return true;
} }
public bool IsEmpty()
{
return 0 == _items.Count;
}
public List<T> ToList() public List<T> ToList()
{ {

View File

@ -24,7 +24,12 @@ namespace DotRecast.Detour
{ {
public class DtNodeQueue public class DtNodeQueue
{ {
private readonly RcSortedQueue<DtNode> m_heap = new RcSortedQueue<DtNode>((n1, n2) => n1.total.CompareTo(n2.total)); private readonly RcSortedQueue<DtNode> m_heap;
public DtNodeQueue()
{
m_heap = new RcSortedQueue<DtNode>((n1, n2) => n1.total.CompareTo(n2.total));
}
public int Count() public int Count()
{ {
@ -43,9 +48,7 @@ namespace DotRecast.Detour
public DtNode Pop() public DtNode Pop()
{ {
var node = Peek(); return m_heap.Dequeue();
m_heap.Remove(node);
return node;
} }
public void Push(DtNode node) public void Push(DtNode node)

View File

@ -0,0 +1,83 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using DotRecast.Core.Collections;
using NUnit.Framework;
namespace DotRecast.Core.Test;
public class RcSortedQueueTest
{
[Test]
public void TestEnqueueAndDequeue()
{
var sortedQueue = new RcSortedQueue<int>((a, b) => a.CompareTo(b));
var r = new RcRand();
var expectedList = new List<int>();
for (int i = 0; i < 999; ++i)
{
expectedList.Add(r.NextInt32() % 300); // allow duplication
}
// ready
foreach (var expected in expectedList)
{
sortedQueue.Enqueue(expected);
}
expectedList.Sort();
// check count
Assert.That(sortedQueue.Count(), Is.EqualTo(expectedList.Count));
Assert.That(sortedQueue.IsEmpty(), Is.False);
Assert.That(sortedQueue.ToList(), Is.EqualTo(expectedList));
// check Peek and Dequeue
for (int i = 0; i < expectedList.Count; ++i)
{
Assert.That(sortedQueue.Peek(), Is.EqualTo(expectedList[i]));
Assert.That(sortedQueue.Count(), Is.EqualTo(expectedList.Count - i));
Assert.That(sortedQueue.Dequeue(), Is.EqualTo(expectedList[i]));
Assert.That(sortedQueue.Count(), Is.EqualTo(expectedList.Count - i - 1));
}
// check count
Assert.That(sortedQueue.Count(), Is.EqualTo(0));
Assert.That(sortedQueue.IsEmpty(), Is.True);
}
[Test]
public void TestRemove()
{
var sortedQueue = new RcSortedQueue<int>((a, b) => a.CompareTo(b));
var r = new RcRand();
var expectedList = new List<int>();
for (int i = 0; i < 999; ++i)
{
expectedList.Add(r.NextInt32() % 300); // allow duplication
}
// ready
foreach (var expected in expectedList)
{
sortedQueue.Enqueue(expected);
}
expectedList.Shuffle();
// check
Assert.That(sortedQueue.Count(), Is.EqualTo(expectedList.Count));
foreach (var expected in expectedList)
{
Assert.That(sortedQueue.Remove(expected), Is.True);
}
Assert.That(sortedQueue.IsEmpty(), Is.True);
}
}

View File

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using DotRecast.Core.Collections; using DotRecast.Core.Collections;
using NuGet.Frameworks;
using NUnit.Framework; using NUnit.Framework;
namespace DotRecast.Core.Test; namespace DotRecast.Core.Test;

View File

@ -0,0 +1,35 @@
using System.Collections.Generic;
using System.Linq;
using DotRecast.Core.Collections;
using NUnit.Framework;
namespace DotRecast.Detour.Test;
public class DtNodeQueueTest
{
[Test]
public void TestDtNodeQueue()
{
var queue = new DtNodeQueue();
// check count
Assert.That(queue.Count(), Is.EqualTo(0));
const int count = 1000;
var nodes = new List<DtNode>();
for (int i = 0; i < count; ++i)
{
var node = new DtNode(i);
node.total = i;
nodes.Add(node);
}
nodes.Shuffle();
foreach (var node in nodes)
{
queue.Push(node);
}
Assert.That(queue.Count(), Is.EqualTo(count));
}
}