
Sorting Algorithm

This is a sorting algorithm.   It may be applied to a set of data in order to sort it.    
For comparing various sorts, see compare sorts.  
For other sorting algorithms,   see sorting algorithms,   or:

O(n logn) sorts
Heap sort |
Merge sort |
Patience sort |
Quick sort
O(n log2n) sorts
Shell Sort
O(n2) sorts
Bubble sort |
Cocktail sort |
Cocktail sort with shifting bounds |
Comb sort |
Cycle sort |
Gnome sort |
Insertion sort |
Selection sort |
Strand sort
other sorts
Bead sort |
Bogo sort |
Common sorted list |
Composite structures sort |
Custom comparator sort |
Counting sort |
Disjoint sublist sort |
External sort |
Jort sort |
Lexicographical sort |
Natural sorting |
Order by pair comparisons |
Order disjoint list items |
Order two numerical lists |
Object identifier (OID) sort |
Pancake sort |
Quickselect |
Permutation sort |
Radix sort |
Ranking methods |
Remove duplicate elements |
Sleep sort |
Stooge sort |
[Sort letters of a string] |
Three variable sort |
Topological sort |
Tree sort


Use the quickselect algorithm on the vector

 [9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
To show the first, second, third, ... up to the tenth largest member of the vector, in order, here on this page.

 Note: Quicksort has a separate task. 


// ----------------------------------------------------------------------------------------------
//  
//  Program.cs - QuickSelect
//  
// ----------------------------------------------------------------------------------------------
 
using System;
using System.Collections.Generic;
using System.Linq;
 
namespace QuickSelect
{
    internal static class Program
    {
        #region Static Members
 
        private static void Main()
        {
            var inputArray = new[] {9, 8, 7, 6, 5, 0, 1, 2, 3, 4};
            // Loop 10 times
            Console.WriteLine( "Loop quick select 10 times." );
            for( var i = 0 ; i < 10 ; i++ )
            {
                Console.Write( inputArray.NthSmallestElement( i ) );
                if( i < 9 )
                    Console.Write( ", " );
            }
            Console.WriteLine();
 
            // And here is then more effective way to get N smallest elements from vector in order by using quick select algorithm
            // Basically we are here just sorting array (taking 10 smallest from array which length is 10)
            Console.WriteLine( "Just sort 10 elements." );
            Console.WriteLine( string.Join( ", ", inputArray.TakeSmallest( 10 ).OrderBy( v => v ).Select( v => v.ToString() ).ToArray() ) );
            // Here we are actually doing quick select once by taking only 4 smallest from array. 
            Console.WriteLine( "Get 4 smallest and sort them." );
            Console.WriteLine( string.Join( ", ", inputArray.TakeSmallest( 4 ).OrderBy( v => v ).Select( v => v.ToString() ).ToArray() ) );
            Console.WriteLine( "< Press any key >" );
            Console.ReadKey();
        }
 
        #endregion
    }
 
    internal static class ArrayExtension
    {
        #region Static Members
 
        /// <summary>
        ///  Return specified number of smallest elements from array.
        /// </summary>
        /// <typeparam name="T">The type of the elements of array. Type must implement IComparable(T) interface.</typeparam>
        /// <param name="array">The array to return elemnts from.</param>
        /// <param name="count">The number of smallest elements to return. </param>
        /// <returns>An IEnumerable(T) that contains the specified number of smallest elements of the input array. Returned elements are NOT sorted.</returns>
        public static IEnumerable<T> TakeSmallest<T>( this T[] array, int count ) where T : IComparable<T>
        {
            if( count < 0 )
                throw new ArgumentOutOfRangeException( "count", "Count is smaller than 0." );
            if( count == 0 )
                return new T[0];
            if( array.Length <= count )
                return array;
 
            return QuickSelectSmallest( array, count - 1 ).Take( count );
        }
 
        /// <summary>
        /// Returns N:th smallest element from the array.
        /// </summary>
        /// <typeparam name="T">The type of the elements of array. Type must implement IComparable(T) interface.</typeparam>
        /// <param name="array">The array to return elemnt from.</param>
        /// <param name="n">Nth element. 0 is smallest element, when array.Length - 1 is largest element.</param>
        /// <returns>N:th smalles element from the array.</returns>
        public static T NthSmallestElement<T>( this T[] array, int n ) where T : IComparable<T>
        {
            if( n < 0 || n > array.Length - 1 )
                throw new ArgumentOutOfRangeException( "n", n, string.Format( "n should be between 0 and {0} it was {1}.", array.Length - 1, n ) );
            if( array.Length == 0 )
                throw new ArgumentException( "Array is empty.", "array" );
            if( array.Length == 1 )
                return array[ 0 ];
 
            return QuickSelectSmallest( array, n )[ n ];
        }
 
        /// <summary>
        ///  Partially sort array such way that elements before index position n are smaller or equal than elemnt at position n. And elements after n are larger or equal. 
        /// </summary>
        /// <typeparam name="T">The type of the elements of array. Type must implement IComparable(T) interface.</typeparam>
        /// <param name="input">The array which elements are being partially sorted. This array is not modified.</param>
        /// <param name="n">Nth smallest element.</param>
        /// <returns>Partially sorted array.</returns>
        private static T[] QuickSelectSmallest<T>( T[] input, int n ) where T : IComparable<T>
        {
            // Let's not mess up with our input array
            // For very large arrays - we should optimize this somehow - or just mess up with our input
            var partiallySortedArray = (T[]) input.Clone();
 
            // Initially we are going to execute quick select to entire array
            var startIndex = 0;
            var endIndex = input.Length - 1;
 
            // Selecting initial pivot
            // Maybe we are lucky and array is sorted initially?
            var pivotIndex = n;
 
            // Loop until there is nothing to loop (this actually shouldn't happen - we should find our value before we run out of values)
            var r = new Random();
            while( endIndex > startIndex )
            {
                pivotIndex = QuickSelectPartition( partiallySortedArray, startIndex, endIndex, pivotIndex );
                if( pivotIndex == n )
                    // We found our n:th smallest value - it is stored to pivot index
                    break;
                if( pivotIndex > n )
                    // Array before our pivot index have more elements that we are looking for                    
                    endIndex = pivotIndex - 1;
                else                    
                    // Array before our pivot index has less elements that we are looking for                    
                    startIndex = pivotIndex + 1;
 
                // Omnipotent beings don't need to roll dices - but we do...
                // Randomly select a new pivot index between end and start indexes (there are other methods, this is just most brutal and simplest)
                pivotIndex = r.Next( startIndex,  endIndex );
            }
            return partiallySortedArray;
        }
 
        /// <summary>
        /// Sort elements in sub array between startIndex and endIndex, such way that elements smaller than or equal with value initially stored to pivot index are before
        /// new returned pivot value index.
        /// </summary>
        /// <typeparam name="T">The type of the elements of array. Type must implement IComparable(T) interface.</typeparam>
        /// <param name="array">The array that is being sorted.</param>
        /// <param name="startIndex">Start index of sub array.</param>
        /// <param name="endIndex">End index of sub array.</param>
        /// <param name="pivotIndex">Pivot index.</param>
        /// <returns>New pivot index. Value that was initially stored to <paramref name="pivotIndex"/> is stored to this newly returned index. All elements before this index are 
        /// either smaller or equal with pivot value. All elements after this index are larger than pivot value.</returns>
        /// <remarks>This method modifies paremater array.</remarks>
        private static int QuickSelectPartition<T>( this T[] array, int startIndex, int endIndex, int pivotIndex ) where T : IComparable<T>
        {
            var pivotValue = array[ pivotIndex ];
            // Initially we just assume that value in pivot index is largest - so we move it to end (makes also for loop more straight forward)
            array.Swap( pivotIndex, endIndex );
            for( var i = startIndex ; i < endIndex ; i++ )
            {
                if( array[ i ].CompareTo( pivotValue ) > 0 )
                    continue;
 
                // Value stored to i was smaller than or equal with pivot value - let's move it to start
                array.Swap( i, startIndex );
                // Move start one index forward 
                startIndex++;
            }
            // Start index is now pointing to index where we should store our pivot value from end of array
            array.Swap( endIndex, startIndex );
            return startIndex;
        }
 
        private static void Swap<T>( this T[] array, int index1, int index2 )
        {
            if( index1 == index2 )
                return;
 
            var temp = array[ index1 ];
            array[ index1 ] = array[ index2 ];
            array[ index2 ] = temp;
        }
 
        #endregion
    }
}