Common sorting algorithm, one article is enough

Sorting algorithm introduction

Sorting is also called
Sort Algorithm. Sorting is the process of arranging a set of data in a specified order.

Sorted categories:

1) Internal sorting:

Refers to loading all the data that needs to be processed into the internal memory for sorting.

2) External sorting method:

The amount of data is too large to load all of it into the memory, and it needs to be sorted with the help of external storage.

The classification of common sorting algorithms is shown in the figure:

Bubble Sort

The basic idea of ​​Bubble Sorting is: by treating the sorting sequence from front to back (starting from the element with the smaller subscript), comparing the values ​​of adjacent elements in turn, and if the reverse order is found, swapping to make the element with the larger value Gradually move from the front to the back, and gradually rise upwards like bubbles under the water.

Original array: 3, 9, -1, 10, 20

First pass sort

(1) 3, 9, -1, 10, 20 // Swap if adjacent elements are reversed

(2)  3, -1, 9, 10, 20

(3)  3, -1, 9, 10, 20

(4)  3, -1, 9, 10, 20

Second pass sort

(1) -1, 3, 9, 10, 20 //Exchange

(2) -1, 3, 9, 10, 20

(3) -1, 3, 9, 10, 20

Third pass sort

(1) -1, 3, 9, 10, 20

(2) -1, 3, 9, 10, 20

Fourth pass sort

(1) -1, 3, 9, 10, 20

Summary bubbling sorting rules

(1) Perform a total of -1 large loops for the size of the array

(2) The number of sorts in each pass is gradually decreasing

(3) If we find that there is no exchange in a certain round of sorting, we can end the bubbling sorting early. This is optimization

Because each element is constantly approaching its position during the sorting process, if there is no exchange in a comparison, the sequence is in order. Therefore, a flag must be set during the sorting process to determine whether the element has been exchanged. Thereby reducing unnecessary comparisons. (This

The optimization mentioned here can be performed after the bubble sort is written)

Code

public static void bubbleSort(int[] arr){
        int temp = 0;
        //标识变量,表示是否进行过交换
        boolean flag = false;
        //时间复杂度O(n^2)
        for (int i = 0; i < arr.length - 1; i++) { //一共要排序几次
            for (int j = 0; j < arr.length - 1 - i; j++) {//每次排序需要比较的次数
                if (arr[j] > arr[j + 1]){
                    flag = true;
                    temp = arr[j + 1];
                    arr[j + 1] = arr[j];
                    arr[j] = temp;
                }
            }
            if (flag){//出现过交换,重置flag
                flag = false;
            }else//在上一趟排序中,一次交换也没有发生过
                break;
        }
    }

Select sort

Selective sorting also belongs to the internal sorting method, which is to select an element from the data to be sorted according to the specified rules, and then exchange positions according to the regulations to achieve the purpose of sorting.

Choice sorting idea

Select sorting is also a simple sorting method. The basic idea is to select the minimum value from arr[0]~arr[n-1] for the first time, exchange with arr[0], and select from arr[1]~arr[n-1] for the second time Minimum value, exchange with arr[1], select the minimum value from arr[2]~arr[n-1] for the third time, exchange with arr[2],..., for the i-th time from arr[i-1]~arr Select the minimum value from [n-1], exchange with arr[i-1],..., select the minimum value from arr[n-2]~arr[n-1] for the n-1th time, and exchange it with arr[n- 2] Exchange, through n-1 times in total, get an ordered sequence arranged from small to large according to the sorting code

Original array: 101, 34, 119, 1

First round sorting:   1 , 34, 119, 101

Second round sorting:   1, 34 , 119, 101

Third round sorting:   1, 34, 101 , 119

Summary selection and sorting rules

1. Select the total array size for sorting-1 round of sorting

2. Every round of sorting is another cycle, the rules of the cycle (code)

2.1 First assume that the current number is the smallest number

2.2 Then compare with each of the following numbers, if you find a number smaller than the current number, re-determine the minimum number and get the subscript

2.3 When traversing to the end of the array, you will get the minimum number of this round and the subscript 2.4 Exchange [to continue in the code]

Code

