Quicksort Without Recursion
All in all there is not much to comment. I like the iterative mechanism with the stack. Trying other collections (linked list, dictionary, hashset etc.) doesn't seem to improve the performance.

One could argue that it would be nice to have the partition part in a dedicated function to improve readability, but again the algorithm isn't that hard to understand.

The really improvement of performance comes from the use of InsertionSort() when the range is smaller than 31 - and that magic number seems to be the right limit. And Insertion Sort seems to be the right choice over other simple algorithms like Selection Sort.

The performance gain from SampleMedian() is little or absent for smaller data sets, but is significant for larger (> 10000) - compared to let it return values[startIndex] or values[startIndex + (endIndex - startIndex) / 2].

All in all a well designed algorithm optimized in respect to performance.



A minor thing in SampleMedian():

I don't like:

if (0 &gt; comparer.Compare(values[right], values[left]))


but rather: 

if (comparer.Compare(values[right], values[left]) &lt; 0)


but that's a matter of habit.



Of course you should check if the arguments are valid (values != null, startIndex &lt; endIndex etc.)