private const int MaximumSectionCount = 128; // This is the maximum granularity for GetBestStartPoint private static ListSearchConfiguration UpdateListSearchConfiguration(IList list) { ListSearchConfiguration configuration = default(ListSearchConfiguration); if (list is Array) { configuration.LowerBound = ((Array)list).GetLowerBound(0); configuration.UpperBound = ((Array)list).GetUpperBound(0); } else { configuration.LowerBound = 0; configuration.UpperBound = list.Count - 1; } configuration.ListSize = list.Count; configuration.SectionSize = InitialSectionSize; while (configuration.SectionSize > 0 && (list.Count / configuration.SectionSize) > MaximumSectionCount) { configuration.SectionSize *= 2; } while (configuration.SectionSize > 0 && (list.Count / configuration.SectionSize) < 1) { configuration.SectionSize /= 2; } configuration.InitialCutSize = (configuration.SectionSize / 2); configuration.SectionCount = configuration.SectionSize > 0 ? (list.Count / configuration.SectionSize) : 0; return(configuration); }
public static int[] FindIndexBinary <T>(this IList list, T item, IComparer <T> comparer = null) { if (comparer == null) { comparer = Comparer <T> .Default; } ListSearchConfiguration configuration = default(ListSearchConfiguration); if (listSearchConfigCache.ContainsKey(list)) { configuration = listSearchConfigCache[list]; } if (configuration.ListSize == 0 || list.Count > configuration.SectionCount * configuration.SectionSize || Math.Abs(list.Count - configuration.ListSize) > configuration.SectionSize) { if (listSearchConfigCache.ContainsKey(list)) { listSearchConfigCache[list] = UpdateListSearchConfiguration(list); } else { listSearchConfigCache.Add(list, configuration = UpdateListSearchConfiguration(list)); } } if (list.Count == 0 || comparer.Compare(item, (T)list[configuration.LowerBound]) == -1) { return(new[] { -1, 0 }); } if (comparer.Compare(item, (T)list[configuration.UpperBound]) == 1) { return(new[] { configuration.UpperBound, configuration.UpperBound + 1 }); } return(FindIndexBinaryCore(list, item, comparer, configuration)); }
private static int GetBestStartPoint <T>(IList list, T item, IComparer <T> comparer, ListSearchConfiguration configuration) { int startPoint = configuration.UpperBound - configuration.InitialCutSize; for (int i = configuration.LowerBound; i <= configuration.UpperBound; i += configuration.SectionSize) { if (comparer.Compare(item, (T)list[i]) == -1) { startPoint = i - configuration.InitialCutSize; break; } } return(startPoint); }
private static int[] FindIndexBinaryCore <T>(IList list, T item, IComparer <T> comparer, ListSearchConfiguration configuration) { int startPoint = GetBestStartPoint(list, item, comparer, configuration); int[] result = { 0, startPoint }; int cutSize = configuration.InitialCutSize; int nextCompareResult = comparer.Compare(item, (T)list[result[1]]); while (true) { result[0] = result[1]; if (nextCompareResult == 0) { return(result); } if (cutSize > 1) { cutSize /= 2; } result[1] += cutSize * nextCompareResult; int compareResult = nextCompareResult; nextCompareResult = result[1] < configuration.LowerBound ? 1 : comparer.Compare(item, (T)list[result[1]]); if (compareResult == 1 && nextCompareResult == -1 && result[1] - result[0] == 1) { return(result); } } }