-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMultiQueue.cs
More file actions
146 lines (119 loc) · 4.47 KB
/
MultiQueue.cs
File metadata and controls
146 lines (119 loc) · 4.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// A Multi-queue that will return the oldest item from a class hierarchy when dequeue() is called.
// If a specific type is requested the oldest instance of that type is returned. All classes stored
// in the queue must derive from a common ancestor.
//
// Compiled: Visual Studio 2013
namespace MultiQueue
{
public class Letter
{
private string id;
public Letter(string id)
{
this.id = id;
}
public override string ToString() { return id; }
}
public class A : Letter { public A(string id) : base(id) { } }
public class B : Letter { public B(string id) : base(id) { } }
public class C : Letter { public C(string id) : base(id) { } }
public class MultiQueue<TBase> : IEnumerable
{
private class Item
{
public int Order { get; set; }
public TBase Value { get; set; }
}
Dictionary<Type, Queue<Item>> queues = new Dictionary<Type, Queue<Item>>();
int order = 0;
public void Push<T>(T itemToInsert) where T : TBase
{
var type = typeof(T);
if (!queues.ContainsKey(type))
queues.Add(type, new Queue<Item>());
var item = new Item() { Order = order++, Value = itemToInsert };
queues[type].Enqueue(item);
}
public TBase DequeueAny()
{
// Find the queue with the oldest item ~ O(k) where k is number of types
Queue<Item> minQueue = null;
foreach(var queue in queues)
{
if (!queue.Value.Any())
continue;
if (minQueue == null || minQueue.Peek().Order > queue.Value.Peek().Order)
minQueue = queue.Value;
}
return (minQueue != null) ? minQueue.Dequeue().Value : default(TBase);
}
public T Dequeue<T>() where T : TBase
{
var type = typeof(T);
if (!queues.ContainsKey(type))
return default(T);
var item = queues[type].Dequeue();
return (item != null) ? (T)item.Value : default(T);
}
public IEnumerator GetEnumerator()
{
// Dequeue the min of all types until no more items are left ~O(n*k)
TBase current = DequeueAny();
while(current != null)
{
yield return current;
current = DequeueAny();
}
}
}
public static class Program
{
public static void Main()
{
var queue = new MultiQueue<Letter>();
Console.WriteLine("Pop in order.");
queue.Push(new A("A1"));
queue.Push(new A("A2"));
queue.Push(new B("B3"));
queue.Push(new A("A4"));
queue.Push(new B("B5"));
queue.Push(new B("B6"));
Console.WriteLine(queue.DequeueAny().ToString());
Console.WriteLine(queue.DequeueAny().ToString());
Console.WriteLine(queue.DequeueAny().ToString());
Console.WriteLine(queue.DequeueAny().ToString());
Console.WriteLine(queue.DequeueAny().ToString());
Console.WriteLine(queue.DequeueAny().ToString());
Console.WriteLine("Pop in order from enumerable.");
queue.Push(new A("A1"));
queue.Push(new A("A2"));
queue.Push(new B("B3"));
queue.Push(new A("A4"));
queue.Push(new B("B5"));
queue.Push(new B("B6"));
foreach (var item in queue)
Console.WriteLine(item.ToString());
queue.Push(new A("A1"));
queue.Push(new A("A2"));
queue.Push(new B("B3"));
queue.Push(new A("A4"));
queue.Push(new B("B5"));
queue.Push(new B("B6"));
Console.WriteLine("Pop specific types.");
Console.WriteLine(queue.Dequeue<B>().ToString());
Console.WriteLine(queue.Dequeue<B>().ToString());
Console.WriteLine(queue.Dequeue<A>().ToString());
Console.WriteLine(queue.Dequeue<A>().ToString());
Console.WriteLine(queue.Dequeue<A>().ToString());
Console.WriteLine(queue.Dequeue<B>().ToString());
Console.WriteLine("Press Enter to exit.");
Console.ReadKey(true);
}
}
}