public static void selectSort(int[]arr){
        for (int i = 0; i < arr.length - 1; i++) {
            int minIndex = i;
            int min = arr[i];
            for (int j = i + 1; j < arr.length; j++) {
                if (min > arr[j]){
                    minIndex = j;
                    min = arr[j];
                }
            }
            //将最小值放在arr[i],即交换
            if (minIndex != i){//如果最小值的下标改变了则交换
                arr[minIndex] = arr[i];
                arr[i] = min;
            }
        }
    }

Insertion sort

Insertion sorting belongs to the internal sorting method, which is to find the appropriate position of the element to be sorted by inserting it in order to achieve the purpose of sorting.

Insert sort idea

The basic idea of ​​insertion sorting (Insertion Sorting) is: treat n elements to be sorted as an ordered list and an unordered list. At the beginning, the ordered list contains only one element, and the unordered list contains n-1 Elements, each time the first element is taken from the unordered list during the sorting process, its sort code is compared with the sort code of the ordered list elements in turn, and it is inserted into the appropriate position in the ordered list to make it Become a new ordered list.

Original array: (101), 34, 119, 1

The orange arrow indicates the subscript of the element to be inserted

The green arrow indicates the element to be inserted

First insertion sort

Second insertion sort

Third insertion sort

Code

public static void insertSort(int[] arr){
        int insertIndex = 0;
        int insertValue = 0;
        for (int i = 1; i < arr.length; i++) {
            insertIndex = i - 1;
            insertValue = arr[i];
            while(insertIndex >= 0 && arr[insertIndex] > insertValue){
                arr[insertIndex + 1] = arr[insertIndex];
                insertIndex--;
            }
            //优化是否需要赋值
            if (insertIndex + 1 != i){
                arr[insertIndex + 1] = insertValue;
            }
        }
    }

Analyze the problems of simple insertion sort

Let's look at the possible problems of simple insertion sort.

Array arr = {2,3,4,5,6,1} The number 1 (minimum) that needs to be inserted at this time, the process is:

{2,3,4,5,6,6}

{2,3,4,5,5,6}

{2,3,4,4,5,6}

{2,3,3,4,5,6}

{2,2,3,4,5,6}

{1,2,3,4,5,6}

Conclusion: When the number to be inserted is a small number, the number of backward shifts is significantly increased, which has an impact on efficiency.

Hill sort

Hill sorting is a sorting algorithm proposed by Donald Shell in 1959. Hill sort is also a kind of insertion sort , it is a more efficient version of simple insertion sort after improvement, also known as reduced incremental sort.

Basic idea of ​​Hill sorting

Hill sorting is to group the records by a certain increment of the target, and use the direct insertion sorting algorithm to sort each group; as the increment decreases, each group contains more and more keywords. When the increment decreases to 1, The entire file is divided into one group, and the algorithm terminates

To make it easier for everyone to understand

When Hill sorting, the exchange method (bubbling method) is used first when inserting the ordered sequence

public static void shellSort(int[] arr){
        int temp = 0;
        int count = 0;
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
            for (int i = gap; i < arr.length; i++) {
                for (int j = i - gap; j >= 0; j -= gap) {
                    if (arr[j] > arr[j + gap]){//这里采用交换法
                        temp = arr[j];
                        arr[j] = arr[j + gap];
                        arr[j + gap] = temp;
                    }
                }
            }
        }
    }

When Hill sorting, the shift method (true Hill sorting) is used when inserting the ordered sequence (insertion method)

public static void shellSort(int[]arr){
        int count = 0;
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
            for (int i = gap; i < arr.length; i++) {
                int insertIndex = i - gap;
                int insertValue = arr[insertIndex + gap];
                while(insertIndex >= 0 && insertValue < arr[insertIndex]){
                    arr[insertIndex + gap] = arr[insertIndex];
                    insertIndex -= gap;
                }
                if (insertIndex != (i - gap)){
                    arr[insertIndex + gap] = insertValue;
                }
            }
        }
    }

Quick sort

Quicksort (Quicksort) is an improvement to bubble sort. The basic idea is: divide the data to be sorted into two independent parts by sorting, all the data in one part is smaller than all the data in the other part, and then quickly sort the two parts of the data according to this method. The entire sorting process can be carried out recursively, so that the entire data becomes an ordered sequence

