"Turn" three fast sorting algorithms and optimization of fast sorting

Source: Internet
Author: User
Tags benchmark

I. basic ideas for fast sequencing

Quick sort using the idea of divide and conquer, the waiting sequence is divided into two parts by a sort of order, and some of the recorded keywords are smaller than the keywords recorded in the other part. The two parts of the records are then sequentially sorted to achieve the order of the entire sequence.

Two. three steps to quickly sort

1) Select the benchmark: in the sequence to be sorted, a certain way to pick out an element, as a "datum" (pivot);

2) Split operation: divides the sequence into two sub-sequences with the actual position of the datum in the sequence. At this point, the elements on the left side of the datum are smaller than the datum, and the elements to the right of the datum are larger than the datum;

3) Quickly sort two sequences recursively, until the sequence is empty or has only one element;

Three. how to select a Datum element

For divide-and-conquer algorithm, when each partition, if the algorithm can be divided into two equal-length sub-sequence, then the efficiency of the divide-and-conquer algorithm will reach the maximum. In other words, the selection of benchmarks is important. The selection of the datum determines the length of the two two sub-sequences, which has a decisive effect on the efficiency of the whole algorithm.

Ideally, the chosen benchmark would be able to divide the ordered sequence into two equal-length sub-sequences.

Method one: Fixed datum element (Basic quick Sort)

Thought: Takes the first or last element of a sequence as a datum element.

<summary>///1.0 Fixed datum element (Basic quick Sort)///</summary> public static void Qsortcommon (int[]                        arr, int low, int.) {if (Low >= high) return;      recursive exit int partition = partition (arr, low, high);            Swap the elements of >= X to the right area and swap the elements of <= X to the left area Qsortcommon (arr, Low, partition-1);        Qsortcommon (arr, partition + 1, high); }///<summary>///fixed datum element, default array the first number is the datum, left and right groups, returns the subscript of the Datum element///</summary> public static int part            Ition (int[] arr, int low, int.) {int first = low;            int last = high;                             int key = Arr[low]; Take the first element as the base element while (initial < last) {while (primary < last && Arr[last] &                gt;= key) last--;                Arr[first] = Arr[last];                 while (first < last && Arr[first] <= key)   first++;            Arr[last] = Arr[first];                               } Arr[first] = key;        The datum element is centered in return first; }

Note: Basic quick sort selects the first or last element as the baseline. However, this is always a very bad way to deal with.

Test data:

Test data analysis: If the input sequence is random, the processing time can be acceptable. If the array is already in order, the segmentation at this point is a very bad one. Because each partition can only be ordered to reduce the sequence of one, at this time, the worst case, the rapid sorting into a bubble sort, the time complexity of θ (n^2). Moreover, it is quite common for the input data to be ordered or partially ordered. Therefore, it is very bad to use the first element as a datum element, and in order to avoid this, the following two methods of obtaining a baseline are introduced.

Method Two: Random datum element

Thought: Take any element in the ordered sequence as a datum element.

The reason of the introduction: in order to alleviate this situation, the random selection datum element is introduced when the sequence is partially ordered and the fixed selection datum element makes the efficiency of the fast row.

<summary>        ///2.0 random datum yuan        ///</summary> public static void Qsortrandom (int[] arr, int low, int High)        {            if (low >=) return;                        Recursive exit            partitionrandom (arr, low, high);                Random datum element            int partition = partition (arr, low, high);      Swap the elements of >= X to the right area and swap the elements of <= X to the left area            qsortrandom (arr, Low, partition-1);            Qsortrandom (arr, partition + 1, high);        } <summary>        ///random reference element, will determine the good datum element and the first number of exchanges, no return value///        </summary> public                static void Partitionrandom (int[] arr, int low, int. high)        {            Random rd = new Random ();            int randomindex = Rd. Next ()% (high-low) + low;//take random subscript            Swap (arr, Randomindex, low) in the array;                     Exchange with the first number        }

Test data:

Test Data analysis:: This is a relatively safe strategy. Because the position of the datum element 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. A predecessor made a brilliant summary: "Random rapid sequencing can meet a person's lifelong personality needs." ”

