What is the time complexity of a while loop that uses random.shuffle (python) inside of it?

Question:

first of all, can we even measure it since we don’t know how many times random.shuffle will shuffle the array until it reaches the desired outcome

def sort(numbers): 
import random
while not sort(numbers)==numbers:
  random.shuffle(numbers)
return numbers
Asked By: pomeranian

||

Answers:

First I assume the function name to not be sort as this would be trivial and would lead to unconditional infinite recursion. I am assuming this function

import random

def random_sort(numbers): 
    while not sorted(numbers)==numbers:
        random.shuffle(numbers)
    return numbers

Without looking at the implementation to much I would assume O(n) for the inner shuffle random.shuffle(numbers). Where n is the number of elements in numbers.

Then we have the while loop. It stops when the array is sorted. Now shuffle returns us one of all possible permutations of numbers. The loop aborts when its sorted. This is for just one of those. (if we don’t assume a small number space).

This stopping is statistical. So we need technically define which complexity we are speaking of. This is where best case, worst case, amortized case comes in.

Best case

The numbers we get are already sorted. Then we have the cost of sort(numbers) and the comparison .. == numbers. Sorting a sorted array is O(n). So our best case complexity is O(n).

Worst case

The shuffle never gives us the right permutation. This is definitely possible. The algorithm would never terminate. So its O(∞).

Average case

This is probably the most interesting case. First we need to establish how many permutations shuffle is giving us. Here is a link which discusses that. An approximation is given as e ⋅ n!. Which is O(n!) (please check).

Now the question is on average when does our loop stop. This is answered in this link. They say its the geometric distribution (please check). The result is 1/ p, where p is the probablity of getting it. In our case this is p = 1 / (e ⋅ n!). So we need on average e ⋅ n! tries.

Now for each try we need to sort O(n log(n)), compare O(n) and compute the shuffle O(n). For the shuffle we can say it uses the Fisher Yates algorithm which has a complexity of O(n), as shown here.

So we have O(n! n log(n)) for the average cost.

Answered By: Chris