Quick sort Step-by-step optimization

Source: Internet
Author: User
Tags rand

First, Quick sort introduction

The quick sort is a sort of division exchange proposed by C.r.a.hoare in 1962. It adopts a strategy of division, which is usually referred to as the Division method (Divide-and-conquermethod).

Algorithm idea: 1. First take an array from the array as a pivot, generally select the first or last element of the array as the pivot, of course, you can choose Other, in the following optimization measures, I will slowly introduced.

2. Bidirectional traversal, choose a number larger than the pivot from the left, select a number smaller than the pivot from the right, then swap the two numbers;

3. Repeat step 2 until the left side of the pivot is smaller than the pivot, and the number on the right side of the pivot is larger than the pivot.

Time complexity of the algorithm: O (NLOGN)

Second, the content

Example array: arr = {1,4,2,5,6,7,9,3};

   

We select the first number as the pivot.

Let's take a look at the first traversal process:

    

We've recovered 3 times from the left loop and found a number 5 larger than the pivot, and from the right loop we've found a few 3 smaller than pivots, and then we're going to swap these two numbers:

    

At this point, the first traversal ends, but this does not meet the requirements. Let's take a look at the result of the second traversal:

    

Exchange:

    

Since the above conditions have been met, it is not necessary to exchange again.

Until the last trip, we pivot to the position:

    

Code implementation:

