Satsuma
a delicious .NET graph library
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Properties Pages
PriorityQueue.cs
Go to the documentation of this file.
1 #region License
2 /*This file is part of Satsuma Graph Library
3 Copyright © 2013 Balázs Szalkai
4 
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8 
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17 
18  2. Altered source versions must be plainly marked as such, and must not be
19  misrepresented as being the original software.
20 
21  3. This notice may not be removed or altered from any source
22  distribution.*/
23 #endregion
24 
25 using System;
26 using System.Collections.Generic;
27 
28 namespace Satsuma
29 {
32  public interface IReadOnlyPriorityQueue<TElement, TPriority>
33  {
35  int Count { get; }
37  IEnumerable<KeyValuePair<TElement, TPriority>> Items { get; }
39  bool Contains(TElement element);
44  bool TryGetPriority(TElement element, out TPriority priority);
46  TElement Peek();
48  TElement Peek(out TPriority priority);
49  }
50 
53  public interface IPriorityQueue<TElement, TPriority>
54  : IReadOnlyPriorityQueue<TElement, TPriority>, IClearable
55  {
57  TPriority this[TElement element] { get; set; }
60  bool Remove(TElement element);
63  bool Pop();
64  }
65 
67  public sealed class PriorityQueue<TElement, TPriority> : IPriorityQueue<TElement, TPriority>
68  where TPriority : IComparable<TPriority>
69  {
70  private List<TElement> payloads = new List<TElement>();
71  private List<TPriority> priorities = new List<TPriority>();
72  private Dictionary<TElement, int> positions = new Dictionary<TElement, int>();
73 
74  public void Clear()
75  {
76  payloads.Clear();
77  priorities.Clear();
78  positions.Clear();
79  }
80 
81  public int Count
82  {
83  get { return payloads.Count; }
84  }
85 
86  public IEnumerable<KeyValuePair<TElement, TPriority>> Items
87  {
88  get
89  {
90  for (int i = 0, n = Count; i < n; i++)
91  yield return new KeyValuePair<TElement, TPriority>(payloads[i], priorities[i]);
92  }
93  }
94 
95  public TPriority this[TElement element]
96  {
97  get
98  {
99  return priorities[positions[element]];
100  }
101 
102  set
103  {
104  int pos;
105  if (positions.TryGetValue(element, out pos))
106  {
107  TPriority oldPriority = priorities[pos];
108  priorities[pos] = value;
109  int priorityDelta = value.CompareTo(oldPriority);
110  if (priorityDelta < 0) MoveUp(pos);
111  else if (priorityDelta > 0) MoveDown(pos);
112  }
113  else
114  {
115  payloads.Add(element);
116  priorities.Add(value);
117  pos = Count - 1;
118  positions[element] = pos;
119  MoveUp(pos);
120  }
121  }
122  }
123 
124  public bool Contains(TElement element)
125  {
126  return positions.ContainsKey(element);
127  }
128 
129  public bool TryGetPriority(TElement element, out TPriority priority)
130  {
131  int pos;
132  if (!positions.TryGetValue(element, out pos))
133  {
134  priority = default(TPriority);
135  return false;
136  }
137  priority = priorities[pos];
138  return true;
139  }
140 
141  private void RemoveAt(int pos)
142  {
143  int count = Count;
144  TElement oldPayload = payloads[pos];
145  TPriority oldPriority = priorities[pos];
146  positions.Remove(oldPayload);
147 
148  bool empty = (count <= 1);
149  if (!empty && pos != count - 1)
150  {
151  // move the last element up to this place
152  payloads[pos] = payloads[count - 1];
153  priorities[pos] = priorities[count - 1];
154  positions[payloads[pos]] = pos;
155  }
156 
157  // delete the last element
158  payloads.RemoveAt(count - 1);
159  priorities.RemoveAt(count - 1);
160 
161  if (!empty && pos != count - 1)
162  {
163  int priorityDelta = priorities[pos].CompareTo(oldPriority);
164  if (priorityDelta > 0) MoveDown(pos);
165  else if (priorityDelta < 0) MoveUp(pos);
166  }
167  }
168 
169  public bool Remove(TElement element)
170  {
171  int pos;
172  bool success = positions.TryGetValue(element, out pos);
173  if (success) RemoveAt(pos);
174  return success;
175  }
176 
177  public TElement Peek()
178  {
179  return payloads[0];
180  }
181 
182  public TElement Peek(out TPriority priority)
183  {
184  priority = priorities[0];
185  return payloads[0];
186  }
187 
188  public bool Pop()
189  {
190  if (Count == 0) return false;
191  RemoveAt(0);
192  return true;
193  }
194 
195  private void MoveUp(int index)
196  {
197  TElement payload = payloads[index];
198  TPriority priority = priorities[index];
199 
200  int i = index;
201  while (i > 0)
202  {
203  int parent = i / 2;
204  if (priority.CompareTo(priorities[parent]) >= 0) break;
205 
206  payloads[i] = payloads[parent];
207  priorities[i] = priorities[parent];
208  positions[payloads[i]] = i;
209 
210  i = parent;
211  }
212 
213  if (i != index)
214  {
215  payloads[i] = payload;
216  priorities[i] = priority;
217  positions[payload] = i;
218  }
219  }
220 
221  private void MoveDown(int index)
222  {
223  TElement payload = payloads[index];
224  TPriority priority = priorities[index];
225 
226  int i = index;
227  while (2 * i < Count)
228  {
229  int min = i;
230 
231  int child = 2 * i;
232  if (priority.CompareTo(priorities[child]) >= 0) min = child;
233 
234  child++;
235  if (child < Count && priorities[min].CompareTo(priorities[child]) >= 0) min = child;
236 
237  if (min == i) break;
238 
239  payloads[i] = payloads[min];
240  priorities[i] = priorities[min];
241  positions[payloads[i]] = i;
242 
243  i = min;
244  }
245 
246  if (i != index)
247  {
248  payloads[i] = payload;
249  priorities[i] = priority;
250  positions[payload] = i;
251  }
252  }
253  }
254 }