1 /* https://github.com/mbuchetics/RangeTree よりコピペ。このファイルのみMITライセンスに従います */
3 using System.Collections.Generic;
5 namespace FooEditEngine
8 /// A node of the range tree. Given a list of items, it builds
9 /// its subtree. Also contains methods to query the subtree.
10 /// Basically, all interval tree logic is here.
12 sealed class RangeTreeNode<TKey, T>
13 where TKey : IComparable<TKey>
14 where T : IRangeProvider<TKey>
17 private RangeTreeNode<TKey, T> _leftNode;
18 private RangeTreeNode<TKey, T> _rightNode;
19 private List<T> _items;
21 private static IComparer<T> s_rangeComparer;
24 /// Initializes an empty node.
26 /// <param name="rangeComparer">The comparer used to compare two items.</param>
27 public RangeTreeNode(IComparer<T> rangeComparer = null)
29 if (rangeComparer != null)
30 s_rangeComparer = rangeComparer;
32 _center = default(TKey);
39 /// Initializes a node with a list of items, builds the sub tree.
41 /// <param name="items">The itme is added</param>
42 /// <param name="rangeComparer">The comparer used to compare two items.</param>
43 public RangeTreeNode(IEnumerable<T> items, IComparer<T> rangeComparer = null)
45 if (rangeComparer != null)
46 s_rangeComparer = rangeComparer;
48 // first, find the median
49 var endPoints = new List<TKey>();
50 foreach (var o in items)
53 endPoints.Add(range.From);
54 endPoints.Add(range.To);
58 // the median is used as center value
59 _center = endPoints[endPoints.Count / 2];
60 _items = new List<T>();
62 var left = new List<T>();
63 var right = new List<T>();
65 // iterate over all items
66 // if the range of an item is completely left of the center, add it to the left items
67 // if it is on the right of the center, add it to the right items
68 // otherwise (range overlaps the center), add the item to this node's items
69 foreach (var o in items)
73 if (range.To.CompareTo(_center) < 0)
75 else if (range.From.CompareTo(_center) > 0)
81 // sort the items, this way the query is faster later on
83 _items.Sort(s_rangeComparer);
87 // create left and right nodes, if there are any items
89 _leftNode = new RangeTreeNode<TKey, T>(left);
91 _rightNode = new RangeTreeNode<TKey, T>(right);
95 /// Performans a "stab" query with a single value.
96 /// All items with overlapping ranges are returned.
98 public List<T> Query(TKey value)
100 var results = new List<T>();
102 // If the node has items, check their ranges.
105 foreach (var o in _items)
107 if (o.Range.From.CompareTo(value) > 0)
109 else if (o.Range.Contains(value))
114 // go to the left or go to the right of the tree, depending
115 // where the query value lies compared to the center
116 if (value.CompareTo(_center) < 0 && _leftNode != null)
117 results.AddRange(_leftNode.Query(value));
118 else if (value.CompareTo(_center) > 0 && _rightNode != null)
119 results.AddRange(_rightNode.Query(value));
125 /// Performans a range query.
126 /// All items with overlapping ranges are returned.
128 public List<T> Query(Range<TKey> range)
130 var results = new List<T>();
132 // If the node has items, check their ranges.
135 foreach (var o in _items)
137 if (o.Range.From.CompareTo(range.To) > 0)
139 else if (o.Range.Intersects(range))
144 // go to the left or go to the right of the tree, depending
145 // where the query value lies compared to the center
146 if (range.From.CompareTo(_center) < 0 && _leftNode != null)
147 results.AddRange(_leftNode.Query(range));
148 if (range.To.CompareTo(_center) > 0 && _rightNode != null)
149 results.AddRange(_rightNode.Query(range));