Code

 public static void quickSort(int[] arr,int left,int right){
        int r = right;
        int l = left;
        int temp = 0;
        int pivot = arr[(right + left) / 2];
        while(l < r){
            while(arr[l] < pivot){
                l++;
            }
            while(arr[r] > pivot){
                r--;
            }
            if(l == r)
                break;
            temp = arr[r];
            arr[r] = arr[l];
            arr[l] = temp;
            if (arr[l] == pivot){
                r--;
            }
            if (arr[r] == pivot){
                l++;
            }
        }
        if (l == r){
            l += 1;
            r -= 1;
        }
        //向左递归
        if(left < r){
            quickSort(arr,left,r);
        }
        //向右递归
        if(right > l){
            quickSort(arr,l,right);
        }
    }

Merge sort

Merge sorting (MERGE-SORT) is a sorting method that uses the idea of ​​merging. The algorithm uses the classic divide-and-conquer strategy (divide-and-conquer) to divide the problem into small problems and then solve them recursively. , And the conquer stage "fixes" the answers obtained in the different stages together, that is, divide and conquer).

Note: It can be seen that this structure is very similar to a complete binary tree. The merge sort in this article is implemented recursively (it can also be implemented in an iterative way). Stages can be understood as the process of recursively splitting sub-sequences.

Let's take a look at the treatment stage. We need to merge two already ordered subsequences into an ordered sequence. For example, the last merge in the above figure requires [4,5,7,8] and [1,2, 3,6] Two already ordered subsequences are merged into the final sequence [1,2,3,4,5,6,7,8], let’s take a look at the implementation steps

Code

rule

/**
     *
     * @param arr   排序的原始数组
     * @param left  左边有序序列的初始索引
     * @param mid   中间索引
     * @param right 右边索引
     * @param temp  中转数组
     */
    public static void merge(int[] arr,int left,int mid,int right,int[]temp){
        //System.out.println("*****");

        int i = left;
        int j = mid + 1;
        int t = 0;

        /*
        (一)
        先把两边有序的数据按照规则填充到temp数组
        指导左右两边的有序序列,有一边处理完毕
        */
        while(i <= mid && j <= right){
            temp[t++] = arr[i] > arr[j] ? arr[j++] : arr[i++];
        }

        /*
        (二)
        把所有剩余数据的一边一次全部填充到temp
         */
        while(i <= mid){
            temp[t++] = arr[i++];
        }
        while (j <= right){
            temp[t++] = arr[j++];
        }

        /*
        (三)
        将temp数组的元素拷贝到arr
         */
        t = 0;
        int tempLeft = left;
        //System.out.println("tempLeft = " + tempLeft + "right = " + right);
        while(tempLeft <= right){
            arr[tempLeft++] = temp[t++];
        }
    }

Points (recursive)

public static void mergeSort(int[] arr,int left,int right,int[] temp){
        if(left < right){
            int mid = (left + right) / 2;
            mergeSort(arr,left,mid,temp);
            mergeSort(arr,mid + 1,right,temp);
            merge(arr,left,mid,right,temp);
        }
    }

Cardinality sort (bucket sort)

1. Radix sort (radix sort) belongs to "distribution sort", also known as "bucket sort" or bin sort. As the name implies, it is sorted by the value of each bit of the key value. The elements are allocated to some "buckets" to achieve the sorting effect

2. Cardinality sorting method is a stable sorting method, and the cardinal number sorting method is a stable sorting method with high efficiency.

3. Radix Sort (Radix Sort) is an extension of bucket sorting

4. Cardinal sorting was invented by Hermann Holleri in 1887. It is implemented like this: the integer is cut into different numbers according to the digits, and then compared according to each digit.

The basic idea of ​​radix sorting

Unify all the values ​​to be compared to the same digit length, and padded zeros in front of the numbers with shorter digits. Then, starting from the lowest bit, sort one time in sequence. After sorting from the lowest order to the highest order, the sequence becomes an ordered sequence.

This description is more difficult to understand. Let's look at a graphic explanation below to understand the steps of cardinal sorting

The initial state of the array arr = {53, 3, 542, 748, 14, 214}

Round 1:

(1) Take out the single digit of each element, and then see which bucket the number should be placed in (a one-dimensional array)

