Quick sort How to write?

Source: Internet
Author: User
Tags array length random seed

Introduced

There are two classic ways to get a quick sort, and the common denominator is that only the partitioning process is:

//randomize the pivot subscript, taking care to initialize the "random seed" in the main function firstinline intGetpivotindex (intLeftintRight) {returnRand ()% (right-left +1) + left;}intPartition vector<int>& nums,intLeftintRight) {//two notation, Only this function body is not the same}voidQuicksorthelper ( vector<int>& nums,intLeftintRight) {if(left >= Right)return;intMID = partition (nums, left, right); Quicksorthelper (nums, left, mid-1); Quicksorthelper (nums, mid +1, right);}voidQuickSort ( vector<int>& Nums) {quicksorthelper (nums,0, Nums.size ()-1);}

The partitioning process has two "pointers", and the difference is that one of these two "pointers" is on the same side, and the other two "pointers" are on the opposite Side.
Is it more confusing? Take a look at the following steps to break down the example!

Same side

This method is shown in the pseudo-code in the introduction to the algorithm! I have been using this kind of writing, very simple and easy to understand!

For example, the original array is [7, 2, 8, 9, 1, 6], selects the last digit 6 as pivot, sets two pointer now=0 (meaning which number is currently traversed), Little=-1 (meaning is less than equal to the right edge of the part of pivot, Initially to the left of the left border to be divided).

Pivot is on the far right.
Now the pointer is traversed from left to right, and each time a element less than or equal to pivot is found, it is swapped to the right of the Little. Why is it? Because we maintain such a property in the Loop: little and its left part is less than or equal to pivot, and its right one is just above pivot, so it is reasonable to exchange it!

initial : now=0,little=-1,pivot=6, array is [7, 2, 8, 9, 1, 6].
First step: now=0,nums[now]=7 > pivot, then little unchanged is still-1;
Step two: now=1,nums[now]=2 <= pivot, then little plus 1 becomes 0, swap nums[little] and nums[now], the array becomes [2, 7, 8, 9, 1, 6];
Step three: now=2,8 > pivot, then little unchanged is still 1;
Fourth step: now=3,9 > pivot, then little unchanged is still 1;
Fifth step: now=4,nums[now]=1 <= pivot, then little plus 1 becomes 1, exchange nums[little] and nums[now], the array becomes [2, 1, 8, 9, 7, 6];
Fifth step: now=5,nums[now]=6 <= pivot, then little plus 1 becomes 2, exchange nums[little] and nums[now], the array becomes [2, 1, 6, 9, 7, 8];

To conclude, is it found that the left side of pivot (6, subscript 2) is all less than or equal to pivot, and all elements on the right side of the pivot are greater than pivot?

It is also worth noting that you can verify that, in the process of looping, the nature "little and its left part is less than or equal to pivot, and that the right one is just greater than the pivot" is it true to remain unchanged?

This process is easy to understand and is written in code:

