LCOV - code coverage report
Current view: top level - collection-1.14.3/lib/src - algorithms.dart (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 0 94 0.0 %
Date: 2017-10-10 20:17:03 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
       2             : // for details. All rights reserved. Use of this source code is governed by a
       3             : // BSD-style license that can be found in the LICENSE file.
       4             : 
       5             : import "dart:math" as math;
       6             : 
       7             : import "utils.dart";
       8             : 
       9             : /// Returns a position of the [value] in [sortedList], if it is there.
      10             : ///
      11             : /// If the list isn't sorted according to the [compare] function, the result
      12             : /// is unpredictable.
      13             : ///
      14             : /// If [compare] is omitted, this defaults to calling [Comparable.compareTo] on
      15             : /// the objects. If any object is not [Comparable], this throws a [CastError].
      16             : ///
      17             : /// Returns -1 if [value] is not in the list by default.
      18             : int binarySearch<T>(List<T> sortedList, T value, {int compare(T a, T b)}) {
      19           0 :   compare ??= defaultCompare<T>();
      20             :   int min = 0;
      21           0 :   int max = sortedList.length;
      22           0 :   while (min < max) {
      23           0 :     int mid = min + ((max - min) >> 1);
      24           0 :     var element = sortedList[mid];
      25           0 :     int comp = compare(element, value);
      26           0 :     if (comp == 0) return mid;
      27           0 :     if (comp < 0) {
      28           0 :       min = mid + 1;
      29             :     } else {
      30             :       max = mid;
      31             :     }
      32             :   }
      33             :   return -1;
      34             : }
      35             : 
      36             : /// Returns the first position in [sortedList] that does not compare less than
      37             : /// [value].
      38             : ///
      39             : /// If the list isn't sorted according to the [compare] function, the result
      40             : /// is unpredictable.
      41             : ///
      42             : /// If [compare] is omitted, this defaults to calling [Comparable.compareTo] on
      43             : /// the objects. If any object is not [Comparable], this throws a [CastError].
      44             : ///
      45             : /// Returns [sortedList.length] if all the items in [sortedList] compare less
      46             : /// than [value].
      47             : int lowerBound<T>(List<T> sortedList, T value, {int compare(T a, T b)}) {
      48           0 :   compare ??= defaultCompare<T>();
      49             :   int min = 0;
      50           0 :   int max = sortedList.length;
      51           0 :   while (min < max) {
      52           0 :     int mid = min + ((max - min) >> 1);
      53           0 :     var element = sortedList[mid];
      54           0 :     int comp = compare(element, value);
      55           0 :     if (comp < 0) {
      56           0 :       min = mid + 1;
      57             :     } else {
      58             :       max = mid;
      59             :     }
      60             :   }
      61             :   return min;
      62             : }
      63             : 
      64             : /// Shuffles a list randomly.
      65             : ///
      66             : /// A sub-range of a list can be shuffled by providing [start] and [end].
      67             : void shuffle(List list, [int start = 0, int end = null]) {
      68           0 :   var random = new math.Random();
      69           0 :   if (end == null) end = list.length;
      70           0 :   int length = end - start;
      71           0 :   while (length > 1) {
      72           0 :     int pos = random.nextInt(length);
      73           0 :     length--;
      74           0 :     var tmp1 = list[start + pos];
      75           0 :     list[start + pos] = list[start + length];
      76           0 :     list[start + length] = tmp1;
      77             :   }
      78             : }
      79             : 
      80             : /// Reverses a list, or a part of a list, in-place.
      81             : void reverse(List list, [int start = 0, int end = null]) {
      82           0 :   if (end == null) end = list.length;
      83           0 :   _reverse(list, start, end);
      84             : }
      85             : 
      86             : /// Internal helper function that assumes valid arguments.
      87             : void _reverse(List list, int start, int end) {
      88           0 :   for (int i = start, j = end - 1; i < j; i++, j--) {
      89           0 :     var tmp = list[i];
      90           0 :     list[i] = list[j];
      91           0 :     list[j] = tmp;
      92             :   }
      93             : }
      94             : 
      95             : /// Sort a list between [start] (inclusive) and [end] (exclusive) using
      96             : /// insertion sort.
      97             : ///
      98             : /// If [compare] is omitted, this defaults to calling [Comparable.compareTo] on
      99             : /// the objects. If any object is not [Comparable], this throws a [CastError].
     100             : ///
     101             : /// Insertion sort is a simple sorting algorithm. For `n` elements it does on
     102             : /// the order of `n * log(n)` comparisons but up to `n` squared moves. The
     103             : /// sorting is performed in-place, without using extra memory.
     104             : ///
     105             : /// For short lists the many moves have less impact than the simple algorithm,
     106             : /// and it is often the favored sorting algorithm for short lists.
     107             : ///
     108             : /// This insertion sort is stable: Equal elements end up in the same order
     109             : /// as they started in.
     110             : void insertionSort<T>(List<T> list,
     111             :     {int compare(T a, T b), int start: 0, int end}) {
     112             :   // If the same method could have both positional and named optional
     113             :   // parameters, this should be (list, [start, end], {compare}).
     114           0 :   compare ??= defaultCompare<T>();
     115           0 :   end ??= list.length;
     116             : 
     117           0 :   for (int pos = start + 1; pos < end; pos++) {
     118             :     int min = start;
     119             :     int max = pos;
     120           0 :     var element = list[pos];
     121           0 :     while (min < max) {
     122           0 :       int mid = min + ((max - min) >> 1);
     123           0 :       int comparison = compare(element, list[mid]);
     124           0 :       if (comparison < 0) {
     125             :         max = mid;
     126             :       } else {
     127           0 :         min = mid + 1;
     128             :       }
     129             :     }
     130           0 :     list.setRange(min + 1, pos + 1, list, min);
     131           0 :     list[min] = element;
     132             :   }
     133             : }
     134             : 
     135             : /// Limit below which merge sort defaults to insertion sort.
     136             : const int _MERGE_SORT_LIMIT = 32;
     137             : 
     138             : /// Sorts a list between [start] (inclusive) and [end] (exclusive) using the
     139             : /// merge sort algorithm.
     140             : ///
     141             : /// If [compare] is omitted, this defaults to calling [Comparable.compareTo] on
     142             : /// the objects. If any object is not [Comparable], this throws a [CastError].
     143             : ///
     144             : /// Merge-sorting works by splitting the job into two parts, sorting each
     145             : /// recursively, and then merging the two sorted parts.
     146             : ///
     147             : /// This takes on the order of `n * log(n)` comparisons and moves to sort
     148             : /// `n` elements, but requires extra space of about the same size as the list
     149             : /// being sorted.
     150             : ///
     151             : /// This merge sort is stable: Equal elements end up in the same order
     152             : /// as they started in.
     153             : void mergeSort<T>(List<T> list,
     154             :     {int start: 0, int end, int compare(T a, T b)}) {
     155           0 :   end ??= list.length;
     156           0 :   compare ??= defaultCompare<T>();
     157             : 
     158           0 :   int length = end - start;
     159           0 :   if (length < 2) return;
     160           0 :   if (length < _MERGE_SORT_LIMIT) {
     161           0 :     insertionSort(list, compare: compare, start: start, end: end);
     162             :     return;
     163             :   }
     164             :   // Special case the first split instead of directly calling
     165             :   // _mergeSort, because the _mergeSort requires its target to
     166             :   // be different from its source, and it requires extra space
     167             :   // of the same size as the list to sort.
     168             :   // This split allows us to have only half as much extra space,
     169             :   // and it ends up in the original place.
     170           0 :   int middle = start + ((end - start) >> 1);
     171           0 :   int firstLength = middle - start;
     172           0 :   int secondLength = end - middle;
     173             :   // secondLength is always the same as firstLength, or one greater.
     174           0 :   var scratchSpace = new List<T>(secondLength);
     175           0 :   _mergeSort(list, compare, middle, end, scratchSpace, 0);
     176           0 :   int firstTarget = end - firstLength;
     177           0 :   _mergeSort(list, compare, start, middle, list, firstTarget);
     178           0 :   _merge(compare, list, firstTarget, end, scratchSpace, 0, secondLength, list,
     179             :       start);
     180             : }
     181             : 
     182             : /// Performs an insertion sort into a potentially different list than the
     183             : /// one containing the original values.
     184             : ///
     185             : /// It will work in-place as well.
     186             : void _movingInsertionSort<T>(List<T> list, int compare(T a, T b), int start,
     187             :     int end, List<T> target, int targetOffset) {
     188           0 :   int length = end - start;
     189           0 :   if (length == 0) return;
     190           0 :   target[targetOffset] = list[start];
     191           0 :   for (int i = 1; i < length; i++) {
     192           0 :     var element = list[start + i];
     193             :     int min = targetOffset;
     194           0 :     int max = targetOffset + i;
     195           0 :     while (min < max) {
     196           0 :       int mid = min + ((max - min) >> 1);
     197           0 :       if (compare(element, target[mid]) < 0) {
     198             :         max = mid;
     199             :       } else {
     200           0 :         min = mid + 1;
     201             :       }
     202             :     }
     203           0 :     target.setRange(min + 1, targetOffset + i + 1, target, min);
     204           0 :     target[min] = element;
     205             :   }
     206             : }
     207             : 
     208             : /// Sorts [list] from [start] to [end] into [target] at [targetOffset].
     209             : ///
     210             : /// The `target` list must be able to contain the range from `start` to `end`
     211             : /// after `targetOffset`.
     212             : ///
     213             : /// Allows target to be the same list as [list], as long as it's not
     214             : /// overlapping the `start..end` range.
     215             : void _mergeSort<T>(List<T> list, int compare(T a, T b), int start, int end,
     216             :     List<T> target, int targetOffset) {
     217           0 :   int length = end - start;
     218           0 :   if (length < _MERGE_SORT_LIMIT) {
     219           0 :     _movingInsertionSort(list, compare, start, end, target, targetOffset);
     220             :     return;
     221             :   }
     222           0 :   int middle = start + (length >> 1);
     223           0 :   int firstLength = middle - start;
     224           0 :   int secondLength = end - middle;
     225             :   // Here secondLength >= firstLength (differs by at most one).
     226           0 :   int targetMiddle = targetOffset + firstLength;
     227             :   // Sort the second half into the end of the target area.
     228           0 :   _mergeSort(list, compare, middle, end, target, targetMiddle);
     229             :   // Sort the first half into the end of the source area.
     230           0 :   _mergeSort(list, compare, start, middle, list, middle);
     231             :   // Merge the two parts into the target area.
     232           0 :   _merge(compare, list, middle, middle + firstLength, target, targetMiddle,
     233           0 :       targetMiddle + secondLength, target, targetOffset);
     234             : }
     235             : 
     236             : /// Merges two lists into a target list.
     237             : ///
     238             : /// One of the input lists may be positioned at the end of the target
     239             : /// list.
     240             : ///
     241             : /// For equal object, elements from [firstList] are always preferred.
     242             : /// This allows the merge to be stable if the first list contains elements
     243             : /// that started out earlier than the ones in [secondList]
     244             : void _merge<T>(
     245             :     int compare(T a, T b),
     246             :     List<T> firstList,
     247             :     int firstStart,
     248             :     int firstEnd,
     249             :     List<T> secondList,
     250             :     int secondStart,
     251             :     int secondEnd,
     252             :     List<T> target,
     253             :     int targetOffset) {
     254             :   // No empty lists reaches here.
     255             :   assert(firstStart < firstEnd);
     256             :   assert(secondStart < secondEnd);
     257             :   int cursor1 = firstStart;
     258             :   int cursor2 = secondStart;
     259           0 :   var firstElement = firstList[cursor1++];
     260           0 :   var secondElement = secondList[cursor2++];
     261             :   while (true) {
     262           0 :     if (compare(firstElement, secondElement) <= 0) {
     263           0 :       target[targetOffset++] = firstElement;
     264           0 :       if (cursor1 == firstEnd) break; // Flushing second list after loop.
     265           0 :       firstElement = firstList[cursor1++];
     266             :     } else {
     267           0 :       target[targetOffset++] = secondElement;
     268           0 :       if (cursor2 != secondEnd) {
     269           0 :         secondElement = secondList[cursor2++];
     270             :         continue;
     271             :       }
     272             :       // Second list empties first. Flushing first list here.
     273           0 :       target[targetOffset++] = firstElement;
     274           0 :       target.setRange(targetOffset, targetOffset + (firstEnd - cursor1),
     275             :           firstList, cursor1);
     276             :       return;
     277             :     }
     278             :   }
     279             :   // First list empties first. Reached by break above.
     280           0 :   target[targetOffset++] = secondElement;
     281           0 :   target.setRange(
     282           0 :       targetOffset, targetOffset + (secondEnd - cursor2), secondList, cursor2);
     283             : }

Generated by: LCOV version 1.13