(2) According to the order of the bucket (the subscripts of the one-dimensional array are taken out one by one and put into the original array)

The first round of the array sorting arr = {542, 53, 3, 14, 214, 748}  

Round 2 sorting:

(1) Take out the tens digit of each element, and then see which bucket the number should be placed in (a one-dimensional array)

(2) According to the order of the bucket (the subscripts of the one-dimensional array are taken out one by one and put into the original array)

The second round of sorting of the array arr = {3, 14, 214, 542, 748, 53} 

Round 3 sorting:

(1) Take out the hundred digits of each element, and then see which bucket the number should be placed in (a one-dimensional array)

(2) According to the order of the bucket (the subscripts of the one-dimensional array are taken out one by one and put into the original array)

The third round of array sorting arr = {3, 14, 53, 214, 542, 748}

The above is the implementation process of radix sort

Code

Code description

Get the number of digits of the largest element of the array

Use two-dimensional array bucket[10][arr.length] to simulate bucket

Use bucketElementCounts[10] to simulate the pointer of each bucket

 public static void redixSort(int[]arr){
        //获取数组中最大元素的位数
        int max = arr[0];
        for (int i = 0; i < arr.length; i++) {
            if(max < arr[i])
                max = arr[i];
        }
        int maxLength = (max + "").length();
        //定义一个二维数组模拟桶
        int [][] bucket = new int[10][arr.length];
        //为了记录每个桶中的元素个数定义一个一维数组
        int [] bucketElementCounts = new int[10];
        for (int i = 0, n = 1; i < maxLength; i++,n *= 10) {
            //入桶
            for (int j = 0; j < arr.length; j++) {
                int digitOfElement = arr[j] / n %10;
                bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
                bucketElementCounts[digitOfElement]++;
            }
            int index = 0;
            //出桶
            for (int j = 0; j < bucketElementCounts.length; j++) {
                if(bucketElementCounts[j] != 0){
                    for (int k = 0; k < bucketElementCounts[j]; k++) {
                        arr[index++] = bucket[j][k];
                    }
                }
                //取出元素后,需要将bucketElementCount中的元素清零
                bucketElementCounts[j] = 0;
            }
            //System.out.println("第" + (i + 1) + "次排序后的数组" + Arrays.toString(arr));
        }
    }

Speed ​​test of sorting algorithm

Below I created a random array with a length of 80,000 for testing

Hardware: CPU8 generation i7

public static void main(String[] args) {
        System.out.println("测试排序算法的时间");
        int[] arr = new int[80000];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int)(Math.random() * 8000000);
        }
        Long startTime = System.currentTimeMillis();
        redixSort(arr);
        Long endTime = System.currentTimeMillis();
        System.out.println(endTime - startTime + "ms");
    }

Test separately

Bubble sort (after optimization)

After many tests, 80,000 data bubbling sorting takes about 10 seconds

Select sort

After many tests, 80,000 data selection and sorting time is approximately 1900ms-2200ms

Insertion sort

After many tests, 80,000 data insertion and sorting time is approximately 528ms-600ms

Hill sort

After many tests, 80,000 data Hill sorting time is approximately 17ms-22ms

Test 800,000 data

Test 8,000,000 data

Quick sort

After many tests, 80,000 pieces of data are quickly sorted. Approximate time is 15ms-22ms

Test 800,000 data

Test 8,000,000 data

Base sort

After many tests, 80,000 data bases are sorted. Approximate time is 18ms-33ms

Test 800,000 data

Test 8,000,000 data

analysis

 

Explanation of related terms:

Stable: if a is originally in front of b, and a=b, a is still in front of b after sorting;

Unstable: If a is originally in front of b, and a=b, a may appear behind b after sorting;

Inner sorting: all sorting operations are completed in memory;

Outer sorting: Because the data is too large, the data is placed on the disk, and the sorting can be performed only through the data transmission between the disk and the memory;

Time complexity: The time it takes for an algorithm to execute.

Space complexity: the amount of memory required to run a program.

n: data size

k: the number of "buckets"

In-place: Does not take up additional memory

Out-place: Take up extra memory

Guess you like

Origin blog.csdn.net/qq_45796208/article/details/110679337