2 Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
3 Permission is hereby granted, free of charge, to any person obtaining a copy
4 of this software and associated documentation files (the "Software"), to deal
5 in the Software without restriction, including without limitation the rights
6 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 copies of the Software, and to permit persons to whom the Software is
8 furnished to do so, subject to the following conditions:
10 The above copyright notice and this permission notice shall be included in
11 all copies or substantial portions of the Software.
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 using System.Diagnostics;
23 using SCG = System.Collections.Generic;
27 /// A utility class with functions for sorting arrays with respect to an IComparer<T>
34 /// Sort part of array in place using IntroSort
36 /// <exception cref="ArgumentOutOfRangeException">If the <code>start</code>
37 /// and <code>count</code> arguments does not describe a valid range.</exception>
38 /// <param name="array">Array to sort</param>
39 /// <param name="start">Index of first position to sort</param>
40 /// <param name="count">Number of elements to sort</param>
41 /// <param name="comparer">IComparer<T> to sort by</param>
43 public static void IntroSort<T>(T[] array, int start, int count, SCG.IComparer<T> comparer)
45 if (start < 0 || count < 0 || start + count > array.Length)
46 throw new ArgumentOutOfRangeException();
47 new Sorter<T>(array, comparer).IntroSort(start, start + count);
51 /// Sort an array in place using IntroSort and default comparer
53 /// <exception cref="NotComparableException">If T is not comparable</exception>
54 /// <param name="array">Array to sort</param>
56 public static void IntroSort<T>(T[] array)
58 new Sorter<T>(array, Comparer<T>.Default).IntroSort(0, array.Length);
63 /// Sort part of array in place using Insertion Sort
65 /// <exception cref="ArgumentOutOfRangeException">If the <code>start</code>
66 /// and <code>count</code> arguments does not describe a valid range.</exception>
67 /// <param name="array">Array to sort</param>
68 /// <param name="start">Index of first position to sort</param>
69 /// <param name="count">Number of elements to sort</param>
70 /// <param name="comparer">IComparer<T> to sort by</param>
72 public static void InsertionSort<T>(T[] array, int start, int count, SCG.IComparer<T> comparer)
74 if (start < 0 || count < 0 || start + count > array.Length)
75 throw new ArgumentOutOfRangeException();
76 new Sorter<T>(array, comparer).InsertionSort(start, start + count);
81 /// Sort part of array in place using Heap Sort
83 /// <exception cref="ArgumentOutOfRangeException">If the <code>start</code>
84 /// and <code>count</code> arguments does not describe a valid range.</exception>
85 /// <param name="array">Array to sort</param>
86 /// <param name="start">Index of first position to sort</param>
87 /// <param name="count">Number of elements to sort</param>
88 /// <param name="comparer">IComparer<T> to sort by</param>
90 public static void HeapSort<T>(T[] array, int start, int count, SCG.IComparer<T> comparer)
92 if (start < 0 || count < 0 || start + count > array.Length)
93 throw new ArgumentOutOfRangeException();
94 new Sorter<T>(array, comparer).HeapSort(start, start + count);
105 internal Sorter(T[] a, SCG.IComparer<T> c) { this.a = a; this.c = c; }
108 internal void IntroSort(int f, int b)
112 int depth_limit = (int)Math.Floor(2.5 * Math.Log(b - f, 2));
114 introSort(f, b, depth_limit);
121 private void introSort(int f, int b, int depth_limit)
123 const int size_threshold = 14;//24;
125 if (depth_limit-- == 0)
127 else if (b - f <= size_threshold)
131 int p = partition(f, b);
133 introSort(f, p, depth_limit);
134 introSort(p, b, depth_limit);
139 private int compare(T i1, T i2) { return c.Compare(i1, i2); }
142 private int partition(int f, int b)
144 int bot = f, mid = (b + f) / 2, top = b - 1;
145 T abot = a[bot], amid = a[mid], atop = a[top];
147 if (compare(abot, amid) < 0)
149 if (compare(atop, abot) < 0)//atop<abot<amid
150 { a[top] = amid; amid = a[mid] = abot; a[bot] = atop; }
151 else if (compare(atop, amid) < 0) //abot<=atop<amid
152 { a[top] = amid; amid = a[mid] = atop; }
153 //else abot<amid<=atop
157 if (compare(amid, atop) > 0) //atop<amid<=abot
158 { a[bot] = atop; a[top] = abot; }
159 else if (compare(abot, atop) > 0) //amid<=atop<abot
160 { a[bot] = amid; amid = a[mid] = atop; a[top] = abot; }
161 else //amid<=abot<=atop
162 { a[bot] = amid; amid = a[mid] = abot; }
165 int i = bot, j = top;
169 while (compare(a[++i], amid) < 0) ;
171 while (compare(amid, a[--j]) < 0) ;
175 T tmp = a[i]; a[i] = a[j]; a[j] = tmp;
183 internal void InsertionSort(int f, int b)
185 for (int j = f + 1; j < b; j++)
190 if (c.Compare(other = a[i], key) > 0)
193 while (i > f && c.Compare(other = a[i - 1], key) > 0) { a[i--] = other; }
201 internal void HeapSort(int f, int b)
203 for (int i = (b + f) / 2; i >= f; i--) heapify(f, b, i);
205 for (int i = b - 1; i > f; i--)
207 T tmp = a[f]; a[f] = a[i]; a[i] = tmp;
213 private void heapify(int f, int b, int i)
215 T pv = a[i], lv, rv, max = pv;
216 int j = i, maxpt = j;
220 int l = 2 * j - f + 1, r = l + 1;
222 if (l < b && compare(lv = a[l], max) > 0) { maxpt = l; max = lv; }
224 if (r < b && compare(rv = a[r], max) > 0) { maxpt = r; max = rv; }