Fastest way to check if an array is sorted

后端 未结 9 2036
走了就别回头了
走了就别回头了 2020-12-05 19:36

Considering there is an array returned from a function which is of very large size.

What will be the fastest approach to test if the array is sorted?

相关标签:
9条回答
  • 2020-12-05 20:08

    The question that comes to my mind is "why"?

    Is it to avoid re-sorting an already-sorted list? If yes, just use Timsort (standard in Python and Java). It's quite good at taking advantage of an array/list being already sorted, or almost sorted. Despite how good Timsort is at this, it's better to not sort inside a loop.

    Another alternative is to use a datastructure that is innately sorted, like a treap, red-black tree or AVL tree. These are good alternatives to sorting inside a loop.

    0 讨论(0)
  • 2020-12-05 20:17

    If the order doesn't matter(descending or ascending).

    private bool IsSorted<T>(T[] values) where T:IComparable<T>
    {
        if (values == null || values.Length == 0) return true;
    
        int sortOrder = 0;
    
        for (int i = 0; i < values.Length - 1; i++)
        {
            int newSortOrder = values[i].CompareTo(values[i + 1]);
    
            if (sortOrder == 0) sortOrder = newSortOrder;
    
            if (newSortOrder != 0 && sortOrder != newSortOrder) return false;
        }
    
        return true;
    }
    
    0 讨论(0)
  • 2020-12-05 20:18

    Linq solution.

    public static bool IsSorted<T>(IEnumerable<T> list) where T:IComparable<T>
    {
        var y = list.First();
        return list.Skip(1).All(x =>
        {
            bool b = y.CompareTo(x) < 0;
            y = x;
            return b;
        });
    }
    
    0 讨论(0)
  • 2020-12-05 20:19

    Faster approach, platform target: Any CPU, Prefer 32-bit.
    A sorted array with 512 elements: ~25% faster.

    static bool isSorted(int[] a)
    {
        int j = a.Length - 1;
        if (j < 1) return true;
        int ai = a[0], i = 1;
        while (i <= j && ai <= (ai = a[i])) i++;
        return i > j;
    }
    

    Target: x64, same array: ~40% faster.

    static bool isSorted(int[] a)
    {
        int i = a.Length - 1;
        if (i <= 0) return true;
        if ((i & 1) > 0) { if (a[i] < a[i - 1]) return false; i--; }
        for (int ai = a[i]; i > 0; i -= 2)
            if (ai < (ai = a[i - 1]) || ai < (ai = a[i - 2])) return false;
        return a[0] <= a[1];
    }
    

    Forgot one, marginally slower than my first code block.

    static bool isSorted(int[] a)
    {
        int i = a.Length - 1; if (i < 1) return true;
        int ai = a[i--]; while (i >= 0 && ai >= (ai = a[i])) i--;
        return i < 0;
    }
    

    Measuring it (see greybeard's comment).

    using System;                                  //  ????????? DEBUG ?????????
    using sw = System.Diagnostics.Stopwatch;       //  static bool abc()    
    class Program                                  //  {   // a <= b <= c ?  
    {                                              //      int a=4,b=7,c=9;  
        static void Main()                         //      int i = 1;  
        {                                          //      if (a <= (a = b))  
            //abc();                               //      {  
            int i = 512;                           //          i++;  
            int[] a = new int[i--];                //          if (a <= (a = c))
            while (i > 0) a[i] = i--;              //          {    
            sw sw = sw.StartNew();                 //              i++;  
            for (i = 10000000; i > 0; i--)         //          }  
                isSorted(a);                       //      }  
            sw.Stop();                             //      return i > 2;  
            Console.Write(sw.ElapsedMilliseconds); //  }  
            Console.Read();                        //  static bool ABC();
        }                                          //  {
                                                   //      int[]a={4,7,9};    
        static bool isSorted(int[] a) // OP Cannon //      int i=1,j=2,ai=a[0]; 
        {                                          //  L0: if(i<=j)    
            for (int i = 1; i < a.Length; i++)     //        if(ai<=(ai=a[i]))  
                if (a[i - 1] > a[i]) return false; //          {i++;goto L0;}  
            return true;                           //      return i > j;  
        }                                          //  }  
    }
    

    Target: x64. Four cores/threads. A sorted array with 100,000 elements: ~55%.

    static readonly object _locker = new object();
    static bool isSorted(int[] a)  // a.Length > 3
    {
        bool b = true;
        Parallel.For(0, 4, k =>
        {
            int i = 0, j = a.Length, ai = 0;
            if (k == 0) { j /= 4; ai = a[0]; }                        // 0 1
            if (k == 1) { j /= 2; i = j / 2; ai = a[i]; }             // 1 2
            if (k == 2) { i = j - 1; ai = a[i]; j = j / 2 + j / 4; }  // 4 3
            if (k == 3) { i = j - j / 4; ai = a[i]; j = j / 2; }      // 3 2
            if (k < 2)
                while (b && i <= j)
                {
                    if (ai <= (ai = a[i + 1]) && ai <= (ai = a[i + 2])) i += 2;
                    else lock (_locker) b = false;
                }
            else
                while (b && i >= j)
                {
                    if (ai >= (ai = a[i - 1]) && ai >= (ai = a[i - 2])) i -= 2;
                    else lock (_locker) b = false;
                }
        });
        return b;
    }
    

    1,000,000 items?

    if (k < 2)
        while (b && i < j)
            if (ai <= (ai = a[i + 1]) && ai <= (ai = a[i + 2]) &&
                ai <= (ai = a[i + 3]) && ai <= (ai = a[i + 4])) i += 4;
            else lock (_locker) b = false;
    else
        while (b && i > j)
            if (ai >= (ai = a[i - 1]) && ai >= (ai = a[i - 2]) &&
                ai >= (ai = a[i - 3]) && ai >= (ai = a[i - 4])) i -= 4;
            else lock (_locker) b = false;
    

    Let's forget percentages.
    Original: 0.77 ns/item, now: 0.22 ns/item.
    2,000,000 items? Four cores: 4 times faster.

    0 讨论(0)
  • 2020-12-05 20:19

    This might not be the fastest but it's the complete solution. Every value with index lower than i is checked against the current value at i. This is written in php but can easily be translated into c# or javascript

    for ($i = 1; $i < $tot; $i++) {
            for ($j = 0; $j <= $i; $j++) {
                //Check all previous values with indexes lower than $i
                if ($chekASCSort[$i - $j] > $chekASCSort[$i]) {
                    return false;
                }
            }
        }
    
    0 讨论(0)
  • You will have to visit each element of the array to see if anything is unsorted.

    Your O(n) approach is about as fast as it gets, without any special knowledge about the likely state of the array.

    Your code specifically tests if the array is sorted with smaller values at lower indices. If that is not what you intend, your if becomes slightly more complex. Your code comment does suggest that is what you're after.

    If you were to have special knowledge of the probable state (say, you know it's generally sorted but new data might be added to the end), you can optimize the order in which you visit array elements to allow the test to fail faster when the array is unsorted.

    You can leverage knowledge of the hardware architecture to check multiple parts of the array in parallel by partitioning the array, first comparing the boundaries of the partition (fail fast check) and then running one array partition per core on a separate thread (no more than 1 thread per CPU core). Note though that if a array partition is much smaller than the size of a cache line, the threads will tend to compete with each other for access to the memory containing the array. Multithreading will only be very efficient for fairly large arrays.

    0 讨论(0)
提交回复
热议问题