intQsortint*a,intLeftintRight ) {    if(Right <=Left )return-1; intPivot =A[right]; inti =Left ; intj = Right-1; //front-to-back scanning, no need to determine if there are any cross-border issues     while(true){         while(a[i++] <pivot); //scan forward from backward to prevent cross-border         while(A[j] > pivot && J >=Left ) {J--; }        if(I <j) Swap (A[i++],a[j--]); Else{             Break; }} swap (A[i],pivot); //The last trip is to exchange A[i] with pivotQsort (A,left,i-1); Qsort (A,i+1, right); return 0;}

Third, optimize

We all know that the efficiency of fast sorting is mainly the selection of the pivot, regardless of whether the first element or the last element as the pivot, we have to iterate through the array. Therefore, in order to optimize the fast row, but also from the pivot of the selection.

  1. Random Selection method

Introduction Reason: in order to arrange the sequence is partially ordered, fixed selection of pivot to make the efficiency of the fast row, to alleviate this situation, the introduction of a randomly selected pivot

Idea: Use the random number generation function to generate a random number rand, the range of random numbers is [left, right], and use this random number as the subscript corresponding to the element A[rand] as the middle axis, and with the last element A[right] exchange, and then proceed

The same algorithm as selecting the last element as the middle axis's fast-line.

Pros: This is a relatively safe strategy. Since the position of the pivot is random, the resulting segmentation will not always result in inferior segmentation. When the entire array number is equal, the worst case is still, and the time complexity is O (n^2). In fact, the probability of a stochastic quick ordering to get a theoretical worst case is only 1/(2^n). So randomization fast sequencing can achieve the desired time complexity of O (NLOGN) for the vast majority of input data.

Code implementation:

intRandomintLeftintRight ) {    returnRand ()% (Right-left +1) +Left ;}voidQsort (int*a,intLeftintRight ) {    if(Left >=Right ) {        return; }    //randomly selects an element as a pivot and swaps it with the last element    intIC =random (Left,right);    Swap (a[ic],a[right]); intMidindex =Data[right]; inti =Left ; intj = Right-1;  while(true){        //finding data larger than the pivot         while(a[i++] <Midindex); //find data that is smaller than the pivot         while(A[j] > Midindex && J >=Left ) {J--; }        //data has been found, ready for Exchange        if(I <j) {Swap (A[i++],a[j--]); }        Else{             Break; }} swap (A[i],midindex); //put the pivot in the right placeQsort (A,left,i-1); Qsort (A,i+1, right);}

  2. Three digital (Median-of-three)

Reason for introduction: Although the probability of bad segmentation is reduced when the pivot is selected randomly, the worst case or O (n^2), to alleviate this situation, introduced the three-digit pick pivot

idea: Suppose the array is sorted by left and right,center= (left+right)/2, A[left], A[right], and A[center] properly sorted, median is the middle axis, the smallest person is put a[left], The largest is placed in A[right], the middle axis element and a[right-1] are exchanged, and in the split phase I and J are initialized to Left+1 and right-2. Then use the bidirectional description method to make a quick row.

Segmentation Benefits:

1. It is correct to divide the smallest of the triples into A[left] and the largest to the a[right], because when a trip is made, it is smaller than the middle axis and placed on the left side, but larger than the middle axis to the right, so that in the split when they are divided into the correct position, reducing a comparison and exchange.

2. In all the algorithms mentioned above, there are cross-boundary problems in bidirectional scanning, and the use of this segmentation strategy can solve this problem. Because I scan to the right, will inevitably encounter no less than the number of a[right-1], and J on the left to scan, will inevitably encounter no greater than the number of a[left], so that a[right-1] and A[left] provides a warning flag, so do not need to check the subscript cross-border problem.

Analysis: The best division is to divide the sequence to be sorted into equal-length subsequence, the best state we can use the middle value of the sequence, that is, the number of N/2. However, this is difficult to figure out, and will significantly slow down the speed of sorting. The median estimate can be obtained by randomly selecting three elements and using their median value as the pivot element. In fact, randomness does not help much, so the general practice is to use the median value of the three elements on the left, right, and center positions as pivot elements. It is clear that the three-digit median split method eliminates the bad situation of pre-sorted inputs and reduces the number of comparisons of the fast rows by approximately 14%

Example:

Initial array: 6 1 8 9 4 3 5 2 7 0

Select three median:6 1 8 9 4 3 5 2 7 0

Sort these three numbers:0 1 8 9 4 3 5 2 7 6

Final middle axis and A[right-1] Exchange: 0 1 8 9 7 3 5 2 4 6

Instance code:

intMedian (int*a,intLeftintRight ) {    intMidindex = (left + right) >>1; if(A[left] >A[midindex])    {swap (a[left],a[midindex]); }    if(A[left] >A[right])    {swap (a[left],a[right]); }    if(A[midindex] >A[right])    {swap (a[midindex],a[right]); } Swap (A[midindex],a[right-1]); returna[right-1];//back to Middle axis}
voidQSort (int*a,intLeftintRight ) {        //Use Quick Sort if you need to sort more than 3 data        if(Right-left >=3)        {            intMidindex =Median (a,left,right); intBegin =Left ; intEnd = Right-1;  while(true){                 while(A[++begin] <Midindex);  while(a[--end]<Midindex); if(Begin <end)                {swap (a[begin],a[end]); }                Else{swap (a[begin],a[right-1]);//where to move the pivot                     Break; }} qSort (A,left,begin-1); QSort (A,begin+1, right); }        Else{bubblesort (a,left,right);//when the data is less than 3, sort directly with bubbles}//when the data to be sorted is very small (less than 3), it is not possible to take the median value in three, which can be done directly using simple sorting (for example, bubbling), and it is reasonable to consider this from an efficiency standpoint, because it avoids the overhead of function calls.     }

Iv. further optimization

The above three kinds of fast rows, when dealing with repetitions, the efficiency is not greatly improved, so we can think of ways to optimize.

  1. Use Insert sorting when the length of the sequence to be sorted is split to a certain size.

Cause: For very small and partially ordered arrays, the quick row is better than the interpolation. When the length of the sequence to be sorted is split to a certain size, the efficiency of continuing the split is worse than the insert sort, where you can use the interpolation instead of the fast

if 1 Ten )  {      insertsort (arr,low,high);       return ;  } // else, a fast row  is executed normally

  2. After the end of a split, you can put the elements equal to the key together, continue the next split, no longer with the key equal element segmentation (processing repetition efficiency is very high) 

Example:

Sequence to sort 1 4 6 7 6 6 7 6 8 6

Select Pivot in three-count: Number of subscript 4 6

After conversion, the sequence to be split: 6 4 6 7 1 6 7 6 8 6 pivot Key:6

After this partition, the result of being equal to the key element is not processed: 1 4 6 6 7 6 7 6 8 6

The next two sub-sequences are: 1 4 6 and 7 6 7 6 8 6

The result of equality with key elements after this division: 1 4 6 6 6 6 6 7 8 7

The next two sub-sequences are: 1 4 and 7 8 7

After comparison, we can see that, after a division, the elements equal to the key together, can reduce the number of iterations, efficiency will improve a lot

Process: In the process, there will be two steps

The first step, in the partitioning process, puts the key equal element into the two ends of the array

The second step, after dividing, moves the element equal to the key around the pivot.

Example:

Sequence to sort 1 4 6 7 6 6 7 6 8 6

Select Pivot in three-count: Number of subscript 4 6

After conversion, the sequence to be split: 6 4 6 7 1 6 7 6 8 6 pivot Key:6

The first step, in the partitioning process, puts the key equal element into the two ends of the array

Results: 6 4 1 6 (Pivot) 7 8 7 6 6 6

At this point, all elements equal to 6 are placed at both ends.

The second step, after dividing, moves the element equal to the key around the pivot.

Results: 1 4 66 (pivot) 6 6 6 7 8 7

At this point, all elements equal to 6 are moved around the pivot.

After that, the 1 4 and 7 8 72 sub-sequences are in a fast row

code example:

voidQSort (intArr[],intLowintHigh )//Three number of Median + aggregation equal element {intFirst =Low ; intLast =High ; intleft =Low ; intright =High ; intLeftlen =0; intRightlen =0; if(High-Low +1<Ten) {insertsort (Arr,low,high); return; }        //One split    intKey = Selectpivotmedianofthree (Arr,low,high);//Selecting a pivot using the three-digit method             while(Low <High ) {         while(High > Low && Arr[high] >=key) {            if(Arr[high] = = key)//working with equal elements{swap (Arr[right],arr[high]); Right--; Rightlen++; } High--; } Arr[low]=Arr[high];  while(High > Low && arr[low] <=key) {            if(Arr[low] = =key)                {swap (arr[left],arr[low]); Left++; Leftlen++; } Low++; } Arr[high]=Arr[low]; } Arr[low]=key; //The end of a quick row//move the element that is the same as the pivot key around the final position of the pivot    inti = low-1; intj =First ;  while(J < left && Arr[i]! =key)        {swap (arr[i],arr[j]); I--; J++; } I= Low +1; J=Last ;  while(J > Right && arr[i]! =key)        {swap (arr[i],arr[j]); I++; J--; } QSort (Arr,first,low-1-Leftlen); QSort (Arr,low+1+rightlen,last);}

Cause: In an array, if there are equal elements, then a lot of redundant partitioning can be reduced. This is particularly evident in the repeating array.

3. Optimize recursive operations  

The fast-line function has two recursive operations at the end of the function, and we can use the tail-recursive optimization

Advantages: If the sequence to be sorted is extremely unbalanced, the depth of recursion will approach N, and the size of the stack is very limited, each recursive call will cost a certain amount of stack space, the more parameters of the function, the more space each time the recursion cost. After optimization, the stack depth can be reduced and the original O (n) is reduced to O (Logn), which will improve performance.

voidQSort (intArr[],intLowintHigh ) {       intPivotpos =-1; if(High-Low +1<Ten) {insertsort (Arr,low,high); return; }       while(Low <High ) {Pivotpos=Partition (Arr,low,high); QSort (Arr,low,pivot-1); Low= pivot +1; }  } 

  

Reference documents

Http://blog.sina.com.cn/s/blog_5a3744350100jnec.html

Http://www.blogjava.net/killme2008/archive/2010/09/08/331404.html

Http://www.cnblogs.com/cj723/archive/2011/04/27/2029993.html

http://blog.csdn.net/zuiaituantuan/article/details/5978009

http://blog.csdn.net/ljianhui/article/details/16797431

  

Quick sort Step-by-step optimization

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.