One article clarifies the difference between direct insertion, quick sort and Hill sort in the sorting algorithm

foreword

In the last article, I introduced bubble sort and selection sort , both of which are sorting algorithms. In fact, sorting algorithms include insertion, Hill, quick sorting , etc. Next, let's learn about these sorting algorithms.


The full text is about [ 5400] words, no nonsense, just pure dry goods that allow you to learn techniques and understand principles! This article has a wealth of cases and videos with pictures, so that you can better understand and use the technical concepts in the article, and can bring you enough enlightening thinking...

1. Direct insertion sort

1. Concept

Direct insertion sort (Insertion Sort) , as the name suggests, is to insert unsorted elements into the ordered collection one by one. When inserting, the ordered collection is scanned from the back to the front to find the appropriate insertion position. In order to let everyone better understand insertion sort, let me explain the meaning of insertion sort through a simple example. Let's take the card game in daily life as an example:

image.png

At the beginning, the above-mentioned cards were out of order, and we tried to sort the above-mentioned cards.

(1) For the first time, the first card 8 is regarded as a sorted card, and the 5, 3, and 9 on the right are not sorted.

image.png

(2) For the second time, insert 5 into the sorted team, 5 is smaller than 8, and put it in front of 8.

image.png

(3) For the third time, insert 3 into the sorted queue. 3 is smaller than 5 and 8, so it is placed in front of 5.

image.png

(4) For the fourth time, insert 9 into the sorted team. 9 is bigger than other cards, so it is placed at the end.

After the above steps, all the cards are in order.

2. Implementation principle

The implementation principle of insertion sort is actually to divide the array into two parts: ordered interval and unordered interval . Initially, there is only one element in the ordered interval, which is the first element of the sequence. Then take an element from the unordered interval and insert it at the end of the ordered interval, and compare the size of the newly inserted element with the data in the ordered interval one by one. If the data is greater than the last data in the ordered interval, the position is not exchanged, and it can be directly inserted at the end of the ordered interval. If the data is smaller than the last data in the ordered interval, it needs to be transposed. After the transposition, the data will continue to be compared with the previous data, and the comparison will not stop until a suitable position is found.

3. Implementation steps

According to the above implementation principle, let me sort out the implementation steps of insertion sort:

(1) Step 1: Extract elements from the second element of the array;

(2) Step 2: Compare it with the first element on the left. If the first element on the left is larger than it, continue to compare it with the second element on the left until it encounters an element that is less than or equal to it. Then insert to the right of this element.

(3) Step 3: Continue to select the 3rd, 4th...n elements, repeat step 2, and select an appropriate position to insert.

Now, we can demonstrate the process of insertion sort through a practical example. For example, there is an array [5, 8, 6, 3, 9, 2, 1, 7] to be sorted, the insertion sorting steps are as follows:

(1) Initially, there are only 5 in the ordered interval, and 8, 6, 3, 9, 2, 1, and 7 in the unordered interval.
insert image description here

(2) Insert the first element 8 of the unordered interval to the end of the sequence in the ordered interval. 8 and 5 are compared in size, and if 8 is larger than 5, there is no need to exchange positions. At this time, the elements in the ordered interval are 5 and 8, and the elements in the unordered interval are 6, 3, 9, 2, 1, and 7.

image.png

(3) Insert the first element 6 of the unordered interval to the end of the ordered interval to form the arrangement order of 5, 8, and 6. 6 is compared with the 8 on the left, if 6 is smaller than 8, then transpose; if 6 is compared with 5, if 6 is larger than 5, there is no need to transpose. Finally, the arrangement of 5, 6, and 8 is formed in the ordered interval. At this time, there are 3, 9, 2, 1, 7 in the disordered interval.

image.png

(4) Insert the first element 3 of the unordered interval to the end of the ordered interval to form the arrangement order of 5, 6, 8, and 3. 3 is compared with the 8 on the left, and if 3 is smaller than 8, transpose; 3 is then compared with 6, and if 3 is smaller than 6, continue to transpose; Finally, an arrangement of 3, 5, 6, and 8 is formed. At this time, there are 3, 5, 6, and 8 in the ordered interval, and 9, 2, 1, and 7 in the disordered interval.

image.png

(5) And so on, until the unordered interval is empty, the sorting ends. The final sorting results are: 1, 2, 3, 5, 6, 7, 8, 9.

image.png

4. Programming implementation

Next, we use the Java language to program the insertion sort algorithm:

public static void insertionSort(int[] arr) {
    
    
    int loop = 0;
    int count = 0;
    //对数组进行遍历
    for (int i = 0; i < arr.length; i++) {
    
    
        //第二个循环仅仅是将当前数据跟自己左边的数字进行比较,如果小于左边数字则交换位置,否则位置不变。
        for (int j = i; j > 0; j--) {
    
    
            count++;
            //此处使用break比使用if效率高,两者在比较次数上有差别。
            if (arr[j] >= arr[j - 1]) break;
            // 前后两个数据交换位置
            arr[j] = arr[j] + arr[j - 1] - (arr[j - 1] = arr[j]);
        }
    }
}

