Skip to content

Commit

Permalink
Merge pull request #33 from naminodarie/feature/PriorityQueue`2
Browse files Browse the repository at this point in the history
Optimize PriorityQueue<TKey, TValue>
  • Loading branch information
kzrnm authored Feb 9, 2021
2 parents 0c72d68 + c3876d1 commit 61f55a6
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 17 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.2.7] - 2021-02-09
### Changed
- Optimize PriorityQueue<TKey, TValue>

## [1.2.6] - 2021-02-09
### Added
- Add PriorityQueue.TryDequeue
Expand Down
4 changes: 2 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
<RepositoryUrl>https://github.com/naminodarie/ac-library-csharp</RepositoryUrl>
<PackageReleaseNotes>https://github.com/naminodarie/ac-library-csharp/blob/master/CHANGELOG.md</PackageReleaseNotes>

<Version>1.2.6</Version>
<AssemblyVersion>1.2.6.100</AssemblyVersion>
<Version>1.2.7</Version>
<AssemblyVersion>1.2.7.100</AssemblyVersion>
<RepositoryCommit Condition="'$(GIT_COMMIT)' != ''">$(GIT_COMMIT)</RepositoryCommit>

<SignAssembly>True</SignAssembly>
Expand Down
12 changes: 12 additions & 0 deletions Source/AtCoderLibrary/STL/Internal/IPriorityQueueOp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace AtCoder.Internal
{
public interface IPriorityQueueOp<T>
{
int Count { get; }
T Peek { get; }
void Add(T value);
T Dequeue();
bool TryDequeue(out T result);
void Clear();
}
}
26 changes: 18 additions & 8 deletions Source/AtCoderLibrary/STL/Internal/PriorityQueueOp.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace AtCoder.Internal
{
[DebuggerTypeProxy(typeof(PriorityQueueOp<,>.DebugView))]
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
public class PriorityQueueOp<T, TOp> where TOp : IComparer<T>
public class PriorityQueueOp<T, TOp> : IPriorityQueueOp<T>, IEnumerable
where TOp : IComparer<T>
{
protected T[] data;
protected readonly TOp _comparer;
Expand Down Expand Up @@ -88,16 +91,23 @@ protected internal void UpdateDown(int i)
data[i] = tar;
}
public void Clear() => Count = 0;
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051", Justification = "for debugger")]
private T[] Items

private T[] GetItems()
{
var arr = new ArraySegment<T>(data, 0, Count).ToArray();
Array.Sort(arr, _comparer);
return arr;
}
IEnumerator IEnumerable.GetEnumerator() => GetItems().GetEnumerator();
private class DebugView
{
get
private readonly PriorityQueueOp<T, TOp> pq;
public DebugView(PriorityQueueOp<T, TOp> pq)
{
var arr = new ArraySegment<T>(data, 0, Count).ToArray();
Array.Sort(arr, _comparer);
return arr;
this.pq = pq;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public T[] Items => pq.GetItems();
}
}
}
125 changes: 118 additions & 7 deletions Source/AtCoderLibrary/STL/Internal/PriorityQueueOp`2.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,52 @@
using System.Collections.Generic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace AtCoder.Internal
{
[DebuggerTypeProxy(typeof(PriorityQueueOp<,,>.DebugView))]
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
public class PriorityQueueOp<TKey, TValue, TKOp>
: PriorityQueueOp<KeyValuePair<TKey, TValue>, KeyComparer<TKey, TValue, TKOp>>
public class PriorityQueueOp<TKey, TValue, TKOp> :
IPriorityQueueOp<KeyValuePair<TKey, TValue>>, IEnumerable
where TKOp : IComparer<TKey>
{
protected TKey[] keys;
protected TValue[] values;
protected readonly TKOp _comparer;
internal const int DefaultCapacity = 16;
public PriorityQueueOp() : this(default(TKOp)) { }
public PriorityQueueOp(int capacity) : this(capacity, default(TKOp)) { }
public PriorityQueueOp(TKOp comparer) : base(new KeyComparer<TKey, TValue, TKOp>(comparer)) { }
public PriorityQueueOp(int capacity, TKOp comparer) : base(capacity, new KeyComparer<TKey, TValue, TKOp>(comparer)) { }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(TKey key, TValue value) => Add(new KeyValuePair<TKey, TValue>(key, value));
public PriorityQueueOp(TKOp comparer) : this(DefaultCapacity, comparer) { }
public PriorityQueueOp(int capacity, TKOp comparer)
{
if (comparer == null)
throw new ArgumentNullException(nameof(comparer));
keys = new TKey[Math.Max(capacity, DefaultCapacity)];
values = new TValue[Math.Max(capacity, DefaultCapacity)];
_comparer = comparer;
}
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public int Count { get; private set; } = 0;

public KeyValuePair<TKey, TValue> Peek => KeyValuePair.Create(keys[0], values[0]);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void Resize()
{
Array.Resize(ref keys, keys.Length << 1);
Array.Resize(ref values, values.Length << 1);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(KeyValuePair<TKey, TValue> pair) => Add(pair.Key, pair.Value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(TKey key, TValue value)
{
if (Count >= keys.Length) Resize();
keys[Count] = key;
values[Count++] = value;
UpdateUp(Count - 1);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryDequeue(out TKey key, out TValue value)
{
Expand All @@ -28,5 +59,85 @@ public bool TryDequeue(out TKey key, out TValue value)
(key, value) = Dequeue();
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryDequeue(out KeyValuePair<TKey, TValue> result)
{
if (Count == 0)
{
result = default(KeyValuePair<TKey, TValue>);
return false;
}
result = Dequeue();
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public KeyValuePair<TKey, TValue> Dequeue()
{
var res = KeyValuePair.Create(keys[0], values[0]);
keys[0] = keys[--Count];
values[0] = values[Count];
UpdateDown(0);
return res;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected internal void UpdateUp(int i)
{
var tar = keys[i];
var tarVal = values[i];
while (i > 0)
{
var p = (i - 1) >> 1;
if (_comparer.Compare(tar, keys[p]) >= 0)
break;
keys[i] = keys[p];
values[i] = values[p];
i = p;
}
keys[i] = tar;
values[i] = tarVal;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected internal void UpdateDown(int i)
{
var tar = keys[i];
var tarVal = values[i];
var n = Count;
var child = 2 * i + 1;
while (child < n)
{
if (child != n - 1 && _comparer.Compare(keys[child], keys[child + 1]) > 0) child++;
if (_comparer.Compare(tar, keys[child]) <= 0)
break;
keys[i] = keys[child];
values[i] = values[child];
i = child;
child = 2 * i + 1;
}
keys[i] = tar;
values[i] = tarVal;
}
public void Clear() => Count = 0;

private KeyValuePair<TKey, TValue>[] GetItems()
{
var keys = new ArraySegment<TKey>(this.keys, 0, Count).ToArray();
var values = new ArraySegment<TValue>(this.values, 0, Count).ToArray();
Array.Sort(keys, values, _comparer);
var arr = new KeyValuePair<TKey, TValue>[Count];
for (int i = 0; i < arr.Length; i++)
arr[i] = KeyValuePair.Create(keys[i], values[i]);
return arr;
}
IEnumerator IEnumerable.GetEnumerator() => GetItems().GetEnumerator();
private class DebugView
{
private readonly PriorityQueueOp<TKey, TValue, TKOp> pq;
public DebugView(PriorityQueueOp<TKey, TValue, TKOp> pq)
{
this.pq = pq;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePair<TKey, TValue>[] Items => pq.GetItems();
}
}
}

0 comments on commit 61f55a6

Please sign in to comment.