Did you have a good evening? Not exist!!!
In the Java data structure and algorithm (three)--bubble, select, insert sorting algorithm we introduced three simple sorting algorithm, their time complexity is large o notation is O (N2), if the amount of data is small, we can endure, but the volume of data is large, So the time required for these three simple sorts is something we can't accept. Then we explain the recursion, introduced the merge sort, the merge sort needs O (Nlogn), which is much faster than the simple sort, but the merge sort has a drawback, it needs twice times the space of the original array, when we need to sort the data occupy more than half of the total memory space, Then the merge sort cannot be used.
This blog will cover several advanced sorting algorithms: Hill sort and quick sort.
1. Hill sort
The hill sort is based on the direct insert sort, which adds a new feature to the direct insert sort, greatly improving the execution efficiency of the insertion sort. So before we go into Hill sort, let's review the direct insert sort.
①, direct Insert sort
Direct insertion sort The basic idea is that each step is to insert a record to be sorted into an ordered sequence that is already in sequence until all elements have been inserted.
The implementation code is:
Package Com.ys.sort;public class Insertsort {public static int[] Sort (int[] array) {int j;//start with an element labeled 1 to select the appropriate location to insert, Because there is only one element for subscript 0, the default is ordered for (int i = 1; i < Array.Length; i++) {int tmp = array[i];//records the data to be inserted j = i;while (J > 0 && ; TMP < ARRAY[J-1]) {//from the rightmost beginning of the sorted sequence, find a number smaller than its array[j] = array[j-1];//backward nudge j--;} ARRAY[J] = tmp;//exists smaller than its number, insert}return array;}}
We can analyze this direct insert sort, first we will need to insert the number in a temporary variable, which is also a marker, the number of the left side of the marker is already ordered, the number of the right of the marker will need to be sorted. The number of marks is then compared with the number of rows on the left, if the number is larger than the number of targets, the left-hand sequence is shifted to the right by one, until it is found to be smaller than its position to insert.
There is an efficiency problem here, if a very small number in a very close to the right position, such as the right to sort of data 1, so that the very small number 1 is inserted into the left side of the ordered position, then the left row of data items must be moved to the right, this step is nearly executed n copy, Although not every data item must move n locations, each data item is moved on average N/2 times, in total N2/2, so the efficiency of the insertion sort is O (N2).
Then if you do not need to move all the data items in the middle of a certain way, you can move the smaller data items to the left, then the efficiency of the algorithm will be greatly improved.
②, Hill sort plot
Hill sort came into being, hill sort by increasing the interval of the elements in the sort, and inserting sorts in these spaced elements, the data items can be moved in a large span. When these data items are sequenced, the hill sorting algorithm decreases the interval of the data items and then sorts them, then goes on, and the last interval is 1 o'clock, which is the simple direct insertion sort we said above.
Shows the first step to sort the 10 array elements with an increment of 4 o'clock, first sorting the elements with the subscript 0,4,8, and after sorting, the algorithm moves right one step, sorts the 1,5,9 elements, and so on, until all the elements are sorted, That is, elements with an interval of 4 are already ordered.
When we finish the 4-delta sort, the normal insertion sort, that is, the 1-delta sort, is much faster than the simple insert sort that was performed directly before.
③,Sorting interval Selection
For 10 elements, we choose 4 of the interval, then 100 data, 1000 data, and even more data, how should we choose the interval?
In Hill's manuscript, he suggested that the interval be selected as N/2, that is, each trip would be divided into two halves, so for the n=100 array, the gradual reduction of the interval sequence is: 50,25,12,6,3,1. The benefit of this method is that you do not need to calculate the sequence before starting the order to find the interval of the initial sequence, just divide n by 2. But this has proven not to be the best sequence.
The number coprime in the interval sequence is an important indicator, that is, they do not have the number of conventions except for 1. This constraint makes each order more likely to keep the previous row sorted, while the inefficiency of Hill's initial N/2 interval is not complying with this rule.
So a hill's deformation method is to divide each interval with 2.2来, and for n=100 arrays, the sequence 45,20,9,4,1 is generated. This can significantly improve the sorting effect by dividing it by 2.
There is also a very common interval sequence:Knuth interval sequence 3h+1
But no matter what interval sequence, the final must meet a condition, that is, the gradual reduction of the interval must be equal to 1, so the last order must be a simple insertion sort.
Here we are using the Knuth interval sequence to implement the hill sort:
implementation of Hill sort algorithm for ④ and Knuth interval sequences
Hill sort Knuth interval sequence 3h+1public static void Shellknuthsort (int[] array) {SYSTEM.OUT.PRINTLN ("original array" +arrays.tostring (array) int step = 1; int len = Array.length;while (step <= len/3) {step = Step*3 + 1;//1,4,13,40 ...} while (Step > 0) {//each increment interval is sorted separately for (int i = step; i < Len; i++) {int temp = Array[i];int J = i;while (J > Step-1 & amp;& temp <= Array[j-step]) {Array[j] = array[j-step];j-= step;} ARRAY[J] = temp;} End ForSystem.out.println ("+step+" is sorted as "+arrays.tostring (Array)"); step = (step-1)/3;} End while (step>0) System.out.println ("final sort:" +arrays.tostring (array));}
Test results:
public static void Main (string[] args) {int[] array = {4,2,8,9,5,7,6,1,3,10};shellknuthsort (array);}
⑤, Interval 2h of hill sort
Hill sort interval sequence 2hpublic static void Shellsort (int[] array) {SYSTEM.OUT.PRINTLN ("original array" +arrays.tostring (array)); int step; int len = array.length;for (step = LEN/2; step > 0; Step/= 2) {//each increment interval is sorted for (int i = step; i < array.length; i++) {int J = I;int temp = array[j];if (Array[j] < Array[j-step]) {while (J-step >=0 && temp < Array[j-step]) {Array[j] = array[j-step];j-= step;} ARRAY[J] = temp;}} System.out.println ("+step+" is sorted as "+arrays.tostring (Array)");}}
Test results:
2. Quick Sort
Quick Sort is an improvement on the bubbling sort, by C. A. R. Hoare in 1962 introduced a sort of divide-and-conquer strategy that uses a split-and-rule approach (typically combined with recursion) to reduce the number of comparisons in the sequencing process.
The basic idea of ① and quick sorting
First, the array is divided into two parts , and all of the data in one part is smaller than all the data in the other part . The original array was divided into 2 parts
Second, through the processing of recursion, and the two parts of the original array division divided into two parts, the same is to make part of all the data is less than the other part of all the data. This time the original array was divided for 4 copies.
Three, 1, 2 is divided by the smallest element sub-array, they are still unordered, but! The original array they consist of is gradually moving in an orderly direction.
Finally, the array is divided into a plurality of elements consisting of one element or multiple identical elements, so that the array is ordered.
Specific examples:
For array [3,1,4,1,5,9,2,6,5,3], the array is divided into [2,1,1] or [4,5,9,3,6,5,3] two sub-arrays by the first order, and for any element, the left sub-array is always smaller than the right sub-array. Finally get an ordered array through constant recursive processing [1 1 2 3 3 4 5 5 6]
Algorithm implementation of ② and fast sorting
Suppose that the unordered interval ordered is [a[i],......, A[j]]
one, Datum element selection: Select one of the records of the keyword V as the datum element (control keyword); How do I choose a keyword?
Division: by the Datum element v the disordered interval a[i] ... A[J] is divided into the left and right parts, so that the left side of the records of the keywords are less than v; )
Three, recursive solution: Repeat the above one or two steps, respectively, the left and right two parts of the recursive fast sorting.
Four, combination: left and right two parts are orderly, then the whole sequence is orderly.
The third to fourth step above does not need to say, mainly is the first step how to select the keyword, so as to achieve the second step of the division?
The process of partitioning involves three keywords:datum element, left cursor, right cursor
datum elements: It is the process of dividing an array into two sub-arrays, which is used to define the value of the size, to judge the criteria, to "divide" the array elements smaller than it into a "array of decimal values", and to "divide" the array elements larger than it into a "array of large values", so that We split the array into two sub-arrays, and the elements of one of the sub-arrays are less than the elements in the other subarray.
Zoo: It initially points to the leftmost array element of the array to be split, and it moves to the right during the sort process.
Right cursor: It initially points to the rightmost array element of the array to be split, which moves to the left during the sort process.
Note: The datum elements/Right cursors/Zoo described above are for single-pass sequencing , that is, the Datum elements/Right cursors /Zoo that are obtained in the sequencing of the overall sorting process are generally different.
The selection of datum elements is, in principle, arbitrary. But generally we select the first element in the array as the Datum element (assuming the array is randomly distributed)
③, Quick sort diagram
The above represents an unordered array, which selects the first element 6 as the datum element. Zoo is the I sentinel, and the right cursor is the J Sentinel. Then the Zoo moves to the left and the right cursor moves to the right, and they follow the following rules:
First, Zoo to the right , across all array elements that are less than the base element , until you encounter an array element that is greater than or equal to the Datum element , stopping at that position.
The right cursor scans the left and crosses all array elements that are larger than the datum element until it encounters an array element that is less than or equal to the datum element and stops at that position .
The first step: Sentinel J starts out first. Because the number of bases set here is the leftmost number, you need to let Sentinel J start out, and Sentinel J moves left one step at a--until a single element less than 6 is found to stop. Next, Sentinel I moves right one step at a pace until it finds an element greater than 6 to stop. The last sentinel I stopped in front of the number 7, Sentinel J stopped in front of the number 5.
By this, the first exchange ended, then Sentinel J continued to move to the left, it found that 4 is smaller than the base number 6, then stop at the number 4. Sentinel I also moves to the right and then stops in front of the number 9, then Sentinel I and Sentinel J are exchanged again.
At the end of the second exchange, Sentinel J continued to move to the left, then stopped before the number 3, and Sentinel I continued to move to the right, but it found that it had met Sentinel J. At this point, the probe ends, the number 3 and the reference number 6 are exchanged, as follows:
To this, the first probe really ended, at this point, the Datum point 6 is the dividing line, 6 the left array element is less than or equal to 6, 6 the right array element is greater than or equal to 6.
The left sequence is "3,1,2,5,4" and the right sequence is "9,7,10,8". Then for the left sequence, the number 3 is the datum element, repeat the above detection operation, the sequence after the detection is "2,1,3,5,4", and for the right sequence, the above probe is repeated with a number 9-bit datum element. Then, step by step, the final sort ends completely.
With this step-by-step decomposition, we find that each round of the quick sort is to place the datum number in place, knowing that all the numbers are in place and the sort is finished.
④, quick Sort complete code
Package Com.ys.high.sort;public class QuickSort {//array the elements in the "I" and "J" positions are exchanged for private static void swap (int[] array, int i, I NT j) {int temp = Array[i];array[i] = array[j];array[j] = temp;} private static void Recquicksort (int[] Array,int left,int right) {if (right <= left) {return;//terminates recursive}else{int partition = Partitionit (array,left,right); Recquicksort (array,left,partition-1);//For the previous round of sorting (slicing), the sub-array to the left of the datum element is recursively recquicksort ( Array,partition+1,right);//For the previous round of sorting (slicing), the sub-array to the right of the datum element is recursive}}private static int partitionit (int[] Array,int left,int {//Why J plus a 1, and I do not add 1 because the following loop is judged to start with--j and ++i.//While the base element is selected Array[left], that is, the first element, so Zoo starts from the second element to compare int i = left;int j = right+1; int pivot = array[left];//Pivot is the selected datum element (head Element) while (true) {while (I<right && array[++i] < pivot) {}while (J & Gt 0 && Array[--j] > Pivot) {}if (i >= j) {///left and right cursors stop when the cursor encounters, so jump out of the outside while loop break;} Else{swap (Array, I, j);//Stop when the cursor is not met, swap the respective elements, and loop to continue}}swap (array, left, j);//reference element and cursor meet when the element is exchanged, for the last exchange return j;//a trip sort complete That returns the position of the Datum element (note that the datum element has swapped bits here}public static void sort (int[] array) {recquicksort (array, 0, array.length-1);} Test public static void main (string[] args) {//int[] array = {7,3,5,2,9,8,6,1,4,7};int[] array = {9,9,8,7,6,5,4,3,2,1};sor T (array); for (int i:array) {System.out.print (i+ "");} Printed Result: 1 2 3 4 5 6 7 7 8 9}}
⑤, optimization analysis
Let's say we sort an inverse array, select the first element as the datum point, that is, the largest element is the datum point, then the first loop, the Zoo is executed to the far right, and the right cursor executes once, and the two are exchanged. This will also be divided into a number of sub-arrays.
So how to solve it? Ideally, the median data of the sorted array should be chosen as the benchmark, that is, half the number is greater than the base number, and the general number is less than the base number, so that the array is divided into two sub-arrays of equal size, and it is best to have two sub-arrays of equal size for fast sorting.
The three-item-taking Division
In order to find the median data in an array, we usually take the first, middle, and last of the array, and select the number in the middle of the three numbers.
Take the array subscript the first number, the middle number, the last number of the middle value private static int medianOf3 (int[] Array,int left,int right) {int center = (right-left)/2+left if (Array[left] > Array[right]) {//Get Array[left] < Array[right]swap (array, left, right);} if (Array[center] > Array[right]) {//Get Array[left] Array[center] < Array[right]swap (array, center, right);} if (Array[center] > Array[left]) {//Get Array[center] < Array[left] < Array[right]swap (array, center, left);} return Array[left]; The value of Array[left] has been replaced with the median of three digits, returning it}
private static int Partitionit (int[] Array,int left,int right) {//Why J plus a 1, and I do not add 1 because the following loop is judged to start with--j and ++i.// The base element is selected Array[left], that is, the first element, so Zoo starts from the second element to compare int i = left;int J = Right+1;int pivot = array[left];//pivot for the selected datum element (head element) int Si Ze = right-left + 1;if (size >= 3) {pivot = medianOf3 (array, left, right);//array range is greater than 3, the datum element selects an intermediate value. }while (True) {while (I<right && array[++i] < pivot) {}while (J > 0 && array[--j] > Pivot) {}if (I & Gt;= j) {///left and right cursors stop when they meet, so jump out of the outside while loop break;} Else{swap (Array, I, j);//Stop when the cursor is not met, swap the respective elements, and loop to continue}}swap (array, left, j);//reference element and cursor meet when the element is exchanged, for the last exchange return j;//a trip sort complete , return the Datum element position (note that the datum element has swapped position here)}
Handling Small Divisions
If you use the three-data-taking method, you must follow the fast sort algorithm to not execute three or less than three of the data, if a large number of sub-arrays are less than 3, then the use of fast sorting is more time-consuming. We talked about a simple sort (bubbling, selecting, inserting) in front of us.
When the array length is less than M (high-low <= m), the insertion sort is not done in a fast row. The optimal value of the conversion parameter m is related to the system, and in general, any value between 5 and 15 can be satisfactory in most cases.
Insert sort private static void Insertsort (int[] array) {for (int i = 1; i < Array.Length; i++) {int temp = Array[i];int J = i while (J > 0 && array[j-1] > Temp) {array[j] = array[j-1];j--;} ARRAY[J] = temp;}}
Java Data structures and algorithms (ix)--Advanced sorting