5. Summary

Next, we summarize the characteristics of insertion sort.

5.1 Time Complexity

According to the degree of confusion of the given sequence, the time complexity can be analyzed as follows:

(1) When the array itself is ordered, the time complexity of insertion sort is O(n). The reason is that if the sequence itself is ordered, the insertion sort needs to compare every two adjacent numbers once, and compare n-1 times in total, so the time complexity is O(n).

(2) When the sequence is unordered, n(n-1)/2 comparisons are required in the worst case, so the time complexity is O(n²).

5.2 Space Complexity

(1) Insertion sorting is in-place sorting, and its space complexity is O(1).

(2) In insertion sort, the elements in the unordered interval are compared with the elements on the left in turn when they are inserted into the ordered interval. If the two elements are equal, the positions are not exchanged.

5.3 Applicable scenarios of insertion sort

(1) A small array is integrated into a large ordered array, for example, a small array [0, 1] is integrated into a large ordered array [1, 2, 3, 4, 5, 6, 7, 8, 9}.

(2) Only a few elements in the array are not in the correct order, or the array is partially ordered.

In summary, insertion sorting is a relatively simple and intuitive sorting algorithm, suitable for processing small or partially ordered sequences of data.

2. Quick sort

1. Concept

Quick sort (Quick Sort) , which is an improvement to bubble sort, was proposed by Hoare in 1962. Like bubble sort, quick sort is also an exchange sort algorithm , which achieves the purpose of sorting by comparing and exchanging positions between elements.

Quick sort sets a reference point every time it sorts, puts all the numbers smaller than the reference point to the left of the reference point, and puts all the numbers greater than or equal to the reference point to the right of the reference point. In this way, each exchange will not only exchange between two adjacent numbers like bubble sorting, and the exchange distance will be improved. Quick sort is faster because each exchange is a jump compared to bubble sort. In this way, the total number of comparisons and exchanges is reduced, and the sorting efficiency is naturally improved.

By sorting in one pass, the data to be sorted is divided into two parts, all the data in one part are smaller than all the data in the other part, and then the two parts of the data are quickly sorted according to this method, and the whole sorting process is performed recursively , so that the entire data becomes an ordered sequence. The implementation idea of ​​the quick sort algorithm is the application of the idea of ​​​​divide and conquer.

2. Implementation idea

Quick sort is implemented based on recursion, and its implementation idea is as follows:

(1) Select an appropriate value (ideally, it is best to choose the median value of the sequence, but for the sake of convenience, the first value of the sequence is generally selected), which is called the "pivot".

(2) Based on the reference element, divide the series into two parts, the smaller part is on the left, and the larger part is on the right.

(3) After the first round, the position of this reference element must be at the final position.

(4) Repeat the above process for the left and right sub-arrays, until each sub-array contains only one element and the sorting is complete. The core idea of ​​quick sort is to find the correct position for the reference element.

3. Implementation steps

Next, an example is used to explain the steps of quick sorting.

Suppose now there is an out-of-order array [5, 8, 6, 3, 9, 2, 1, 7], we use the quick sort algorithm to sort. First, select an element as the reference element. In this example, we can select the first element 5 as the reference element. Next, exchange elements, the specific steps are as follows:

(1) Select the reference element 5, and set the two pointers as left and right to point to the leftmost element 5 and the rightmost element 7 respectively. The rules for moving and comparing are:

  • Starting from the position of the right pointer, compare the element pointed to by the pointer with the reference element. If the data pointed by the right pointer is smaller than the reference element, the right pointer stops moving; switch to the left pointer, otherwise the right pointer continues to move to the left.

  • When it is the turn of the left pointer to move, compare the element pointed to by the left pointer with the reference element. Compare the data pointed to by the left pointer with the reference element. If the element data pointed to by left is larger than the reference element, the left pointer stops moving, otherwise the left pointer continues to move to the right.

  • Swap the elements pointed by the left and right pointers.

(2) The right pointer starts first, and the data currently pointed to by the right pointer is 7. Since 7>5, the right pointer continues to move to the left, pointing to 1, and because 1<5, it stops at the position of 1.

  • It's the left pointer's turn. Since left starts to point to the reference element 5, so left is shifted to the right by 1 bit, pointing to 8. Since 8>5, the left pointer stops

  • Next, the elements pointed to by left and right are swapped. At this time, the sequence formed is [5, 1, 6, 3, 9, 2, 8, 7]

