### Merge **sort** versus quick **sort** performance

##### - by Giorgio

I have implemented merge

**sort**and quick**sort**using C (GCC 4.4.3 on Ubuntu 10.04 running on a 4 GB RAM laptop with an Intel DUO CPU at 2GHz) and I wanted to compare the performance of the two algorithms. The prototypes of the sorting functions are: void merge_sort(const char **lines, int start, int end); void quick_sort(const char **lines, int start, int end); i.e. both take an array of pointers to strings and**sort**the elements with index i : start <= i <= end. I have produced some files containing random strings with length on average 4.5 characters. The test files range from 100 lines to 10000000 lines. I was a bit surprised by the results because, even though I know that merge**sort**has complexity O(n log(n)) while quick**sort**is O(n^2), I have often read that on average quick**sort**should be as fast as merge**sort**. However, my results are the following. Up to 10000 strings, both algorithms perform equally well. For 10000 strings, both require about 0.007 seconds. For 100000 strings, merge**sort**is slightly faster with 0.095 s against 0.121 s. For 1000000 strings merge**sort**takes 1.287 s against 5.233 s of quick**sort**. For 5000000 strings merge**sort**takes 7.582 s against 118.240 s of quick**sort**. For 10000000 strings merge**sort**takes 16.305 s against 1202.918 s of quick**sort**. So my question is: are my results as expected, meaning that quick**sort**is comparable in speed to merge**sort**for small inputs but, as the size of the input data grows, the fact that its complexity is quadratic will become evident? Here is a sketch of what I did. In the merge**sort**implementation, the partitioning consists in calling merge**sort**recursively, i.e. merge_sort(lines, start, (start + end) / 2); merge_sort(lines, 1 + (start + end) / 2, end); Merging of the two sorted sub-array is performed by reading the data from the array lines and writing it to a global temporary array of pointers (this global array is allocate only once). After each merge the pointers are copied back to the original array. So the strings are stored once but I need twice as much memory for the pointers. For quick**sort**, the partition function chooses the last element of the array to**sort**as the pivot and scans the previous elements in one loop. After it has produced a partition of the type start ... {elements <= pivot} ... pivotIndex ... {elements > pivot} ... end it calls itself recursively: quick_sort(lines, start, pivotIndex - 1); quick_sort(lines, pivotIndex + 1, end); Note that this quick**sort**implementation sorts the array in-place and does not require additional memory, therefore it is more memory efficient than the merge**sort**implementation. So my question is: is there a better way to implement quick**sort**that is worthwhile trying out? If I improve the quick**sort**implementation and perform more tests on different data sets (computing the average of the running times on different data sets) can I expect a better performance of quick**sort**wrt merge sort? EDIT Thank you for your answers. My implementation is in-place and is based on the pseudo-code I have found on wikipedia in Section In-place version: function partition(array, 'left', 'right', 'pivotIndex') where I choose the last element in the range to be sorted as a pivot, i.e. pivotIndex := right. I have checked the code over and over again and it seems correct to me. In order to rule out the case that I am using the wrong implementation I have uploaded the source code on github (in case you would like to take a look at it). Your answers seem to suggest that I am using the wrong test data. I will look into it and try out different test data sets. I will report as soon as I have some results.