#region Copyright 2012-2014 by Roger Knapp, Licensed under the Apache License, Version 2.0 /* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #endregion using System; using System.Collections.Generic; namespace CSharpTest.Net.Collections { /// /// Provides a stable array sort based on merge-sort using O(n) additional memory. As a release build, /// this routine will operate faster than Array.Sort when using a custom (non-default) comparison. It /// also has the advantange of being stable, that is it preserves the order of elements that compare as /// being of equal value. /// public static class MergeSort { /// Sorts the contents of the array using a stable merge-sort with O(n) additional memory public static void Sort(T[] list) { T[] clone = (T[])list.Clone(); Sort(clone, list, 0, list.Length, Comparer.Default); } /// Sorts the contents of the array using a stable merge-sort with O(n) additional memory /// This overload also yields the working copy of the array which is unsorted. internal static void Sort(T[] list, out T[] working, int offset, int count, IComparer compare) { working = (T[])list.Clone(); Sort(working, list, offset, count, compare); } /// Sorts the contents of the array using a stable merge-sort with O(n) additional memory public static void Sort(T[] list, IComparer compare) { T[] clone = (T[])list.Clone(); Sort(clone, list, 0, list.Length, compare); } /// Sorts the contents of the array using a stable merge-sort with O(n) additional memory public static void Sort(T[] list, int offset, int count, IComparer compare) { T[] clone = (T[])list.Clone(); Sort(clone, list, offset, count, compare); } /// Sorts the contents of the array using a stable merge-sort with O(n) additional memory public static void Sort(T[] list, Comparison compare) { T[] clone = (T[])list.Clone(); Sort(clone, list, 0, list.Length, new ByComparison(compare)); } /// Sorts the contents of the array using a stable merge-sort with O(n) additional memory public static void Sort(T[] list, int offset, int count, Comparison compare) { T[] clone = (T[])list.Clone(); Sort(clone, list, offset, count, new ByComparison(compare)); } class ByComparison : IComparer { private readonly Comparison _compare; public ByComparison(Comparison compare) { _compare = compare; } public int Compare(T x, T y) { return _compare(x, y); } } private static void Sort(T[] src, T[] dest, int offset, int count, IComparer compare) { if (count > 2) { int half = count >> 1; int c1 = half, c2 = count - half; Sort(dest, src, offset, c1, compare); Sort(dest, src, offset + half, c2, compare); c1 += offset; c2 += offset + half; for (int rix = offset, stop = offset + count, ix1 = offset, ix2 = offset + half; rix < stop; rix++) { dest[rix] = (ix1 < c1 && (ix2 == c2 || compare.Compare(src[ix1], src[ix2]) <= 0)) ? src[ix1++] : src[ix2++]; } } else if (count == 1) dest[offset] = src[offset]; else if (count == 2) { if (compare.Compare(src[offset], src[offset + 1]) <= 0) { dest[offset] = src[offset]; dest[offset + 1] = src[offset + 1]; } else { dest[offset] = src[offset + 1]; dest[offset + 1] = src[offset]; } } } } }