Sorting is closely related to our daily life, for example, we want to find a contact from the phone book first will be sorted by last name, buy train tickets will be sorted according to the departure time or time, shopping will be sorted by sales or praise, find the file will be sorted by the time of modification and so on. In computer programming, sorting and finding is also the most basic algorithm, many other algorithms are based on the sorting algorithm, in the general data processing or analysis, usually the first step is to sort, for example, binary search, the first to sort the data. In the four volumes of the Art of computer programming by Donald Knuth, one volume is devoted to sorting and finding.
There are many algorithms for sorting, there is a category on Wikipedia, and we are interested in reading the relevant algorithms directly on Wikipedia, this article also refers to the above content.
First of all, compare the simple selection sort (Selection sort), insert sort (insertion sort), and then on the basis of analyzing the features and drawbacks of the insert sort, introduce the improved hill sort (Shell sort) based on the insertion sort.
a selection sort
principle :
The choice of sorting is simple, and his steps are as follows:
- Traverse from left to right, find the smallest (large) element, and then swap with the first element.
- Continue looking for the smallest (large) element from the remaining unsorted elements, and then swap with the second element.
- And so on until all elements are sorted.
It's called selection sorting because every time we traverse an unordered sequence, we always choose the smallest element from it. Here is an animated demonstration of the selection sort:
Realize:
The algorithm is also very simple to implement, we create a new sort generic class, let the type must implement the IComparable interface, and then we define the Selectionsort method, the method passed into the T array, the code is as follows:
// <summary>///sort algorithm generic class, requires type implementation IComparable Interface/// </summary>///<typeparam name= "T" ></typeparam>Public classSort<T>whereT:IComparable<t>{/// <summary> //Select Sort//</summary>// <param name= "Array" ></param>Public static voidSelectionsort (t[] array) {intn = array. Length; for(inti = 0; i < n; i++) { intmin = i; //Starting with the first I+1 element, find the minimum value for(intj = i + 1; j < N; j + +) { if(Array[min]. CompareTo (Array[j]) > 0 min = j; } //Find and Exchange after element ISwap (array, I, min); } } /// <summary> //element Exchange//</summary>//<param name= "Array" ></param>//<param name= "I" ></param>// /<param name= "min" ></param>private static voidSwap (t[] array,intI,intmin) {T temp = array[i]; Array[i] = Array[min]; Array[min] = temp; }}
The process of selecting each order in the sorting is analyzed, and you can look at the histogram on the right side of the chart.
The test is as follows:
static voidMain (string[] args) { Int32[] array =NewInt32[] {1, 3, 1, 4, 2, 4, 2, 3, 2, 4, 7, 6, 6, 7, 5, 5, 7, 7}; Console. WriteLine ("before Selectionsort:"); PrintArray (array); Sort<Int32. Selectionsort (array); Console. WriteLine ("after Selectionsort:"); PrintArray (array); Console. ReadKey ();}
Output Result:
Analysis:
The sorting effect of the selected sort under various initial conditions is as follows:
- Select Sort takes (n–1) + (n–2) + ... + 1 + 0 = N (N-1)/2 ~ N2/2 times comparison and N-1 Secondary exchange operations.
- The initial data is not sensitive, regardless of the initial data is not ordered, it is necessary to undergo a N2/2 comparison, which for some of the original order, or approximate sequence of sequences without advantage. In the best case, that is, all the order, need 0 times exchange, worst case, reverse order, need N-1 times exchange.
- the number of data exchanges is less , and if an element is in the correct final position, it will not be moved. In the worst case, only a N-1 data exchange is required, and in all of the sorting methods that rely entirely on swapping to move elements, the choice of sorting is a good one.
Two insert Sort
principle :
Inserting a sort is also a more intuitive way to sort. can use our usual playing poker as an example to illustrate, assuming that our hands are in the hand of the cards are ordered, then the insertion of the order can be understood as we will touch each hand, and hands of the hand from left to right in turn to compare, if found the right position is inserted directly. The specific steps are:
- Starting with the first element, the element can be thought to have been sorted
- Takes the next element and scans the sequence of elements that have been sorted from back to forward
- If the element is smaller than the preceding element (sorted), then the comparison is compared to the previous element if it is less than the interchange until it is found to be greater than the element;
- If the element is larger than the previous element (sorted), repeat step 2
- Repeat steps until all elements are sorted.
Here is an animated demonstration of the insertion sort:
Realize:
In the sort generic method, we add the following method, as in the above definition
// <summary>///Insert Sort/// </summary>///<param name= "Array" ></param>Public static voidInsertionsort (t[] array) {intn = array. Length; //start with a second element for(inti = 1; i < n; i++) { //Starting from the first element, the first and the previous ordered i-1 elements are compared, if less than, then the Exchange for(intj = i; j > 0; j--) { if(Array[j]. CompareTo (Array[j-1]) < 0) {Swap (array, J, j-1); } Else//If greater than, then do not continue to compare, because the front of the elements have been ordered, larger than the large is the teaching of the big. Break; } }}
The test is as follows:
Int32Int32[] {1, 3, 1, 4, 2, 4, 2, 3, 2, 4, 7, 6, 6, 7, 5, 5, 7, 7}; Console . WriteLine ("before Insertionsort:"); PrintArray (array1); Sort < Int32 . Insertionsort (array1); Console . WriteLine ("after Insertionsort:"); PrintArray (array1); Console . ReadKey ();
Output Result:
Analysis:
The sort effect of the insertion sort under various initial conditions is as follows:
1. The average insertion order requires a N2/4 comparison and a N2/4-second exchange . In the worst case, N2/2 comparisons and exchanges are required, and in the best case only N-1 comparisons and 0 exchanges are required.
First consider the worst case, that is, all the elements in reverse order, then the first element needs to be compared with the previous I-1 elements i-1 and exchange, all add up is approximately equal to N (N-1)/2 ~ N2/2, in the case of random array, only the first half of the elements to compare and exchange, So the average need for N2/4 comparison and N2/4 Exchange.
In the best case, all elements are ordered, and only one can be compared to the previous element at the beginning of the second element, and no swap is required, so it is a N-1 comparison and 0 exchanges.
2. In the insert sort, the number of elements exchanged is equal to the logarithm of the reverse element in the sequence. The number of elements to compare is at least the logarithm of the element in reverse order, with a maximum of 1 of the logarithm plus the number of elements in reverse.
3. In general, the insertion sort is a more efficient way to sequence a partially ordered sequence and a smaller number of elements.
For example, sequence aeelmotrxps, the logarithm in reverse is t-r,t-p,t-s,r-p,x-s 6 pairs. Typical partial ordered queues are characterized by:
- Each element in the array is not too far away from the final sequence.
- Small unsorted array added to the large sorted array after
- Only individual elements in an array are not ordered.
For partially ordered arrays, the insertion sort is more efficient . When the logarithm of an inverse element in an array is lower, the insertion order is much more efficient than the other sorting methods.
Select a comparison of sort and insert sort :
Shows the animation effect of inserting sort and selecting sort. The gray pillars in the picture are not moving, the black ones need to be involved in the comparison, and the red ones are involved in the exchange. You can see in the figure:
Inserting a sort does not move the element to the right, and selecting sort does not move the left element, because the insertion sort involves less than the inserted element, and the comparison operation involves an average of less than half of the selection sort .
three-Hill sort (Shell sort)
Principle:
The hill sort is also known as the descending incremental sort, which is an improvement on the insertion sort. In the second insert sort, we know that the insertion order is very efficient in order to approximate the ordered sequence and can achieve the efficiency of linear sequencing. But the insertion sort efficiency is also relatively low, he can only move the data one bit at a time. For example, if a sequence of length n is the smallest element if it happens to be at the end, then using the Insert sort still requires step-after-step forward and comparison, to N-1 the comparison and exchange.
Hill sort increases the efficiency of the insertion sort by dividing the elements to be compared into several regions. This allows the element to take one step at a time to the final position, and then the algorithm takes smaller steps to sort, and the last step is 1 of the normal insertion sort, but at this time, the whole sequence is approximately ranked, so the efficiency is high.
For example, when we sort the following array, we first take 4 as the step, this is the element is divided into LMPT,EHSS,ELOX,AELR several sequences, we have the separate sequence to insert the sort, after the sort completes, we reduce the step to continue to sort, finally until the step is 1, A step of 1 is the general sort of insertion, and he guarantees that the elements will definitely be sorted.
The incremental decrement algorithm of the hill sort can be arbitrarily specified and can be decremented by N/2, as long as the last step is guaranteed to be 1.
Realize:
// <summary>///Hill Sort/// </summary>///<param name= "Array" ></param>Public static voidShellsort (t[] array) {intn = array. Length; inth = 1; //Initial maximum step size while(H < N/3) H = h * 3 + 1; while(H >= 1) {//start with a second element for(inti = 1; i < n; i++) { //Starting from the first element, the second and the previous ordered i-h elements are compared, if less than the Exchange for(intJ = i; j >= h; j = j-h) { if(Array[j]. CompareTo (Array[j-h]) < 0) {Swap (array, J, j-h); } Else//If greater than, then do not continue to compare, because the front of the elements have been ordered, larger than the large is the teaching of the big. Break; } } //step in addition to 3 decrementh = H/3; }}
As you can see, the implementation of the hill sort is improved on the basis of the insertion sort, the step of the insertion sort is 1, each decrements by 1, the step of the hill sort is defined by the H, and then each time compared to the element at the front-h position. In the algorithm, we first get the maximum step size smaller than N/3, and then gradually decrement to a general insertion sort of step 1.
Here is a sort of hill sort animation in various cases:
Analysis:
1. The key to the hill sort is the determination of the step descending sequence, any sequence that decrements to 1 steps, which is now known to be a better sequence:
- Shell's sequence: N/2, N/4, ..., 1 (Repeat divided by 2);
- Hibbard ' s sequence: 1, 3, 7, ..., 2k-1;
- Knuth ' s sequence: 1, 4,, ..., (3k-1)/2; the sequence is the sequence used in this article's code.
- The best known sequence is the sequence of Sedgewick ' s (Knuth's students, Algorithems's authors): 1, 5, 19, 41, 109, ....
The sequence is obtained by interacting with the following two expressions:
- 1, 109, 505, 2161,....., 9 (4k–2k) + 1, k = 0, 1, 2, 3,...
- 5, 209, 929, 3905,..... 2k+2 (2k+2–3) + 1, k = 0, 1, 2, 3, ...
"The comparison is the most important operation in the hill sort, not the exchange. "Hill sorting in such a step is faster than inserting sort and heap sorting, even faster than fast sorting in decimal groups, but Hill sorting is slower than fast sorting when large amounts of data are involved."
2. The analysis of hill sequencing is complex, with the time complexity of Hibbard's descending step sequence being O (N3/2), the average time complexity is about O (N5/4), and the specific complexity is still controversial.
3. Experiments show that for medium-sized sequences (million), the time complexity of the hill sort is close to the fastest sorting algorithm of the time complexity Nlogn.
Four Summary
Finally, summarize the best worst-case and average-time complexity of the three sorting algorithms presented in this article.
Name |
Best |
Average |
Worst |
Memory consumption |
Stable sorting |
Insert Sort |
N |
N2 |
N2 |
1 |
Is |
Select sort |
N2 |
N2 |
N2 |
1 |
Whether |
Hill sort |
N |
nlog2n Or N3/2 |
Depending on the increment descending sequence, the best is now nlog2n |
1 |
Whether |
I hope this article will help you understand the above three basic sorting algorithms, followed by the introduction of merge sorting and quick sorting.
Super-detailed interpretation of basic sorting algorithms (no regrets)