private static void AssertQuickSortResult <TItem>(QuickselectSortOrder order, TItem[] items, int i, TItem result)
        {
            var cmp = Comparer <TItem> .Default;

            if (order == QuickselectSortOrder.Ascending)
            {
                var minimum = items.Skip(i).Min();
                foreach (var item in items.Take(i))
                {
                    cmp.Compare(item, minimum).Should().BeLessOrEqualTo(0);
                }

                cmp.Compare(minimum, result).Should().Be(0);
            }
            else
            {
                var maximum = items.Skip(i).Max();
                foreach (var item in items.Take(i))
                {
                    cmp.Compare(item, maximum).Should().BeGreaterOrEqualTo(0);
                }

                cmp.Compare(maximum, result).Should().Be(0);
            }
        }
        public void Should_work_in_trivial_cases(QuickselectSortOrder order)
        {
            var items = new [] { 1, 7, 4, 15, 34, -54, 5 };

            items.QuickSelect(0, order: order).Should().Be(order == QuickselectSortOrder.Ascending ? items.Min() : items.Max());
            items.QuickSelect(items.Length, order: order).Should().Be(order == QuickselectSortOrder.Ascending ? items.Max() : items.Min());
            items.QuickSelect(2, order: order).Should().Be(order == QuickselectSortOrder.Ascending ? 4 : 7);
        }
        public void Should_select_fast_on_sameData(QuickselectSortOrder order)
        {
            var itemsCount = 8000;
            var items      = Enumerable.Repeat(new string('c', 10), itemsCount).ToArray();
            var comparer   = new CountedComparer <string>(Comparer <string> .Default);
            var result     = items.QuickSelect(6000, order: order, comparer: comparer);

            comparer.Called.Should().BeLessThan(itemsCount * 7); // Avg Performace O(n)
            AssertQuickSortResult(order, items, 6000, result);
        }
        public void Should_select_fast_on_similarData(QuickselectSortOrder order)
        {
            var itemsCount = 800;
            var items      = new[] { "c", "a", "b", "zf", "e", "f", "w", "we", "z", "gg" }
            .SelectMany(prefix => Enumerable.Repeat(prefix + new string('c', 10), itemsCount))
            .ToArray();
            var comparer = new CountedComparer <string>(Comparer <string> .Default);
            var result   = items.QuickSelect(6000, order: order, comparer: comparer);

            comparer.Called.Should().BeLessThan(items.Length * 7); // Avg Performace O(n)
            AssertQuickSortResult(order, items, 6000, result);
        }
示例#5
0
        private static int IndexOfMin <T>(this T[] list, IComparer <T> comparer, QuickselectSortOrder order)
        {
            var minIndex = 0;

            for (var i = 0; i < list.Length; i++)
            {
                if (comparer.CompareWithOrder(list[i], list[minIndex], order) < 0)
                {
                    minIndex = i;
                }
            }
            return(minIndex);
        }
        public void Should_move_top_items_to_the_beginning_of_given_array(QuickselectSortOrder order)
        {
            var random = new Random();

            var itemsCount = random.Next(100, 200);
            var items      = new int[itemsCount];

            for (var i = 1; i <= itemsCount - 1; i++)
            {
                for (var j = 0; j < itemsCount; j++)
                {
                    items[j] = random.Next(10);
                }

                var result = items.QuickSelect(i, order: order);
                AssertQuickSortResult(order, items, i, result);
            }
        }
示例#7
0
        private static int Partition <T>(this T[] list, int startIndex, int endIndex, int pivotIndex, IComparer <T> comparer, QuickselectSortOrder order)
        {
            Swap(list, pivotIndex, startIndex);

            var pivot = list[startIndex];
            var i     = startIndex;
            var j     = endIndex + 1;

            while (true)
            {
                do
                {
                    i++;
                } while (i <= endIndex && comparer.CompareWithOrder(list[i], pivot, order) < 0);

                do
                {
                    j--;
                } while (comparer.CompareWithOrder(list[j], pivot, order) > 0);

                if (i >= j)
                {
                    Swap(list, startIndex, j);
                    return(j);
                }

                Swap(list, i, j);
            }
        }
示例#8
0
 private static int CompareWithOrder <T>(this IComparer <T> comparer, T first, T second, QuickselectSortOrder order)
 => comparer.Compare(first, second) * (int)order;
示例#9
0
        public static T QuickSelect <T>(this T[] list, int top, IComparer <T> comparer = null, QuickselectSortOrder order = QuickselectSortOrder.Ascending)
        {
            if (top > list.Length || list.Length == 0)
            {
                throw new InvalidOperationException($"Requested to select top {top} items from array with size {list.Length}.");
            }

            if (comparer == null)
            {
                comparer = Comparer <T> .Default;
            }

            if (top == list.Length)
            {
                list.Swap(list.IndexOfMax(comparer, order), top - 1);
                return(list[top - 1]);
            }

            if (top <= 0)
            {
                list.Swap(list.IndexOfMin(comparer, order), 0);
                return(list[0]);
            }

            var startIndex = 0;
            var endIndex   = list.Length - 1;
            var pivotIndex = top;

            while (endIndex > startIndex)
            {
                pivotIndex = list.Partition(startIndex, endIndex, pivotIndex, comparer, order);

                if (pivotIndex == top)
                {
                    break;
                }

                if (pivotIndex > top)
                {
                    endIndex = pivotIndex - 1;
                }
                else
                {
                    startIndex = pivotIndex + 1;
                }

                pivotIndex = Next(startIndex, endIndex);
            }

            return(list[pivotIndex]);
        }
示例#10
0
 private static int IndexOfMax <T>(this T[] list, IComparer <T> comparer, QuickselectSortOrder order)
 => list.IndexOfMin(comparer, (QuickselectSortOrder)((int)order * -1));