├── .gitignore
├── README.md
└── src
├── FNSeq
├── FNSeq.cs
├── FNSeq.csproj
└── Properties
│ └── AssemblyInfo.cs
├── FingerTree.UnitTests
├── App.config
├── FingerTree.UnitTests.csproj
├── OrderedSequenceUnitTests.cs
├── Program.cs
└── Properties
│ └── AssemblyInfo.cs
├── FingerTree.sln
├── FingerTree
├── FingerTree.cs
├── FingerTree.csproj
├── FingerTreeM.cs
├── FingerTreeSplits.cs
├── OrderedSequence.cs
├── PriorityQueue.cs
├── Properties
│ └── AssemblyInfo.cs
└── RandAccessSequence.cs
└── TestDotNetCollection
├── Properties
└── AssemblyInfo.cs
├── TestCollAndString.cs
├── TestCollAndString.csproj
└── app.config
/.gitignore:
--------------------------------------------------------------------------------
1 | **.user
2 | **/obj
3 | **/bin
4 | **/res
5 | **.tlb
6 | **.tlh
7 | **.olb
8 | **.dll
9 | **.obj
10 | **.exe
11 | **.ncb
12 | **.suo
13 | **.bak
14 | **.log
15 | **.sdf
16 | **.opensdf
17 | **.ipch
18 | /vs
19 | /src/FingerTree/bin
20 | /src/FingerTree/obj
21 | /src/FingerTree.UnitTests/bin
22 | /src/FingerTree.UnitTests/obj
23 | /src/FNSeq/bin
24 | /src/FNSeq/obj
25 | /src/TestDotNetCollection/bin
26 | /src/TestDotNetCollection/obj
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CSharpFingerTree
2 |
3 |
4 | C# Implementation of Finger Tree
5 |
6 | Based on the work of Dimitre Novatchev [here](https://dnovatchev.wordpress.com/2008/07/20/the-swiss-army-knife-of-data-structures-in-c/) which in turn is based on this [research paper](http://www.staff.city.ac.uk/~ross/papers/FingerTree.html).
7 |
--------------------------------------------------------------------------------
/src/FNSeq/FNSeq.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using FingerTree;
6 | namespace FSeq
7 | {
8 | public class FString
9 | {
10 | private Seq theSeq = null;
11 |
12 | public FString()
13 | {
14 | theSeq = new Seq(new List());
15 | }
16 |
17 | public FString(string aString)
18 | {
19 | theSeq = new Seq(aString.ToCharArray());
20 | }
21 |
22 | protected FString(Seq aSeq)
23 | {
24 | theSeq = aSeq;
25 | }
26 |
27 | public uint Length()
28 | {
29 | return this.theSeq.length;
30 | }
31 |
32 | public FString Merge(FString string2)
33 | {
34 | return new FString(new Seq(theSeq.Merge(string2.theSeq.treeRep)));
35 | }
36 |
37 | public FString concat(FString afString)
38 | {
39 | return this.Merge(afString);
40 | }
41 |
42 | public static FString
43 | stringJoin(FString[] stringList,
44 | FString strSeparator)
45 | {
46 | FString fStr = new FString();
47 |
48 | int numStrings = stringList.Length;
49 |
50 | if (numStrings == 0)
51 | return fStr;
52 | //else
53 | int i = 0;
54 | for (i = 0; i < numStrings - 1; i++)
55 | {
56 | fStr = fStr.Merge(stringList[i]);
57 | fStr = fStr.Merge(strSeparator);
58 | }
59 | fStr = fStr.Merge(stringList[i]);
60 |
61 | return fStr;
62 | }
63 |
64 | public FString insert(int startInd, FString fstr2)
65 | {
66 | Pair, uint>, FTreeM, uint>> theSplit =
67 | theSeq.SeqSplit(new MPredicate
68 | (FP.Curry(theLTMethod, (uint)startInd)));
69 |
70 | return new FString(
71 | new Seq
72 | (
73 | (
74 | theSplit.first.Merge(fstr2.theSeq.treeRep)
75 | .Merge(((Seq)(theSplit.second)).treeRep)
76 | )
77 | )
78 | );
79 |
80 | }
81 |
82 | public FString remove(int startInd, int subLength)
83 | {
84 | uint theLength = theSeq.length;
85 |
86 | if (theLength == 0 || subLength <= 0)
87 | return this;
88 | //else
89 | if (startInd < 1)
90 | startInd = 0;
91 |
92 | if (startInd + subLength > theLength)
93 | subLength = (int)(theLength - startInd);
94 |
95 | // Now ready to do the real work
96 | Pair, uint>, FTreeM, uint>> split1 =
97 | theSeq.SeqSplit
98 | (
99 | new MPredicate
100 | (FP.Curry(theLTMethod, (uint)startInd))
101 | );
102 |
103 | Pair, uint>, FTreeM, uint>> split2 =
104 | split1.second.SeqSplit
105 | (
106 | new MPredicate
107 | (FP.Curry(theLTMethod, (uint)subLength))
108 | );
109 |
110 | FString fsResult =
111 | new FString(
112 | new Seq
113 | (
114 | split1.first.Merge(((Seq)(split2.second)).treeRep)
115 | )
116 | );
117 | return fsResult;
118 | }
119 |
120 | public FString substring(int startInd, int subLength)
121 | {
122 | uint theLength = theSeq.length;
123 |
124 | if (theLength == 0 || subLength <= 0)
125 | return this;
126 | //else
127 | if (startInd < 1)
128 | startInd = 0;
129 |
130 | if (startInd + subLength > theLength)
131 | subLength = (int)(theLength - startInd);
132 |
133 | // Now ready to do the real work
134 | FString fsResult =
135 | new FString(
136 | new Seq
137 | (
138 | theSeq.SeqSplit
139 | (
140 | new MPredicate
141 | (FP.Curry(theLTMethod, (uint)startInd))
142 | ).second
143 | .SeqSplit
144 | (new MPredicate
145 | (FP.Curry(theLTMethod, (uint)subLength))
146 | ).first
147 | )
148 | );
149 | return fsResult;
150 | }
151 |
152 | public char itemAt(int ind)
153 | {
154 | if (ind < 0 || ind >= Length())
155 | throw new ArgumentOutOfRangeException();
156 | //else
157 | return theSeq.ElemAt(((uint)ind));
158 | }
159 |
160 |
161 |
162 | bool theLTMethod(uint i1, uint i2)
163 | {
164 | return i1 < i2;
165 | }
166 |
167 | }
168 |
169 |
170 | public class FNSeq //where T : IMeasured
171 | {
172 | private Seq theSeq = null;
173 |
174 | public FNSeq()
175 | {
176 | theSeq = new Seq(new List());
177 | }
178 |
179 | public FNSeq(IEnumerable seqIterator)
180 | {
181 | theSeq = new Seq(new List());
182 |
183 | foreach(T t in seqIterator)
184 | theSeq = (Seq)(theSeq.Push_Back(new SizedElem(t)));
185 | }
186 |
187 | protected FNSeq(Seq aSeq)
188 | {
189 | theSeq = aSeq;
190 | }
191 |
192 | public uint Length()
193 | {
194 | return this.theSeq.length;
195 | }
196 |
197 | public List ToSequence()
198 | {
199 | List lstResult = new List();
200 |
201 | foreach (SizedElem elem in theSeq.ToSequence())
202 | lstResult.Add(elem.Element);
203 |
204 | return lstResult;//.ToArray();
205 | }
206 |
207 | public T itemAt(int ind)
208 | {
209 | if (ind < 0 || ind >= Length())
210 | throw new ArgumentOutOfRangeException();
211 | //else
212 | return theSeq.ElemAt(((uint)ind));
213 | }
214 |
215 | public FNSeq reverse()
216 | {
217 | return new FNSeq((Seq)(theSeq.Reverse()));
218 | }
219 |
220 | public FNSeq Merge(FNSeq seq2)
221 | {
222 | return new FNSeq(new Seq(theSeq.Merge(seq2.theSeq.treeRep)));
223 | }
224 |
225 | public FNSeq skip(int length)
226 | {
227 | return new FNSeq
228 | (
229 | new Seq
230 | (
231 | this.theSeq.dropUntil(new MPredicate
232 | (FP.Curry(theLTMethod, (uint)length))
233 | )
234 | )
235 | );
236 | }
237 |
238 | public FNSeq take(int length)
239 | {
240 | return new FNSeq
241 | (
242 | new Seq
243 | (
244 | this.theSeq.takeUntil(new MPredicate
245 | (FP.Curry(theLTMethod, (uint)length))
246 | )
247 | )
248 | );
249 | }
250 |
251 | public FNSeq subsequence(int startInd, int subLength)
252 | {
253 | uint theLength = theSeq.length;
254 |
255 | if (theLength == 0 || subLength <= 0)
256 | return this;
257 | //else
258 | if (startInd < 0)
259 | startInd = 0;
260 |
261 | if (startInd + subLength > theLength)
262 | subLength = (int)(theLength - startInd);
263 |
264 | // Now ready to do the real work
265 | FNSeq fsResult =
266 | new FNSeq(
267 | (Seq)
268 | (
269 | ((Seq)
270 | (theSeq.SeqSplit
271 | (
272 | new MPredicate
273 | (FP.Curry(theLTMethod, (uint)startInd))
274 | ).second
275 | )
276 | ).SeqSplit
277 | (new MPredicate
278 | (FP.Curry(theLTMethod, (uint)subLength))
279 | ).first
280 | )
281 | );
282 | return fsResult;
283 | }
284 |
285 | public FNSeq remove(int ind)
286 | {
287 | if (ind < 0 || ind >= Length())
288 | throw new ArgumentOutOfRangeException();
289 | //else
290 | return new FNSeq(theSeq.RemoveAt((uint)(ind)));
291 | }
292 |
293 | // this inserts a whole sequence, so we cannot just use Seq.snsertAt()
294 | public FNSeq insert_before(int ind, FNSeq fSeq2)
295 | {
296 | if (ind < 0 || ind >= this.Length())
297 | throw new ArgumentOutOfRangeException();
298 | //else
299 | Pair, uint>, FTreeM, uint>> theSplit =
300 | theSeq.SeqSplit
301 | (new MPredicate
302 | (
303 | FP.Curry(theLTMethod, (uint)ind - 1)
304 | )
305 | );
306 |
307 | FNSeq fs1 = new FNSeq((Seq)(theSplit.first));
308 | FNSeq fs3 = new FNSeq((Seq)(theSplit.second));
309 |
310 | return fs1.Merge(fSeq2).Merge(fs3);
311 | }
312 |
313 | bool theLTMethod(uint i1, uint i2)
314 | {
315 | return i1 < i2;
316 | }
317 |
318 | }
319 | }
320 |
321 |
--------------------------------------------------------------------------------
/src/FNSeq/FNSeq.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 9.0.21022
7 | 2.0
8 | {9CDD93A8-3350-4F13-A001-F640BF28B96D}
9 | Library
10 | Properties
11 | FNSeq
12 | FNSeq
13 | v4.6.1
14 | 512
15 |
16 |
17 |
18 |
19 | 3.5
20 |
21 |
22 |
23 | true
24 | full
25 | false
26 | bin\Debug\
27 | DEBUG;TRACE
28 | prompt
29 | 4
30 | false
31 |
32 |
33 | pdbonly
34 | true
35 | bin\Release\
36 | TRACE
37 | prompt
38 | 4
39 | false
40 |
41 |
42 |
43 |
44 | 3.5
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | {51807875-B25D-4F87-8B8D-5100E5F26BAD}
55 | FingerTree
56 |
57 |
58 |
59 |
66 |
--------------------------------------------------------------------------------
/src/FNSeq/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("FNSeq")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("At Home")]
12 | [assembly: AssemblyProduct("FNSeq")]
13 | [assembly: AssemblyCopyright("Copyright © At Home 2008")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("501764b5-1b81-408a-9970-96051f5d1daf")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/FingerTree.UnitTests/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/FingerTree.UnitTests/FingerTree.UnitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {78137E75-6466-4EDA-AACF-0EC4405741CA}
8 | Exe
9 | Properties
10 | FingerTree.UnitTests
11 | FingerTree.UnitTests
12 | v4.6.1
13 | 512
14 | true
15 |
16 |
17 |
18 | AnyCPU
19 | true
20 | full
21 | false
22 | bin\Debug\
23 | DEBUG;TRACE
24 | prompt
25 | 4
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | {51807875-b25d-4f87-8b8d-5100e5f26bad}
57 | FingerTree
58 |
59 |
60 |
61 |
68 |
--------------------------------------------------------------------------------
/src/FingerTree.UnitTests/OrderedSequenceUnitTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace FingerTree.UnitTests
8 | {
9 | public class OrderedSequenceUnitTests
10 | {
11 | public void TestCharOrderedSequence()
12 | {
13 | var os = new OrderedSequence(
14 | new Key(uint.MinValue, (c) => { return c; }));
15 |
16 | var src = new List
17 | {
18 | 'z',
19 | 'b',
20 | 'h',
21 | 'a',
22 | 'a',
23 | 'c',
24 | 'e',
25 | 'j'
26 | };
27 |
28 | foreach (var s in src)
29 | os = os.Insert(s);
30 |
31 | var expected = new List
32 | {
33 | 'a',
34 | 'a',
35 | 'b',
36 | 'c',
37 | 'e',
38 | 'h',
39 | 'j',
40 | 'z',
41 | };
42 |
43 | var tseq = os.ToSequence();
44 |
45 | var tseqEnum = tseq.GetEnumerator();
46 | tseqEnum.MoveNext();
47 |
48 | foreach (var es in expected)
49 | {
50 | if (0 != es.CompareTo(tseqEnum.Current))
51 | throw new Exception("TestCharOrderedSequence failed.");
52 | tseqEnum.MoveNext();
53 | }
54 | }
55 |
56 | public void TestStringOrderedSequence()
57 | {
58 | var os = new OrderedSequence(
59 | new Key(string.Empty, (s) => { return s; }));
60 |
61 | var src = new List
62 | {
63 | "zaz",
64 | "zab",
65 | "zah",
66 | "aaz",
67 | "abz",
68 | "acd",
69 | "eeh",
70 | "heh"
71 | };
72 |
73 | foreach (var s in src)
74 | os = os.Insert(s);
75 |
76 | var expected = new List
77 | {
78 | "aaz",
79 | "abz",
80 | "acd",
81 | "eeh",
82 | "heh",
83 | "zab",
84 | "zah",
85 | "zaz",
86 | };
87 |
88 | var tseq = os.ToSequence();
89 |
90 | var tseqEnum = tseq.GetEnumerator();
91 | tseqEnum.MoveNext();
92 |
93 | foreach (var es in expected)
94 | {
95 | if(0 != es.CompareTo(tseqEnum.Current))
96 | throw new Exception("TestStringOrderedSequence failed.");
97 | tseqEnum.MoveNext();
98 | }
99 |
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/FingerTree.UnitTests/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace FingerTree.UnitTests
8 | {
9 | class Program
10 | {
11 | static void Main(string[] args)
12 | {
13 | var t1 = new OrderedSequenceUnitTests();
14 | t1.TestCharOrderedSequence();
15 | t1.TestStringOrderedSequence();
16 |
17 | Console.ReadKey();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/FingerTree.UnitTests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("FingerTree.UnitTests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("FingerTree.UnitTests")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("78137e75-6466-4eda-aacf-0ec4405741ca")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/FingerTree.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FingerTree", "FingerTree\FingerTree.csproj", "{51807875-B25D-4F87-8B8D-5100E5F26BAD}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestCollAndString", "TestDotNetCollection\TestCollAndString.csproj", "{CFBD54BD-4EDD-4793-8913-4611B3D33682}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FNSeq", "FNSeq\FNSeq.csproj", "{9CDD93A8-3350-4F13-A001-F640BF28B96D}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FingerTree.UnitTests", "FingerTree.UnitTests\FingerTree.UnitTests.csproj", "{78137E75-6466-4EDA-AACF-0EC4405741CA}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {51807875-B25D-4F87-8B8D-5100E5F26BAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {51807875-B25D-4F87-8B8D-5100E5F26BAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {51807875-B25D-4F87-8B8D-5100E5F26BAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {51807875-B25D-4F87-8B8D-5100E5F26BAD}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {CFBD54BD-4EDD-4793-8913-4611B3D33682}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {CFBD54BD-4EDD-4793-8913-4611B3D33682}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {CFBD54BD-4EDD-4793-8913-4611B3D33682}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {CFBD54BD-4EDD-4793-8913-4611B3D33682}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {9CDD93A8-3350-4F13-A001-F640BF28B96D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {9CDD93A8-3350-4F13-A001-F640BF28B96D}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {9CDD93A8-3350-4F13-A001-F640BF28B96D}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {9CDD93A8-3350-4F13-A001-F640BF28B96D}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {78137E75-6466-4EDA-AACF-0EC4405741CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {78137E75-6466-4EDA-AACF-0EC4405741CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {78137E75-6466-4EDA-AACF-0EC4405741CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {78137E75-6466-4EDA-AACF-0EC4405741CA}.Release|Any CPU.Build.0 = Release|Any CPU
36 | EndGlobalSection
37 | GlobalSection(SolutionProperties) = preSolution
38 | HideSolutionNode = FALSE
39 | EndGlobalSection
40 | EndGlobal
41 |
--------------------------------------------------------------------------------
/src/FingerTree/FingerTree.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace FingerTree
6 | {
7 | public abstract class FTree
8 | {
9 | public abstract FTree Push_Front(T t);
10 | public abstract FTree Push_Back(T t);
11 |
12 | public abstract IEnumerable ToSequence();
13 | public abstract IEnumerable ToSequenceR();
14 |
15 | public abstract ViewL LeftView();
16 | public abstract ViewR RightView();
17 |
18 | public abstract FTree Merge(FTree rightFT);
19 |
20 | public abstract FTree App2(List ts, FTree rightFT);
21 |
22 |
23 | public static FTree Create(List frontList, //may be empty!
24 | FTree> innerFT,
25 | Digit backDig
26 | )
27 | {
28 | if (frontList.Count > 0)
29 | return new DeepFTree(new Digit(frontList),
30 | innerFT,
31 | backDig
32 | );
33 | //else
34 |
35 | if (innerFT is EmptyFTree>)
36 | return FromSequence(backDig.digNodes);
37 |
38 | //else we must create a new intermediate tree
39 | var innerLeft = innerFT.LeftView();
40 |
41 | List newlstFront = innerLeft.head.theNodes;
42 |
43 | DeepFTree theNewDeepTree =
44 | new DeepFTree(new Digit(newlstFront),
45 | innerLeft.ftTail,
46 | backDig
47 | );
48 |
49 | return theNewDeepTree;
50 | }
51 |
52 | public static FTree CreateR(Digit frontDig,
53 | FTree> innerFT,
54 | List backList //may be empty!
55 | )
56 | {
57 | if (backList.Count > 0)
58 | return new DeepFTree(frontDig,
59 | innerFT,
60 | new Digit(backList)
61 | );
62 | //else
63 |
64 | if (innerFT is EmptyFTree>)
65 | return FromSequence(frontDig.digNodes);
66 |
67 | //else we must create a new intermediate tree
68 | var innerRight = innerFT.RightView();
69 |
70 | List newlstBack = innerRight.last.theNodes;
71 |
72 | DeepFTree theNewDeepTree =
73 | new DeepFTree(frontDig,
74 | innerRight.ftInit,
75 | new Digit(newlstBack)
76 | );
77 |
78 | return theNewDeepTree;
79 | }
80 |
81 | public static FTree FromSequence(IEnumerable sequence)
82 | {
83 | IEnumerator sequenceEnum = sequence.GetEnumerator();
84 |
85 | FTree ftResult = new EmptyFTree();
86 |
87 | while (sequenceEnum.MoveNext())
88 | {
89 | ftResult = ftResult.Push_Back(sequenceEnum.Current);
90 | }
91 |
92 | return ftResult;
93 | }
94 |
95 | public static List> ListOfNodes(List tList)
96 | {
97 | List> resultNodeList = new List>();
98 |
99 | Node nextNode = null;
100 |
101 | int tCount = tList.Count;
102 |
103 | if(tCount < 4)
104 | {
105 | nextNode = new Node(tList);
106 |
107 | resultNodeList.Add(nextNode);
108 |
109 | return resultNodeList;
110 | }
111 |
112 | //else
113 | List nextTList = new List(tList.GetRange(0,3));
114 | //tList.CopyTo(0, nextTList, 0, 3);
115 |
116 | nextNode = new Node(nextTList);
117 | resultNodeList.Add(nextNode);
118 |
119 | resultNodeList.AddRange(ListOfNodes(tList.GetRange(3, tCount-3)));
120 |
121 | return resultNodeList;
122 | }
123 |
124 | public class ViewL
125 | {
126 | public X head;
127 | public FTree ftTail;
128 |
129 | public ViewL(X head, FTree ftTail)
130 | {
131 | this.head = head;
132 | this.ftTail = ftTail;
133 | }
134 | }
135 |
136 | public class ViewR
137 | {
138 | public X last;
139 | public FTree ftInit;
140 |
141 | public ViewR(FTree ftInit, X last)
142 | {
143 | this.ftInit = ftInit;
144 | this.last = last;
145 | }
146 | }
147 |
148 | public class Digit
149 | {
150 | public List digNodes = new List(); // At most four elements in this list
151 |
152 | public Digit(U u1)
153 | {
154 | digNodes.Add(u1);
155 | }
156 |
157 | public Digit(U u1, U u2)
158 | {
159 | digNodes.Add(u1);
160 | digNodes.Add(u2);
161 | }
162 | public Digit(U u1, U u2, U u3)
163 | {
164 | digNodes.Add(u1);
165 | digNodes.Add(u2);
166 | digNodes.Add(u3);
167 | }
168 | public Digit(U u1, U u2, U u3, U u4)
169 | {
170 | digNodes.Add(u1);
171 | digNodes.Add(u2);
172 | digNodes.Add(u3);
173 | digNodes.Add(u4);
174 | }
175 |
176 | public Digit(List listU)
177 | {
178 | digNodes = listU;
179 | }
180 | }
181 |
182 |
183 | public class Node
184 | {
185 | public List theNodes = new List(); // 2 or 3 elements in this list
186 |
187 | public Node(V v1, V v2)
188 | {
189 | theNodes.Add(v1);
190 | theNodes.Add(v2);
191 | }
192 |
193 | public Node(V v1, V v2, V v3)
194 | {
195 | theNodes.Add(v1);
196 | theNodes.Add(v2);
197 | theNodes.Add(v3);
198 | }
199 |
200 | public Node(List listV)
201 | {
202 | theNodes = listV;
203 | }
204 | }
205 |
206 |
207 |
208 | }
209 |
210 | public class EmptyFTree : FTree
211 | {
212 | public EmptyFTree() { }
213 |
214 | public override FTree Push_Front(T t)
215 | {
216 | return new SingleFTree(t);
217 | }
218 |
219 | public override FTree Push_Back(T t)
220 | {
221 | return new SingleFTree(t);
222 | }
223 |
224 | public override IEnumerable ToSequence()
225 | {
226 | return new List();
227 | }
228 |
229 | public override IEnumerable ToSequenceR()
230 | {
231 | return new List();
232 | }
233 |
234 | public override ViewL LeftView()
235 | {
236 | return null;
237 | }
238 |
239 | public override ViewR RightView()
240 | {
241 | return null;
242 | }
243 |
244 | public override FTree App2(List ts, FTree rightFT)
245 | {
246 | FTree resultFT = rightFT;
247 |
248 | for(int i = ts.Count -1; i >= 0; i--)
249 | {
250 | resultFT = resultFT.Push_Front(ts[i]);
251 | }
252 |
253 | return resultFT;
254 | }
255 |
256 | public override FTree Merge(FTree rightFT)
257 | {
258 | return rightFT;
259 | }
260 |
261 |
262 | }
263 |
264 | public class SingleFTree : FTree
265 | {
266 | protected T theSingle;
267 | public SingleFTree(T t)
268 | {
269 | theSingle = t;
270 | }
271 |
272 | public override FTree Push_Front(T t)
273 | {
274 | return new DeepFTree(new Digit(t),
275 | new EmptyFTree>(),
276 | new Digit(theSingle)
277 | );
278 | }
279 |
280 | public override FTree Push_Back(T t)
281 | {
282 | return new DeepFTree(new Digit(theSingle),
283 | new EmptyFTree>(),
284 | new Digit(t)
285 | );
286 | }
287 |
288 | public override IEnumerable ToSequence()
289 | {
290 | List newL = new List();
291 | newL.Add(theSingle);
292 | return newL;
293 | }
294 |
295 | public override IEnumerable ToSequenceR()
296 | {
297 | List newR = new List();
298 | newR.Add(theSingle);
299 | return newR;
300 | }
301 |
302 | public override ViewL LeftView()
303 | {
304 | return new ViewL(theSingle, new EmptyFTree());
305 | }
306 |
307 | public override ViewR RightView()
308 | {
309 | return new ViewR(new EmptyFTree(), theSingle);
310 | }
311 |
312 | public override FTree App2(List ts, FTree rightFT)
313 | {
314 | FTree resultFT = rightFT;
315 |
316 | for (int i = ts.Count - 1; i >= 0; i--)
317 | {
318 | resultFT = resultFT.Push_Front(ts[i]);
319 | }
320 |
321 | return resultFT.Push_Front(theSingle);
322 | }
323 |
324 | public override FTree Merge(FTree rightFT)
325 | {
326 | return rightFT.Push_Front(theSingle);
327 | }
328 |
329 |
330 | }
331 |
332 | public class DeepFTree : FTree
333 | {
334 | protected Digit frontDig;
335 | protected FTree> innerFT;
336 | protected Digit backDig;
337 |
338 | public DeepFTree(Digit frontDig, FTree> innerFT, Digit backDig)
339 | {
340 | if (frontDig.digNodes.Count > 0)
341 | {
342 | this.frontDig = frontDig;
343 | this.innerFT = innerFT;
344 | this.backDig = backDig;
345 | }
346 | else
347 | {
348 | throw new Exception("The DeepFTree() constructor is passed an empty frontDig !");
349 | }
350 |
351 | }
352 |
353 | public override ViewL LeftView()
354 | {
355 | T head = frontDig.digNodes[0];
356 |
357 | List newFront = new List(frontDig.digNodes);
358 | newFront.RemoveAt(0);
359 |
360 | return new ViewL(head,
361 | FTree.Create(newFront, innerFT, backDig)
362 | //new DeepFTree(newDigs, innerFT, backDig)
363 | );
364 | }
365 |
366 | public override ViewR RightView()
367 | {
368 | int lastIndex = backDig.digNodes.Count - 1;
369 | T last = backDig.digNodes[lastIndex];
370 |
371 | List newBack = new List(backDig.digNodes);
372 | newBack.RemoveAt(lastIndex);
373 |
374 | return new ViewR(FTree.CreateR(frontDig, innerFT, newBack),
375 | last
376 | );
377 | }
378 |
379 | public override FTree Push_Front(T t)
380 | {
381 | if (frontDig.digNodes.Count == 4)
382 | {
383 | List newFront = new List(frontDig.digNodes);
384 | newFront.RemoveAt(0);
385 |
386 | return new DeepFTree(new Digit(t, frontDig.digNodes[0]),
387 | innerFT.Push_Front(new Node(newFront)),
388 | backDig
389 | );
390 | }
391 | else //less than three digits in front -- will accomodate one more
392 | {
393 | List newFront = new List(frontDig.digNodes);
394 | newFront.Insert(0, t);
395 |
396 | return new DeepFTree(new Digit(newFront), innerFT, backDig);
397 | }
398 | }
399 |
400 | public override FTree Push_Back(T t)
401 | {
402 | int cntbackDig = backDig.digNodes.Count;
403 |
404 |
405 | if (backDig.digNodes.Count == 4)
406 | {
407 | List newBack = new List(backDig.digNodes);
408 | newBack.RemoveAt(cntbackDig - 1);
409 |
410 | return new DeepFTree
411 | (frontDig,
412 | innerFT.Push_Back(new Node(newBack)),
413 | new Digit(backDig.digNodes[cntbackDig - 1], t)
414 | );
415 |
416 | }
417 | else //less than three digits at the back -- will accomodate one more
418 | {
419 | List newBack = new List(backDig.digNodes);
420 | newBack.Add(t);
421 |
422 | return new DeepFTree(frontDig, innerFT, new Digit(newBack));
423 | }
424 |
425 | }
426 |
427 |
428 |
429 | public override IEnumerable ToSequence()
430 | {
431 | ViewL lView = LeftView();
432 |
433 | yield return lView.head;
434 |
435 | foreach (T t in lView.ftTail.ToSequence())
436 | yield return t;
437 | }
438 |
439 | public override IEnumerable ToSequenceR()
440 | {
441 | ViewR rView = RightView();
442 |
443 | yield return rView.last;
444 |
445 | foreach (T t in rView.ftInit.ToSequenceR())
446 | yield return t;
447 | }
448 |
449 | public override FTree App2(List ts, FTree rightFT)
450 | {
451 | if (! (rightFT is DeepFTree))
452 | {
453 | FTree resultFT = this;
454 |
455 | foreach (T t in ts)
456 | {
457 | resultFT = resultFT.Push_Back(t);
458 | }
459 |
460 | return (rightFT is EmptyFTree)
461 | ? resultFT
462 | : resultFT.Push_Back(rightFT.LeftView().head);
463 | }
464 | else // the right tree is also a deep tree
465 | {
466 | DeepFTree deepRight = rightFT as DeepFTree;
467 |
468 | List cmbList = new List(backDig.digNodes);
469 |
470 | cmbList.AddRange(ts);
471 |
472 | cmbList.AddRange(deepRight.frontDig.digNodes);
473 |
474 | FTree resultFT =
475 | new DeepFTree