(3) Switch to the right pointer again, the pointer moves to the left, and the right pointer points to 2. Since 2<5, the right pointer stops at 2.

  • When it is the turn of the left pointer, the pointer moves right by 1 bit, pointing to 6. Since 6>5, the left pointer stops.

  • Next, the elements pointed to by left and right are swapped. At this time, the sequence formed is [5, 1, 2, 3, 9, 6, 8, 7].

(4) Switch to the right pointer again, and the pointer moves to the left. The right pointer points to 9. Since 9>5, the right pointer continues to move to the left and points to 3. Since 3<5, the right pointer stops at the position of 3.

  • When it is the turn of the left pointer, the pointer moves to the right by 1 bit, pointing to 3, at this time the right pointer and the left pointer overlap.

  • Next, exchange the pivot element 5 with the element 3 at the overlapping point, and the sequence is [3, 1, 2, 5, 9, 6, 8, 7]. The first round of sorting is over.

We make the above text description process into a corresponding schematic diagram, as shown below:

image.png

After the first round of sorting, the position of the reference element 5 in this round is the position after the final sorting. Next, we recursively sort the first half [3, 1, 2] on the left side of the reference element 5, and then sort the second half [9, 6, 8, 7] on the right side of element 5 ,As shown below:

image.png

(1) The first half of the reference element 5 [3, 1, 2], with 3 as the reference element, after sorting, the result is [2, 1, 3]. After the current round, the position of the reference element 3 of the current round is its final position.

(2) The queue [2, 1] on the left side of the reference element 3 in the last round is sorted with 2 as the reference element, and the sorting result is [1, 2]. After the current round, the position of the reference element 2 of the current round is its final position.

(3) Only element 1 is left on the left side of the last round of reference element 2, and 1 is its own reference element. In this way, the final position of element 1 is determined.

(4) The second half of the reference element 5 [9, 6, 8, 7], sorting with 9 as the reference element, the result is: [7, 6, 8, 9], after the current round, the current round of reference elements The position of 9 is its final position.

(5) The queue [7, 6, 8] on the left side of the reference element 9 in the last round is sorted with 7 as the reference element, and the result is [6, 7, 8]. After the current round, the position of the reference element 7 of the current round is its final position.

(6) Only 6 is left on the left side of the last round of reference element 7, and 6 is your own reference element. In this way, the final position of element 6 is determined.

(7) Only 8 is left on the right side of the reference element 7, and 8 is its own reference element. In this way, the final position of element 8 is determined.

(8) At this time, the reference elements 5, 3, 2, 1, 9, 7, 6, and 8 all find their correct positions, and the sorting ends.

4. Coding implementation

Next, we use the Java language to code the quick sort algorithm:

public static void quickSort(int[] arr, int start, int end) {
    
    
    // 递归结束条件:start大于或等于end时
    if (start < end) {
    
    
        // 得到基准元素位置
        int pivotIndex = partition(arr, start, end);
        // 根据基准元素,分成两部分进行递归排序
        quickSort(arr, start, pivotIndex - 1);
        quickSort(arr, pivotIndex + 1, end);
    }
}

private static int partition(int[] arr, int start, int end) {
    
    
    // 取第1个位置的元素作为基准元素
    int pivot = arr[start];
    int left = start;
    int right = end;

    while (left < right) {
    
    
        //right指针左移
        while (left < right && arr[right] >= pivot) right--;
        //left指针右移
        while (left < right && arr[left] <= pivot) left++;
        if (left >= right) break;
        //交换left和right 指针所指向的元素
        arr[left] = arr[left] + arr[right] - (arr[right] = arr[left]);
    }
    // 将基准元素与指针重合点所指的元素进行交换
    arr[start] = arr[left];
    arr[left] = pivot;
    
    return left;
}

quickSortTwo methods and partitionthe logic to implement the quick sort algorithm are used here . The core idea is consistent with the previous description. First, an element is found as the reference element, and then sorted separately.

3. Hill sorting

1. Concept

Shell's Sort , this algorithm is a type of insertion sort, also known as "Diminishing Increment Sort" , which was proposed by Shell in 1959.

Hill sort is a sorting algorithm based on the improvement of direct insertion sort. It is a more efficient and improved version of the direct insertion sort algorithm. Direct insertion sort itself is not efficient enough, insertion sort can only move data one bit at a time. When there is a large amount of data to be sorted, a large number of shift operations will be required. However, insertion sorting is very efficient when operating on almost sorted data, almost reaching the efficiency of linear sorting. Therefore, if the data can be preliminarily sorted to achieve basic sorting, and then insertion sorting will greatly improve the sorting efficiency. Hill sorting is formed based on this idea.

2. Implementation steps

The steps of Hill sorting are briefly described as follows:

(1) Group the elements according to the step size gap, and the value of the gap is actually the number of groups. The initial value of the gap is half the length of the sequence, and the gap is reduced to half of the original value every cycle.

