1: using System;
2: using System.Collections.Generic;
3: using System.Diagnostics;
4:
5: /// <summary>
6: /// Extension methods for binary search
7: /// </summary>
8: public static class BinarySearchExt
9: {
10: #region Recursive only approach
11:
12: public static int BinSearch3<T>(this List<T> list, T key, bool sortRequired = false)
13: {
14: Comparer<T> comparer = Comparer<T>.Default;
15:
16: return BinSearch3<T>(list, key, comparer, sortRequired);
17: }
18:
19: public static int BinSearch3<T>(this List<T> list, T key, IComparer<T> comparer, bool sortRequired = false)
20: {
21: if (sortRequired)
22: {
23: list.Sort(comparer);
24: }
25:
26: // Invoked with the initial low and high values of 0 and N-1.
27: return BinarySearchHelper<T>(list, comparer, key, 0, list.Count - 1);
28: }
29:
30: /// <summary>
31: /// Binary search finds item in sorted ArrayList, Recursive method.
32: /// </summary>
33: /// <typeparam name="T"></typeparam>
34: /// <param name="list"></param>
35: /// <param name="comparer"></param>
36: /// <param name="key"></param>
37: /// <param name="lowerBound"></param>
38: /// <param name="upperBound"></param>
39: /// <returns></returns>
40: private static int BinarySearchHelper<T>(List<T> list,
41: IComparer<T> comparer,
42: T key,
43: int lowerBound,
44: int upperBound)
45: {
46: // check bounds
47: if (lowerBound > upperBound || lowerBound < 0)
48: {
49: return -1; // return not found
50: }
51:
52: // the middle index
53: int middle = (lowerBound + upperBound) / 2;
54:
55: // base condition
56: if (comparer.Compare(list[middle], key) == 0)
57: {
58: return middle; // we have found the index to the key, return it
59: }
60: // divide & conquer, the range
61: else if (comparer.Compare(list[middle], key) < 0) // key is in the upper half
62: {
63: return BinarySearchHelper<T>(list, comparer, key, middle + 1, upperBound);
64: }
65: else // if (comparer.Compare(list[middle], key) > 0) // key is in the lower half
66: {
67: return BinarySearchHelper<T>(list, comparer, key, lowerBound, middle - 1);
68: }
69: }
70:
71: #endregion
72:
73: #region Recursive & Functional/Lambda approach - 1
74:
75: public delegate int SearchDelegate<in TArgs>(TArgs arg, int lowerBound, int upperBound);
76:
77: public static int BinSearch2<T>(this List<T> list, T key, bool sortRequired = false)
78: {
79: Comparer<T> comparer = Comparer<T>.Default;
80:
81: return BinSearch2(list, key, comparer, sortRequired);
82: }
83:
84: // Recursive delegates approach, list has to be ordered/sorted
85: public static int BinSearch2<T>(this List<T> list, T key, IComparer<T> comparer, bool sortRequired = false)
86: {
87: if (sortRequired)
88: {
89: list.Sort(comparer);
90: }
91:
92: SearchDelegate<T> searchFunc = null;
93:
94: searchFunc = (xkey, lowerBound, upperBound) =>
95: {
96: // check bounds
97: if (lowerBound > upperBound || lowerBound < 0)
98: {
99: return -1; // return not found
100: }
101:
102: // the middle index
103: int middle = (lowerBound + upperBound) / 2;
104:
105: // base condition, stack un-wind
106: if (comparer.Compare(list[middle], xkey) == 0)
107: {
108: return middle; // we have found the index to the key, return it
109: }
110: else if (comparer.Compare(list[middle], xkey) < 0) // key is in the upper half
111: {
112: return searchFunc(xkey, middle + 1, upperBound);
113: }
114: else // if (comparer.Compare(list[middle], xkey) > 0) // key is in the lower half
115: {
116: return searchFunc(xkey, lowerBound, middle - 1);
117: }
118:
119: };
120:
121: // Invoked with the initial low and high values of 0 and N-1.
122: return searchFunc(key, 0, list.Count - 1);
123: }
124:
125: #endregion
126:
127: #region Recursive & Functional/lambda approach - 2
128:
129: public delegate int RecursiveDelegate<TArgs>(RecursiveDelegate<TArgs> func, TArgs arg, int lowerBound, int upperBound);
130:
131: public static int BinSearch<T>(this List<T> list, T key, bool sortRequired = false)
132: {
133: Comparer<T> comparer = Comparer<T>.Default;
134:
135: return BinSearch(list, key, comparer);
136: }
137:
138: /// <summary>
139: /// Functional & Recursive delegates approach, list has to be ordered/sorted
140: /// </summary>
141: /// <typeparam name="T"></typeparam>
142: /// <param name="list"></param>
143: /// <param name="key"></param>
144: /// <param name="comparer"></param>
145: /// <returns></returns>
146: public static int BinSearch<T>(this List<T> list, T key, IComparer<T> comparer, bool sortRequired = false)
147: {
148: if (sortRequired)
149: {
150: list.Sort(comparer);
151: }
152:
153: RecursiveDelegate<T> searchFunc = (func, xkey, lowerBound, upperBound) =>
154: {
155: // check bounds
156: if (lowerBound > upperBound || lowerBound < 0)
157: {
158: return -1; // return not found
159: }
160:
161: // the middle index
162: int middle = (lowerBound + upperBound) / 2;
163:
164: Debug.WriteLine(middle + ", " + list[middle]);
165:
166: // base condition, stack un-wind
167: if (comparer.Compare(list[middle], xkey) == 0)
168: {
169: return middle; // we have found the index to the key, return it
170: }
171: else if (comparer.Compare(list[middle], xkey) < 0) // key is in the upper half
172: {
173: return func(func, xkey, middle + 1, upperBound);
174: }
175: else // if (comparer.Compare(list[middle], xkey) > 0) // key is in the lower half
176: {
177: return func(func, xkey, lowerBound, middle - 1);
178: }
179: };
180:
181: // Invoked/called with the initial low and high values of 0 and N-1.
182: return searchFunc(searchFunc, key, 0, list.Count - 1);
183: }
184:
185:
186: public static int BinSearchX<T>(this List<T> list, T key, bool sortRequired = false)
187: {
188: Comparer<T> comparer = Comparer<T>.Default;
189:
190: return BinSearchX(list, key, comparer);
191: }
192:
193: /// <summary>
194: /// Functional & Recursive delegates approach, list has to be ordered/sorted
195: /// </summary>
196: /// <typeparam name="T"></typeparam>
197: /// <param name="list"></param>
198: /// <param name="key"></param>
199: /// <param name="comparer"></param>
200: /// <param name="sortRequired"></param>
201: /// <returns></returns>
202: public static int BinSearchX<T>(this List<T> list, T key, IComparer<T> comparer, bool sortRequired = false)
203: {
204: if (sortRequired)
205: {
206: list.Sort(comparer);
207: }
208:
209: RecursiveDelegate<T> searchFunc = (func, xkey, lowerBound, upperBound) =>
210: {
211: // check bounds
212: if (lowerBound > upperBound || lowerBound < 0)
213: {
214: return -1; // return not found
215: }
216:
217: // the middle index
218: int middle = (lowerBound + upperBound) / 2;
219:
220: if (comparer.Compare(list[middle], xkey) < 0) // key is in the upper half
221: {
222: return func(func, xkey, middle + 1, upperBound);
223: }
224: else if (comparer.Compare(list[middle], xkey) > 0) // key is in the lower half
225: {
226: return func(func, xkey, lowerBound, middle - 1);
227: }
228: else
229: {
230: return middle; // base condition - we have found the index to the key, return it
231: }
232: };
233:
234: // Invoked/called with the initial low and high values of 0 and N-1.
235: return searchFunc(searchFunc, key, 0, list.Count - 1);
236: }
237:
238: #endregion
239: }