From 0a8e42fe0d411b074e254a34ff4da19fa04b5f73 Mon Sep 17 00:00:00 2001 From: naminodarie Date: Tue, 9 Feb 2021 22:27:33 +0900 Subject: [PATCH 1/3] Refactor PriorityQueue --- .../STL/Internal/IPriorityQueueOp.cs | 14 ++++++++++ .../STL/Internal/PriorityQueueOp.cs | 26 +++++++++++++------ 2 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 Source/AtCoderLibrary/STL/Internal/IPriorityQueueOp.cs diff --git a/Source/AtCoderLibrary/STL/Internal/IPriorityQueueOp.cs b/Source/AtCoderLibrary/STL/Internal/IPriorityQueueOp.cs new file mode 100644 index 00000000..455e45c3 --- /dev/null +++ b/Source/AtCoderLibrary/STL/Internal/IPriorityQueueOp.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace AtCoder.Internal +{ + public interface IPriorityQueueOp where TOp : IComparer + { + int Count { get; } + T Peek { get; } + void Add(T value); + T Dequeue(); + bool TryDequeue(out T result); + void Clear(); + } +} diff --git a/Source/AtCoderLibrary/STL/Internal/PriorityQueueOp.cs b/Source/AtCoderLibrary/STL/Internal/PriorityQueueOp.cs index 9cbf644a..0998e98c 100644 --- a/Source/AtCoderLibrary/STL/Internal/PriorityQueueOp.cs +++ b/Source/AtCoderLibrary/STL/Internal/PriorityQueueOp.cs @@ -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 where TOp : IComparer + public class PriorityQueueOp : IPriorityQueueOp, IEnumerable + where TOp : IComparer { protected T[] data; protected readonly TOp _comparer; @@ -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(data, 0, Count).ToArray(); + Array.Sort(arr, _comparer); + return arr; + } + IEnumerator IEnumerable.GetEnumerator() => GetItems().GetEnumerator(); + private class DebugView { - get + private readonly PriorityQueueOp pq; + public DebugView(PriorityQueueOp pq) { - var arr = new ArraySegment(data, 0, Count).ToArray(); - Array.Sort(arr, _comparer); - return arr; + this.pq = pq; } + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] + public T[] Items => pq.GetItems(); } } } From 537ffcc03301108f02a43db73bf12dddafde2fd1 Mon Sep 17 00:00:00 2001 From: naminodarie Date: Tue, 9 Feb 2021 22:40:18 +0900 Subject: [PATCH 2/3] Optimize PriorityQueue --- .../STL/Internal/IPriorityQueueOp.cs | 6 +- .../STL/Internal/PriorityQueueOp.cs | 2 +- .../STL/Internal/PriorityQueueOp`2.cs | 125 +++++++++++++++++- 3 files changed, 121 insertions(+), 12 deletions(-) diff --git a/Source/AtCoderLibrary/STL/Internal/IPriorityQueueOp.cs b/Source/AtCoderLibrary/STL/Internal/IPriorityQueueOp.cs index 455e45c3..1f0cbd8b 100644 --- a/Source/AtCoderLibrary/STL/Internal/IPriorityQueueOp.cs +++ b/Source/AtCoderLibrary/STL/Internal/IPriorityQueueOp.cs @@ -1,8 +1,6 @@ -using System.Collections.Generic; - -namespace AtCoder.Internal +namespace AtCoder.Internal { - public interface IPriorityQueueOp where TOp : IComparer + public interface IPriorityQueueOp { int Count { get; } T Peek { get; } diff --git a/Source/AtCoderLibrary/STL/Internal/PriorityQueueOp.cs b/Source/AtCoderLibrary/STL/Internal/PriorityQueueOp.cs index 0998e98c..59250c2c 100644 --- a/Source/AtCoderLibrary/STL/Internal/PriorityQueueOp.cs +++ b/Source/AtCoderLibrary/STL/Internal/PriorityQueueOp.cs @@ -8,7 +8,7 @@ namespace AtCoder.Internal { [DebuggerTypeProxy(typeof(PriorityQueueOp<,>.DebugView))] [DebuggerDisplay("Count = {" + nameof(Count) + "}")] - public class PriorityQueueOp : IPriorityQueueOp, IEnumerable + public class PriorityQueueOp : IPriorityQueueOp, IEnumerable where TOp : IComparer { protected T[] data; diff --git a/Source/AtCoderLibrary/STL/Internal/PriorityQueueOp`2.cs b/Source/AtCoderLibrary/STL/Internal/PriorityQueueOp`2.cs index 9469ad59..6020e735 100644 --- a/Source/AtCoderLibrary/STL/Internal/PriorityQueueOp`2.cs +++ b/Source/AtCoderLibrary/STL/Internal/PriorityQueueOp`2.cs @@ -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 - : PriorityQueueOp, KeyComparer> + public class PriorityQueueOp : + IPriorityQueueOp>, IEnumerable where TKOp : IComparer { + 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(comparer)) { } - public PriorityQueueOp(int capacity, TKOp comparer) : base(capacity, new KeyComparer(comparer)) { } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(TKey key, TValue value) => Add(new KeyValuePair(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 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 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) { @@ -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 result) + { + if (Count == 0) + { + result = default(KeyValuePair); + return false; + } + result = Dequeue(); + return true; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public KeyValuePair 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[] GetItems() + { + var keys = new ArraySegment(this.keys, 0, Count).ToArray(); + var values = new ArraySegment(this.values, 0, Count).ToArray(); + Array.Sort(keys, values, _comparer); + var arr = new KeyValuePair[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 pq; + public DebugView(PriorityQueueOp pq) + { + this.pq = pq; + } + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] + public KeyValuePair[] Items => pq.GetItems(); + } } } From c3876d1150e4d8a9cc0f5d937bc0b5e5fa802436 Mon Sep 17 00:00:00 2001 From: naminodarie Date: Tue, 9 Feb 2021 22:40:45 +0900 Subject: [PATCH 3/3] v1.2.7 --- CHANGELOG.md | 4 ++++ Directory.Build.props | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24138178..6914257e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 + ## [1.2.6] - 2021-02-09 ### Added - Add PriorityQueue.TryDequeue diff --git a/Directory.Build.props b/Directory.Build.props index 1be78654..d30fa0f8 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,8 +7,8 @@ https://github.com/naminodarie/ac-library-csharp https://github.com/naminodarie/ac-library-csharp/blob/master/CHANGELOG.md - 1.2.6 - 1.2.6.100 + 1.2.7 + 1.2.7.100 $(GIT_COMMIT) True