int partition(vector<int>intint right) {    swap(nums[getPivotIndex(left, right)], nums[right]);    int1;    for (int now = left; now <= right; ++now) {        if (nums[now] <= pivot) {            // 做一点小优化,如果是相同的,就不用交换了            if (++little != now)                swap(nums[little], nums[now]);        }    }    return little;}

The overall test code is as Follows:

#include <iostream>#include <vector>#include <algorithm>#include <ctime>#include <cstdlib>using namespace STD;//randomize the pivot subscript, taking care to initialize the "random seed" in the main function firstinline intGetpivotindex (intLeftintRight) {returnRand ()% (right-left +1) + left;}intPartition vector<int>& nums,intLeftintRight) {swap (nums[getpivotindex (left, right)], nums[right]);intPivot = nums[right], Little = left-1; for(intnow = left; Now <= right; ++now) {if(nums[now] <= Pivot) {//do a little optimization, and if it is the same, you don't have to swap            if(++little! = Now) Swap (nums[little], nums[now]); }    }returnlittle;}voidQuicksorthelper ( vector<int>& nums,intLeftintRight) {if(left >= Right)return;intMID = partition (nums, left, right); Quicksorthelper (nums, left, mid-1); Quicksorthelper (nums, mid +1, right);}voidQuickSort ( vector<int>& Nums) {quicksorthelper (nums,0, Nums.size ()-1);}//determine If arrays are ordered in orderBOOLIsSorted (Const  vector<int>& V) { vector<int>Sorted (v.begin (), V.end ()); Sort (sorted.begin (), sorted.end ()); for(inti =0; I < v.size (); ++i)if(v[i]! = Sorted[i])return false;return true;}//randomly generate an array of sizevoidGen vector<int>& v, size_t Size) {Static Const intMAX =99997; v = vector<int>(size); for(inti =0; I < size; ++i) v[i] = Rand ()% MAX;}intMain () {srand (0)); for(size_t size =0; Size <10000; ++size) { vector<int>V        Gen (v, size); QuickSort (v);if(!issorted (v)) {cout<<"FAIL with size ="<< size << endl; break; }Else{cout<<"good with size ="<< size << endl; }    }return 0; }
Different side

First of all, this solution at the end of a detail need to be clear, although the process is very intuitive, in general, the individual feel inferior to the above solution came concise beautiful ~

Maintains two pointers: left, which represents the right edge of the part that is less than or equal to the pivot, and the starboard (representing the lower boundary of the part that is greater than the pivot, the initial value is the subscript of the Second-to-last element).

Pivot is on the far right.
At each loop, left finds the first value that is greater than pivot, while right finds the first value that is less than or equal to the pivot, and if the condition is appropriate, swaps both so that elements less than or equal to pivot are always left in the range The elements that are greater than pivot are always in the right range!

Or take an array [7, 2, 8, 9, 1, 6] to give an example.

initially, left=0,right=6-1-1=4 (6 for the array length , because the subscript starts at 0, so you want to subtract one first, then right is initially the Second-to-last element, so you need to subtract one more because the final one is pivot), pivot=nums[ 6-1]=6, the array is [7, 2, 8, 9, 1, 6].

the First step :
left=0,nums[left] = 7 > 6, found the first element greater than 6!
Right=4,nums[right]=1 < 6, found the first element less than or equal to 6!
Find left < right, you can swap both, the array becomes [1, 2, 8, 9, 7, 6].

Step Two :
Left from 01 until 2, will make nums[left]=8 > 6;
Right from 4 to 1 will make nums[right]=2 <= 6;
Find left > right, no swapping!

Why?
In retrospect, left is less than or equal to pivot, and right is greater than pivot, and now there is a r > a, which means the intersection of the two ranges, which is the sum of the two intervals covering the entire original interval, the explanation has been divided! So there's no need to trade again ~

after exiting the loop :
But did you find a point? pivot, which is the last 6, has not been moved, and the current result is [1, 2, 8, 9, 7, 6], But the results we want should be [1, 2, 6, 9, 7, 8]!

so, after exiting the loop, you also need to check a step to see the size relationship between nums[left] and pivot, and if it is larger than pivot, switch pivot and nums[left].

What if the last nums[left] <= pivot? What does it mean?
This means that the entire range is less than or equal to pivot, so the left should naturally be equal to the original right boundary.

Why must this be so?
The answer is: (using end to denote the right end of the interval subscript,) exit the loop, there must be left >=.
Assuming right has moved, then [right, end-1] This interval, must be greater than pivot, and left >=, then is falling on [right, end-1], supposedly should also nums[left] > pivot to , but there are nums[left] <= pivot???
So the conclusion is that right has never been moved to the left, and that one is moved from 0 to end-1, and has nums[end-1] <= num[end], so it should be returned with the value assigned to End.

intPartition vector<int>& nums,intLeftintRight) {swap (nums[getpivotindex (left, right)], nums[right]);intPivot = nums[right], End = right; --right; while(left < Right) {//left to right find the first value greater than pivot         while(left < right && nums[left] <= pivot) ++left;//find The first value less than or equal to pivot from right to left         while(right > Left && nums[right] > pivot)--right;//exchange Both if the conditions are right        if(left < Right) swap (nums[left], nums[right]); }if(nums[left] > Nums[end]) swap (nums[left], nums[end]);Elseleft = end;returnleft;}

The overall test code is as Follows:

#include <iostream>#include <vector>#include <algorithm>#include <ctime>#include <cstdlib>using namespace STD;//randomize the pivot subscript, taking care to initialize the "random seed" in the main function firstinline intGetpivotindex (intLeftintRight) {returnRand ()% (right-left +1) + left;}intPartition vector<int>& nums,intLeftintRight) {swap (nums[getpivotindex (left, right)], nums[right]);intPivot = nums[right], End = right; --right; while(left < Right) {//left to right find the first value greater than pivot         while(left < right && nums[left] <= pivot) ++left;//find The first value less than or equal to pivot from right to left         while(right > Left && nums[right] > pivot)--right;//exchange Both if the conditions are right        if(left < Right) swap (nums[left], nums[right]); }if(nums[left] > Nums[end]) swap (nums[left], nums[end]);Elseleft = end;returnleft;}voidQuicksorthelper ( vector<int>& nums,intLeftintRight) {if(left >= Right)return;intMID = partition (nums, left, right); Quicksorthelper (nums, left, mid-1); Quicksorthelper (nums, mid +1, right);}voidQuickSort ( vector<int>& Nums) {quicksorthelper (nums,0, Nums.size ()-1);}//determine If arrays are ordered in orderBOOLIsSorted (Const  vector<int>& V) { vector<int>Sorted (v.begin (), V.end ()); Sort (sorted.begin (), sorted.end ()); for(inti =0; I < v.size (); ++i)if(v[i]! = Sorted[i])return false;return true;}//randomly generate an array of sizevoidGen vector<int>& v, size_t Size) {Static Const intMAX =99997; v = vector<int>(size); for(inti =0; I < size; ++i) v[i] = Rand ()% MAX;}intMain () {srand (0)); for(size_t size =0; Size <10000; ++size) { vector<int>V        Gen (v, size); QuickSort (v);if(!issorted (v)) {cout<<"FAIL with size ="<< size << endl; break; }Else{cout<<"good with size ="<< size << endl; }    }return 0; }
Comparison of two methods

Intuitive and concise, has been discussed above, here the main want to say, the complexity of the two how!

The above example, using the same array, found that the first need to exchange three times, and the second only need to exchange two times, does it mean that the second is better?

Some people do have such an illusion, hhh, do not remember where to see, it should be known or bole online one.

Why should I say it's an illusion? Is it not felt that the first solution, a number, can be exchanged multiple times? And the second solution, save a lot of exchange? (it does make sense, but not the truth, and listen to the following Analysis)

The number of exchanges of the first solution

For example [1, 6, 2, 3, 5, 4], where now encounters the element 2 o'clock, it will become [1, 2, 6, 3, 5, 4], element 6 is exchanged for the first time!
Immediately thereafter, now encounters element 3, element 6 is exchanged once, and the array becomes [1, 2, 3, 6, 5, 4].
finally, now encounters element 4, element 6 is exchanged once, and the array becomes 1, 2, 3, 4, 5, 6].
In this process, element 6 was exchanged altogether 3 times!

however, you have to notice that not all elements greater than pivot are exchanged 3 times!!! 5, for example, has never been exchanged! In essence, using the first solution, the total number of times an element is exchanged is actually equal to the number of elements in the array that are less than or equal to pivot !

Speaking of which, do you think I'm talking nonsense?
Because in the above array, the number of elements that are clearly less than or equal to pivot is 4, not 3! Think about that little step of optimization ... Right? You do not optimize the words, is 4, as for why, I temporarily do not give strict proof (have time to come, write blog now has more than one o'clock late at night), in fact, if you really understand this algorithm, is able to very intuitive to think out why.

Number of exchanges for the second solution

What about the second solution?
Suppose that the number of elements in an array that is less than or equal to pivot is P, and the number of interchanges is actually equal to the number of all elements less than or equal to pivot on the interval [left + P-1, right] !

For example above [1, 6, 2, 3, 5, 4], at this time p=4, and the interval [3, 5] above two elements are less than or equal to pivot (=4), so the number of exchanges is 2 (first Exchange 6 and 3, second Exchange 6 and 4).

Is it less than the first kind? indeed, because [left, left + P-1] on the general will have less than equal to the pivot element, so this method of exchange is naturally less than p, and P equals the first solution is not optimized when the number of Exchanges.

Sum up

In fact, after the first solution has been optimized, it is almost identical to the number of times the second solution was exchanged (intuition).

Is the performance of the algorithm determined only by the number of interchange elements?

Obviously the answer is no!
Note that there is a concept called "cache", assuming that the array is very long, then the order of access will be better, because there is a cache, but if each time it is accessed from both ends, the cache is constantly invalid, right?

It's all on Paper.

In fact, if you really want to find out whether the efficiency of the two algorithms are high or low, we should generate test samples of complete length, various data distribution, etc., to test, but the test also involves a variety of compiler environment, operating environment ... Slightly dizzy.

This great work is to be done to posterity or to Scientists. t_t run and send me a copy of the experiment, thx.

Optimization 1. How to take the principal element (pivot)

Try to randomize it, don't fix it (like the first or last one), so it's easier to avoid the worst case scenario.

At present, There are the median method (median-of-three)! Select nums[left], nums[(left+right) >>1], nums[right] three digits in the median, you can also expand ... For details, Please refer to: three quick sort and quick sort optimization

2. Introspection Sort

For an introduction to introspection sort, Please refer to the introspective Sort-wikipedia.

In fact, the idea is simple: when the length of the array to be sorted reaches the lower threshold, use other types of sorting such as insert sort, heap sort, and so On.

This is done by using the sort method of inserting sort, when the data size is very small, the performance is better than the fast sort (after all, the Fast-track constant is large)!

This length threshold is generally [26, 29], is a test out, interested can also design their own experiments to find!

Why O (nlog N)

It's too late today to do math deduction tomorrow!

Quick sort How to write?

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.