Revision | 7a41749a49ff6a165011c5d3a73203b3a07be29c (tree) |
---|---|
Time | 2015-07-07 22:14:58 |
Author | komutan <t_komuta@nift...> |
Commiter | komutan |
PriorityQueueをPairringHeapで実装。キューとしての順序を確保。
@@ -7,77 +7,78 @@ namespace NMeCab.Core | ||
7 | 7 | public class PriorityQueue<T> |
8 | 8 | where T : IComparable<T> |
9 | 9 | { |
10 | - private readonly List<T> heapList = new List<T>(); | |
11 | - | |
12 | - public int Count | |
10 | + private class Node | |
13 | 11 | { |
14 | - get { return this.heapList.Count; } | |
12 | + public T Value; | |
13 | + | |
14 | + public LinkedList<Node> Childs = new LinkedList<Node>(); | |
15 | + | |
16 | + public Node(T value) | |
17 | + { | |
18 | + this.Value = value; | |
19 | + } | |
15 | 20 | } |
16 | 21 | |
22 | + private Node rootNode = null; | |
23 | + | |
24 | + public int Count { get; private set; } | |
25 | + | |
26 | + public T First { get { return this.rootNode.Value; } } | |
27 | + | |
17 | 28 | public void Clear() |
18 | 29 | { |
19 | - this.heapList.Clear(); | |
30 | + this.rootNode = null; | |
31 | + this.Count = 0; | |
32 | + } | |
33 | + | |
34 | + public void RemoveFirst() | |
35 | + { | |
36 | + this.rootNode = this.Unify(this.rootNode.Childs); | |
37 | + this.Count--; | |
20 | 38 | } |
21 | 39 | |
22 | 40 | public void Push(T item) |
23 | 41 | { |
24 | - if (item == null) throw new ArgumentNullException("item"); | |
42 | + this.rootNode = this.Merge(this.rootNode, new Node(item)); | |
43 | + this.Count++; | |
44 | + } | |
25 | 45 | |
26 | - //up heap | |
27 | - int currentPos = this.heapList.Count; //tail | |
28 | - this.heapList.Add(default(T)); | |
29 | - while (currentPos != 0) | |
30 | - { | |
31 | - int parentPos = (currentPos - 1) / 2; | |
32 | - T parent = this.heapList[parentPos]; | |
46 | + public T Pop() | |
47 | + { | |
48 | + T ret = this.First; | |
49 | + this.RemoveFirst(); | |
50 | + return ret; | |
51 | + } | |
33 | 52 | |
34 | - if (parent.CompareTo(item) <= 0) break; | |
53 | + private Node Merge(Node l, Node r) | |
54 | + { | |
55 | + if (l == null) return r; | |
56 | + if (r == null) return l; | |
35 | 57 | |
36 | - this.heapList[currentPos] = parent; //down | |
37 | - currentPos = parentPos; | |
58 | + if (l.Value.CompareTo(r.Value) > 0) | |
59 | + { | |
60 | + r.Childs.AddFirst(l); | |
61 | + return r; | |
62 | + } | |
63 | + else | |
64 | + { | |
65 | + l.Childs.AddLast(r); | |
66 | + return l; | |
38 | 67 | } |
39 | - this.heapList[currentPos] = item; //commit | |
40 | 68 | } |
41 | 69 | |
42 | - public T Pop() | |
70 | + private Node Unify(LinkedList<Node> nodes) | |
43 | 71 | { |
44 | - if (this.heapList.Count == 0) throw new InvalidOperationException("Empty"); | |
72 | + if (nodes == null || nodes.Count == 0) return null; | |
45 | 73 | |
46 | - T root = this.heapList[0]; | |
74 | + Node x = nodes.First.Value; | |
75 | + nodes.RemoveFirst(); | |
76 | + if (nodes.Count == 0) return x; | |
47 | 77 | |
48 | - int tailPos = this.heapList.Count - 1; | |
49 | - if (tailPos != 0) | |
50 | - { | |
51 | - //down heap | |
52 | - T tail = this.heapList[tailPos]; | |
53 | - int currentPos = 0; | |
54 | - while (true) | |
55 | - { | |
56 | - int childPos = currentPos * 2 + 1; //left child | |
57 | - if (childPos >= tailPos) break; | |
58 | - T child = this.heapList[childPos]; | |
59 | - | |
60 | - int rChiledPos = childPos + 1; //right child | |
61 | - if (rChiledPos < tailPos) | |
62 | - { | |
63 | - T rChiled = this.heapList[rChiledPos]; | |
64 | - if (child.CompareTo(rChiled) > 0) | |
65 | - { | |
66 | - child = rChiled; | |
67 | - childPos = rChiledPos; | |
68 | - } | |
69 | - } | |
70 | - | |
71 | - if (tail.CompareTo(child) < 0) break; | |
72 | - | |
73 | - this.heapList[currentPos] = child; //up | |
74 | - currentPos = childPos; | |
75 | - } | |
76 | - this.heapList[currentPos] = tail; //commit | |
77 | - } | |
78 | - this.heapList.RemoveAt(tailPos); | |
78 | + Node y = nodes.First.Value; | |
79 | + nodes.RemoveFirst(); | |
79 | 80 | |
80 | - return root; | |
81 | + return this.Merge(this.Merge(x, y), this.Unify(nodes)); | |
81 | 82 | } |
82 | 83 | } |
83 | 84 | } |
@@ -57,9 +57,9 @@ | ||
57 | 57 | <Compile Include="Properties\AssemblyInfo.cs" /> |
58 | 58 | </ItemGroup> |
59 | 59 | <ItemGroup> |
60 | - <ProjectReference Include="..\LibNMeCab35\LibNMeCab35.csproj"> | |
61 | - <Project>{4ffe4221-2f41-446e-be59-d9cfcdf91ac6}</Project> | |
62 | - <Name>LibNMeCab35</Name> | |
60 | + <ProjectReference Include="..\LibNMeCab40MMF\LibNMeCab40MMF.csproj"> | |
61 | + <Project>{86711194-4c2b-4853-830f-07c57f035283}</Project> | |
62 | + <Name>LibNMeCab40MMF</Name> | |
63 | 63 | </ProjectReference> |
64 | 64 | </ItemGroup> |
65 | 65 | <Choose> |
@@ -1,92 +1,159 @@ | ||
1 | 1 | using System; |
2 | 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; |
3 | +using System.Collections.Generic; | |
4 | +using System.Linq; | |
5 | +using System.Diagnostics; | |
3 | 6 | |
4 | 7 | namespace LibNMeCabTest |
5 | 8 | { |
9 | + public class Element : IComparable<Element> | |
10 | + { | |
11 | + public int Priority { get; set; } | |
12 | + | |
13 | + public int Order { get; set; } | |
14 | + | |
15 | + public int CompareTo(Element other) | |
16 | + { | |
17 | + return this.Priority.CompareTo(other.Priority); | |
18 | + } | |
19 | + | |
20 | + public override int GetHashCode() | |
21 | + { | |
22 | + return this.Priority; | |
23 | + } | |
24 | + | |
25 | + public override bool Equals(object obj) | |
26 | + { | |
27 | + var other = obj as Element; | |
28 | + return other != null | |
29 | + && this.Priority == other.Priority | |
30 | + && this.Order == other.Order; | |
31 | + } | |
32 | + | |
33 | + public override string ToString() | |
34 | + { | |
35 | + return "priority:" + this.Priority + " order:" + this.Order; | |
36 | + } | |
37 | + } | |
38 | + | |
6 | 39 | [TestClass] |
7 | 40 | public class PriorityQueueTest |
8 | 41 | { |
9 | 42 | [TestMethod] |
10 | 43 | public void TestMethod1() |
11 | 44 | { |
12 | - var target = new NMeCab.Core.PriorityQueue<int>(); | |
45 | + var queue = new NMeCab.Core.PriorityQueue<Element>(); | |
46 | + var collection = new List<Element>(); | |
13 | 47 | var count = 0; |
14 | 48 | |
15 | - for (int i = 0; i < 10; i++) | |
49 | + for (int i = 0; i < 2; i++) | |
16 | 50 | { |
17 | - for (int j = 0; j < 10; j++) | |
51 | + //追加 優先度昇順 | |
52 | + for (int j = 0; j < 3; j++) | |
18 | 53 | { |
19 | - target.Push(j); | |
54 | + var item = new Element { Priority = j, Order = count }; | |
55 | + queue.Push(item); | |
56 | + collection.Add(item); | |
20 | 57 | count++; |
21 | - Assert.AreEqual(target.Count, count); | |
58 | + Assert.AreEqual(queue.Count, count); | |
22 | 59 | } |
23 | 60 | } |
24 | 61 | |
25 | - int wrk1 = 0; | |
26 | - for (int k = 0; k < count; k++) | |
62 | + //並べ直し | |
63 | + collection = (from e in collection | |
64 | + orderby e.Priority, e.Order | |
65 | + select e).ToList(); | |
66 | + | |
67 | + //取り出し | |
68 | + foreach (var expected in collection) | |
27 | 69 | { |
28 | - int wrk2 = target.Pop(); | |
70 | + var actual = queue.Pop(); | |
29 | 71 | count--; |
30 | - Assert.AreEqual(target.Count, count); | |
31 | - Assert.IsTrue(wrk1 <= wrk2); | |
32 | - wrk1 = wrk2; | |
72 | + | |
73 | + Assert.AreEqual(expected, actual); | |
74 | + Assert.AreEqual(count, queue.Count); | |
33 | 75 | } |
34 | 76 | } |
35 | 77 | |
36 | 78 | [TestMethod] |
37 | 79 | public void TestMethod2() |
38 | 80 | { |
39 | - var target = new NMeCab.Core.PriorityQueue<int>(); | |
81 | + var queue = new NMeCab.Core.PriorityQueue<Element>(); | |
82 | + var collection = new List<Element>(); | |
40 | 83 | var count = 0; |
41 | 84 | |
42 | - for (int i = 0; i < 10; i++) | |
85 | + for (int i = 0; i < 2; i++) | |
43 | 86 | { |
44 | - for (int j = 10; j >= 0; j--) | |
87 | + //追加 優先度降順 | |
88 | + for (int j = 3; j >= 0; j--) | |
45 | 89 | { |
46 | - target.Push(j); | |
90 | + var item = new Element { Priority = j, Order = count }; | |
91 | + queue.Push(item); | |
92 | + collection.Add(item); | |
47 | 93 | count++; |
48 | - Assert.AreEqual(target.Count, count); | |
94 | + | |
95 | + Assert.AreEqual(count, queue.Count); | |
49 | 96 | } |
50 | 97 | } |
51 | 98 | |
52 | - int wrk1 = 0; | |
53 | - for (int k = 0; k < count; k++) | |
99 | + //並べ直し | |
100 | + collection = (from e in collection | |
101 | + orderby e.Priority, e.Order | |
102 | + select e).ToList(); | |
103 | + | |
104 | + //取り出し | |
105 | + foreach (var expected in collection) | |
54 | 106 | { |
55 | - int wrk2 = target.Pop(); | |
107 | + var actual = queue.Pop(); | |
56 | 108 | count--; |
57 | - Assert.AreEqual(target.Count, count); | |
58 | - Assert.IsTrue(wrk1 <= wrk2); | |
59 | - wrk1 = wrk2; | |
109 | + | |
110 | + Assert.AreEqual(expected, actual); | |
111 | + Assert.AreEqual(count, queue.Count); | |
60 | 112 | } |
61 | 113 | } |
62 | 114 | |
63 | 115 | [TestMethod] |
64 | 116 | public void TestMethod3() |
65 | 117 | { |
66 | - var target = new NMeCab.Core.PriorityQueue<int>(); | |
118 | + var queue = new NMeCab.Core.PriorityQueue<Element>(); | |
119 | + var collection = new List<Element>(); | |
120 | + var order = 0; | |
67 | 121 | var count = 0; |
68 | 122 | var rnd = new Random(); |
69 | 123 | |
124 | + //追加と取り出しを一定数繰り返す | |
70 | 125 | for (int i = 0; i < 1000; i++) |
71 | 126 | { |
127 | + //ランダム優先度でランダム個追加 | |
72 | 128 | int repeat = rnd.Next(10); |
73 | 129 | for (int j = 0; j < repeat; j++) |
74 | 130 | { |
75 | - target.Push(rnd.Next(10)); | |
131 | + var item = new Element { Priority = rnd.Next(10), Order = order }; | |
132 | + collection.Add(item); | |
133 | + queue.Push(item); | |
134 | + order++; | |
76 | 135 | count++; |
77 | - Assert.AreEqual(target.Count, count); | |
136 | + | |
137 | + Assert.AreEqual(count, queue.Count); | |
78 | 138 | } |
79 | 139 | |
80 | - repeat = rnd.Next(target.Count); | |
81 | - int wrk1 = 0; | |
82 | - for (int k = 0; k < repeat; k++) | |
140 | + //並べ直し | |
141 | + collection = (from e in collection | |
142 | + orderby e.Priority, e.Order | |
143 | + select e).ToList(); | |
144 | + | |
145 | + //ランダム個取り出し | |
146 | + repeat = rnd.Next(collection.Count); | |
147 | + for (int j = 0; j < repeat; j++) | |
83 | 148 | { |
84 | - int wrk2 = target.Pop(); | |
149 | + var actual = queue.Pop(); | |
150 | + var expected = collection[j]; | |
85 | 151 | count--; |
86 | - Assert.AreEqual(target.Count, count); | |
87 | - Assert.IsTrue(wrk1 <= wrk2); | |
88 | - wrk1 = wrk2; | |
152 | + | |
153 | + Assert.AreEqual(expected, actual); | |
154 | + Assert.AreEqual(count, queue.Count); | |
89 | 155 | } |
156 | + collection.RemoveRange(0, repeat); | |
90 | 157 | } |
91 | 158 | } |
92 | 159 | } |