Method 3:3 in the number of

The reason for the introduction: Although the random selection of the benchmark, reduce the likelihood of bad segmentation, but still the worst case or O (n^2), to alleviate this situation, the introduction of a three-digit selection of the benchmark.

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 reference element. In fact, randomness does not help much, so the general practice is to use the median of the three elements on the left, right, and center positions as the base element. It is obvious that the three-digit median segmentation method eliminates the bad situation of pre-sorted inputs and reduces the number of comparisons of the fast rows by approximately 14%.

Example: The sequence to be sorted is: 8 1 4 9 6 3 5 2 7 0

to the left: 8 , to the right 0 , in the middle for 6

We take three numbers here and sort the middle number as the pivot, then the pivot is 6

Note: When selecting the middle axis value, it can be selected from the middle left and right three medium selection to five elements or more elements, in general, there will be (2t+1) mean partition method (median-of-(2t+1), three mean division method English is median-of-three.

Specific idea: treat the data in low, mid, and high three positions in the sort sequence, take the data in between them as a benchmark, and store the benchmark with 0 subscript elements.

That is: use three-digit, and 0 subscript elements to store the benchmark.

<summary>///3.0 three-digit///</summary> public static void Qsortmedianofthree (int[] Arr                        , int low, int.) {if (Low >= high) return;         Recursive exit Partitionmedianofthree (arr, low, high);      three-digit int partition = partition (arr, low, high);            Swap the elements of >= X to the right area and swap the elements of <= X to the left area qsortmedianofthree (arr, Low, partition-1);        Qsortmedianofthree (arr, partition + 1, high); }///<summary>/////Three to determine the datum element, will determine the good datum and the first number of exchanges, no return value///</summary> public static VO            ID partitionmedianofthree (int[] arr, int low, int.) {int mid = low + (high +-low)/2;            if (Arr[mid] > Arr[high]) {Swap (arr, Mid, High);            } if (Arr[low] > Arr[high]) {Swap (arr, low, high); } if (Arr[mid] > Arr[low]) {                Swap (arr, Mid, Low); }//Swap the number of intermediate sizes with the first number}

Test data:

Test data analysis: Using the three-digit advantage is still obvious, but it is still not able to handle duplicate arrays.

Four. two ways to optimize

Optimization One: Use Insert sort 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 continued segmentation is worse than the insertion sort, which can be used instead of a quick row.

Cutoff range: The sequence length to be sorted n = 10, although a similar result can be produced in any cutoff range between 5~20, this practice also avoids some harmful degradation scenarios.

--excerpt from data structure and algorithmic analysis Mark Allen weiness

<summary>        ///4.0 three-digit + insert                ///</summary> public static void Qsortthreeinsert (int[] arr, int Low, int.)        {            if (high-low + 1 <)            {                insertsort (arr, low, high);                return;            }                                               Pluggable, recursive exit            Partitionmedianofthree (arr, low, high);         Three            -digit int partition = partition (arr, low, high);      Swap the elements of >= X to the right area and swap the elements of <= X to the left area            qsortmedianofthree (arr, Low, partition-1);            Qsortmedianofthree (arr, partition + 1, high);        }

Test data:

Test data analysis: For a random array, using the three-digit selection datum + interpolation, the efficiency can be improved a bit, really for the sorted array, there is no use. Because the ordered sequence is ordered, each partition can only subtract one from the sorted sequence. At this point, the interpolation is not playing a role. So there is no time to see the reduction. In addition, the three-digit selection datum + interpolate or cannot handle the repeating array.

optimization Two: After the end of a split, you can put the key equal elements together, continue the next split, no longer with the key equal element Segmentation

Example:

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

Select Datum in three-digit selection: The number of subscript is 4 6

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

Benchmark 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.

<summary>///5.0 three-digit + interpolation + aggregation of the same element///</summary> public static void Qsortthree Insertgather (int[] arr, int low, int. high) {if (high-low + 1 <) {Ins                Ertsort (arr, low, high);            Return         }//Plug-in, recursive exit Partitionmedianofthree (arr, low, high);            Three-digit middle//left-right grouping (processing of equal elements) int first = low;            int last = high;            int left = low;            int right = high;            int leftlength = 0;            int rightlength = 0;            int key = Arr[first];                while (first < last) {when (First < last && Arr[last] >= key)                        {if (arr[last] = = key)//handles equal elements, placing equal elements at both ends of the array {                        Swap (arr, last, right);                      right--;  rightlength++;                } last--;                } Arr[first] = Arr[last];                    while (first < last && Arr[first] <= key) {if (arr[first] = = key)                        {Swap (arr, first, left);                        left++;                    leftlength++;                } first++;            } Arr[last] = Arr[first];            } Arr[first] = key;            One quick line end//move the element with the same reference element key to the final position around int i = first-1;            int j = Low;                while (J < left && arr[i]! = key) {Swap (arr, I, j);                i--;            j + +;            } i = last + 1;            j = high;                while (J > right && arr[i]! = key) {Swap (arr, I, j);                i++;            j--;   }         Qsortthreeinsertgather (arr, Low, first-leftlength-1);        Qsortthreeinsertgather (arr, first + rightlength + 1, high); }

Test data:

Test data analysis: Three number of + interpolation + aggregation of equal elements of the combination, the effect is surprisingly good.

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.

In fact here, the role of Plug and Play is not big.

The following is the full source of the test program:

Using system;using system.collections.generic;using system.linq;using system.text;using System.Threading.Tasks; Using system.diagnostics;using System.threading;namespace sort{class Program {static void Main (string[] Arg            s) {//Open 10M of stack space thread ThreadStart ts = new ThreadStart (sort.doqsort);            Thread thread = new Thread (ts, 10000000); Thread.        Start ();                        }} class Sort {public static void Doqsort () {int[] arr = new int[100000];            An array of 10W spatial sizes//random rd = new Random (); for (int i = 0; i < arr. Length; i++)//random array//{//arr[i] = Rd.            Next (); }//for (int i = 0; i < arr. Length;            i++)//ascending array//{//arr[i] = i; }//for (int i = 0; i < arr. Length; i++)//descending array//{//arr[i] = arr.  Length-1-I;          } for (int i = 0; i < arr. Length;            i++)//repeating array {arr[i] = 5768461;            } Stopwatch Watch = new Stopwatch (); Watch.                                  Start (); Start Timing//qsortcommon (arr, 0, arr.)          LENGTH-1); Fixed datum element//qsortrandom (arr, 0, arr.          LENGTH-1); Random datum element//qsortmedianofthree (arr, 0, arr.)   LENGTH-1); Three-digit//qsortthreeinsert (arr, 0, arr.)     LENGTH-1); Three-digit + interpolation qsortthreeinsertgather (arr, 0, arr.) LENGTH-1); Three-digit + interpolation + gather the same element watch.                                   Stop (); Time to end Console.WriteLine (watch.        Elapsedmilliseconds.tostring ()); }///<summary>//1.0 Fixed datum element (Basic quick Sort)///</summary> public static void Qsortcomm                        On (int[] arr, int. Low, int.) {if (Low >= high) return; recursive exit int partition = PaRtition (arr, low, high);            Swap the elements of >= X to the right area and swap the elements of <= X to the left area Qsortcommon (arr, Low, partition-1);        Qsortcommon (arr, partition + 1, high); }///<summary>//2.0 stochastic datum///</summary> public static void Qsortrandom (int[]                        arr, int low, int.) {if (Low >= high) return;                Recursive exit Partitionrandom (arr, low, high);      Random datum element int partition = partition (arr, low, high);            Swap the elements of >= X to the right area and swap the elements of <= X to the left area qsortrandom (arr, Low, partition-1);        Qsortrandom (arr, partition + 1, high); }///<summary>//3.0 three-digit///</summary> public static void Qsortmedianofthree (                        Int[] arr, int low, int.) {if (Low >= high) return;         Recursive exit Partitionmedianofthree (arr, low, high); three-digit int partition = Partition (arr, low, high);            Swap the elements of >= X to the right area and swap the elements of <= X to the left area qsortmedianofthree (arr, Low, partition-1);        Qsortmedianofthree (arr, partition + 1, high); }///<summary>//4.0 three-digit +///</summary> public static void Qsortthr Eeinsert (int[] arr, int low, int. high) {if (high-low + 1 <) {Inserts                ORT (arr, low, high);            Return         }//Plug-in, recursive exit Partitionmedianofthree (arr, low, high);      three-digit int partition = partition (arr, low, high);            Swap the elements of >= X to the right area and swap the elements of <= X to the left area qsortmedianofthree (arr, Low, partition-1);        Qsortmedianofthree (arr, partition + 1, high); }///<summary>//5.0 three-digit + interpolation + aggregation same element///</summary> public static void Q Sortthreeinsertgather (int[] arr,int low, int.) {if (high-low + 1 <) {Insertsort (arr, low, high);            Return         }//Plug-in, recursive exit Partitionmedianofthree (arr, low, high);            Three-digit middle//left-right grouping (processing of equal elements) int first = low;            int last = high;            int left = low;            int right = high;            int leftlength = 0;            int rightlength = 0;            int key = Arr[first];                while (first < last) {when (First < last && Arr[last] >= key) {if (arr[last] = = key)//process equal element {Swap (arr                        , last, right);                        right--;                    rightlength++;                } last--;                } Arr[first] = Arr[last]; while (First < last&& Arr[first] <= key) {if (arr[first] = = key) {                        Swap (arr, first, left);                        left++;                    leftlength++;                } first++;            } Arr[last] = Arr[first];            } Arr[first] = key;            One quick line end//move the element with the same reference element key to the final position around int i = first-1;            int j = Low;                while (J < left && arr[i]! = key) {Swap (arr, I, j);                i--;            j + +;            } i = last + 1;            j = high;                while (J > right && arr[i]! = key) {Swap (arr, I, j);                i++;            j--;            } qsortthreeinsertgather (arr, Low, first-leftlength-1);        Qsortthreeinsertgather (arr, first + rightlength + 1, high); }        /// <summary>///fixed datum, default array the first number is the Datum element, left and right group, return the subscript of the Datum element//</summary> public static int Partition (            Int[] arr, int low, int.) {int first = low;            int last = high;                             int key = Arr[low]; Take the first element as the base element while (initial < last) {while (primary < last && Arr[last] &                gt;= key) last--;                Arr[first] = Arr[last];                while (first < last && Arr[first] <= key) first++;            Arr[last] = Arr[first];                               } Arr[first] = key;        The datum element is centered in return first; }///<summary>///random datum, will determine good datum element and first number exchange, no return value///</summary> public Stati            c void Partitionrandom (int[] arr, int low, int. high) {Random rd = new Random (); int randomindex = Rd. Next ()% (high-low) + low;//random subscript Swap (arr, Randomindex, low) in the array;                With the first number of exchanges}///<summary>///Three to determine the base element, will determine the good datum and the first number of exchanges, no return value///</summary>  public static void Partitionmedianofthree (int[] arr, int. Low, int.) {int mid = low + (high            +-low)/2;            if (Arr[mid] > Arr[high]) {Swap (arr, Mid, High);            } if (Arr[low] > Arr[high]) {Swap (arr, low, high);            } if (Arr[mid] > Arr[low]) {Swap (arr, Mid, Low);        }//Convert the middle size to the first number of exchanges}///<summary>///Insert Sort </summary> public static void Insertsort (int[] arr, int. Low, int.) {for (int i = low + 1; I <= high;               i++) {if (Arr[i] < arr[i-1]) {     for (int j = Low; J < I; J + +) {if (Arr[j] > Arr[i])                        {Swap (arr, I, j); }}}}}//<summary> array Exchange///&LT;/S            ummary> public static void Swap (int[] arr, int index1, int index2) {int temp = arr[index1];            ARR[INDEX1] = Arr[index2];        ARR[INDEX2] = temp; }    }}

Go to three quick sort algorithms and quick sort 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.