(2) Use the direct insertion sort algorithm to sort each group of elements.

(3) As the step size gradually decreases, there are fewer groups and more elements contained in the groups.

(4) When the step value is reduced to 1, the entire data is combined into one group, and finally this group of arrays is adjusted by direct insertion sorting, and the sorting is finally completed.

Let's take the unordered sequence [5, 8, 6, 3, 9, 2, 1, 7, 4] as an example to introduce the steps of Hill sorting in detail:

(1). The first round of sorting, gap = length/2 = 4, that is, the array is divided into 4 groups. The four groups of elements are [5, 9, 4], [8, 2], [6, 1], [3, 7]. The results of sorting the four groups of elements are: [4, 5, 9], [2, 8], [1, 6], [3, 7]. Merge the four sets of sorting results to get the first round of sorting results: [4, 2, 1, 3, 5, 8, 6, 7, 9]. As shown below.

image.png

(2). The second round of sorting, gap = 2, divide the sequence into 2 groups. The elements of the two groups are [4, 1, 5, 6, 9] and [2, 3, 8, 7]. The results of these two groups performing direct insertion sorting are [1, 4, 5, 6, 9] and [2, 3, 7, 8]. The result after combining the two groups is [1, 2, 4, 3, 5, 7, 6, 8, 9], as shown in the figure below.

image.png

(3). The third round of sorting, gap = 1, the array becomes a group. The elements of this group are [1, 2, 4, 3, 5, 7, 6, 8, 9], and the result of this group after performing direct insertion sorting is [1, 2, 3, 4, 5, 6, 7, 8 , 9], this result is the result obtained after the third round of sorting. At this point the sorting is complete, as shown in the figure below.

image.png

3. Coding implementation

Next, we use the code to program the Hill sort:

public static void shellSort(int[] arr) {
    
    
    int loop = 0;
    //增量gap,并逐步缩小增量
    for (int gap = arr.length / 2; gap > 0; gap /= 2) {
    
    
        //对一个步长区间进行比较 [gap,arr.length)
        for (int i = gap; i < arr.length; i++) {
    
    
            //对步长区间中具体的元素进行比较
            for (int j = i - gap; j >= 0; j -= gap) {
    
    
                //System.out.println("j=" + j);
                if (arr[j] <= arr[j + gap]) break;
                //换位
                arr[j] = arr[j] + arr[j + gap] - (arr[j + gap] = arr[j]);
            }
        }
    }
}

4. Summary

Next, we analyze and summarize the complexity of Hill sorting, as follows:

(1) The time complexity of Hill sorting is related to the selection of the increment (that is, the step size gap). For example, when the increment is 1, Hill sort degenerates into direct insertion sort, and the worst case time complexity is O(n²). While the average time complexity of Hill sort with increment is O(n^1.3), the best case time complexity of Hill sort is O(n).

(2) The space complexity of Hill sorting is O(1).

(3) Direct insertion sorting is stable and will not change the relative order of the same elements. But in different insertion sort processes, the same elements may move in their respective insertion sorts, and finally their stability will be disturbed. That is to say, for the same two numbers, they may be divided into different groups and cause their order to change, so Hill sorting is unstable.


4. Conclusion

So far, we have introduced five classic sorting algorithms, including bubble sort, selection sort, insertion sort, quick sort, and Hill sort . In addition, there are some classic sorting algorithms such as heap sorting, merge sorting, bucket sorting, and counting sorting .

You will find that the steps and process of our introduction to the sorting algorithm are the same, basically including algorithm concepts, ideas and principles, algorithm steps, and coding implementation.

At the end of this article, we summarize the comparison and summary of classic sorting algorithms for you. We make a horizontal summary from several aspects such as time complexity, space complexity, and stability.

Sorting Algorithm Time complexity (average) Time complexity (worst) Time complexity (best) space complexity stability
Bubble Sort O(n2) O(n2) O(n) O(1) Stablize
selection sort O(n²) O(n²) O(n²) O(1) unstable
insertion sort O(n²) O(n²) O(n) O(1) Stablize
quick sort O(nlogn) O(n²) O(nlogn) O(nlogn) unstable
heap sort O(nlogn) O(nlogn) O(nlogn) O(1) unstable
Hill sort O(n^1.3) O(n²) O(n) O(1) unstable
merge sort O(nlogn) O(nlogn) O(nlogn) O(n) Stablize
bucket sort O(n+k) O(n²) O(n) O(n+k) Stablize
counting sort O(n+k) O(n+k) O(n+k) O(n+k) Stablize
radix sort O(d(n+k)) O(d(n+k)) O(d(n+k)) O(n+k) Stablize

Guess you like

Origin blog.csdn.net/GUDUzhongliang/article/details/131081729