[data structure] analysis and implementation of ten sorting algorithms

Sorting algorithm

Sorting algorithms can be divided into internal sorting and external sorting. Internal sorting is completed in memory without additional space; It can also be divided into comparative sorting and non comparative sorting. The following figure shows the performance comparison of ten common sorting algorithms. Stability is based on whether the sorting changes the relative position of the original elements.

1. Bubble sorting

Bubble sorting uses pairwise comparison of adjacent elements. If the order is wrong, exchange their order. In this way, the largest or smallest elements will be exchanged to the top. Because the form is very similar to bubble after bubble, we call it bubble sorting. The following is a demonstration of sorting from small to large:

/**
     * Bubbling sort: Optimization: if no bubbling occurs in one sort, it indicates that the array has been ordered and can exit the loop
     * @param arr
     */
    public static int[] bubbleSort(int[] arr) {
        boolean flag = false;
        for (int i = 0; i < arr.length - 1; i++) {
            //Every time it bubbles, the biggest one will bubble to the top
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    flag = true;
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
           //Optimize code
            if (!flag) {
                break;
            } else {
                System.out.println("The first" + (i + 1) + "Secondary bubbling" + Arrays.toString(arr));
                flag = false;
            }
        }
        return arr;
    }

2. Select Sorting

That is, during each round of comparison, select the current element as the possible maximum value of the round. If the size is wrong, update and exchange the maximum value. In this way, the position of a number can be determined after each round.

/**
     * Select sort
     * @param arr
     * @return
     */
    public static int[] selectSort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            int min = arr[i]; //Select one as the minimum value
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[j] < min) {
                   arr[j] = arr[j] + arr[i];
                    arr[i] = arr[j] - arr[i];
                    arr[j] = arr[j] - arr[i];
                }
                min = arr[i];
            }
        }
        return arr;
    }

3. Insert sorting

Starting from the second element, compare with the first element one by one, and insert the element into the first position if appropriate; Find the appropriate elements in turn and insert them in the second and third positions..

Similar to the way of inserting playing cards: start from the second poker and compare it with the cards in the first position in proper order, that is, insert the elements in the first position and don't compare the elements, which is equivalent to moving back.

In the comparison process, the front elements begin to be orderly and the rear elements are disordered.

/**
     * Insert sort
     * @param arr
     * @return
     */
    public static int[] insertSort(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            //Current element to insert
            int current = arr[i];
            //The position to be inserted, that is, the previous position of the current number
            int preIndex = i - 1;
            while (preIndex >= 0 && current < arr[preIndex]) {
                //The element at the inserted position is moved back
                arr[preIndex +1] = arr[preIndex];
                //Move Index Forward
                preIndex--;
            }
            //Where the current value is inserted
            arr[preIndex + 1] = current;
        }
        return arr;
    }

4. Hill sort

Hill sort is an improvement on the original simple insertion sort, also known as reduced incremental sort. For example, for an already ordered sequence, it may move unnecessarily many times during insertion, affecting the efficiency.

Idea: divide the sequence into groups according to some incremental gap (generally length/2), and simply insert and sort each group of data; Then continue grouping according to gap/=2 and repeat the above method. Until gap=1, that is, when there is one group left, the effect of hill sorting has been achieved. At this time, most of the sequences have been ordered, and then simple sorting can be carried out.

The purpose of grouping is to make the group orderly and the whole as orderly as possible.

Thinking: why is grouping suitable for insertion sorting? You can see that the grouping here is not a simple dichotomy, but is divided according to the spacing. In the past, the exchange of two positions in insertion sorting will move the elements in the position spacing. Sorting according to the grouping only needs to move the spacing at one time.

  /**
     * Shell Sort 
     *
     * @param arr
     * @return
     */
    public static int[] shellSort(int[] arr) {
        //Controls the step size for each
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
            //Group by step
            for (int i = gap; i < arr.length; i++) {
                //Compare the elements of each group
                int preIndex = i - gap; //The position of the previous element within the group
                int current = arr[i];   //Current value
                //Compare all elements in the group and move the position
                while (preIndex >= 0 && arr[preIndex] > current) { 
                    arr[preIndex + gap] = arr[preIndex];
                    preIndex -= gap;
                }
                //After exiting the loop, the insertion position is found
                arr[preIndex + gap] = current;
            }
        }
        return arr;
    }

5. Quick sort

Fast sorting principle: find an element as the reference value (generally select the first element), put the smaller elements on the right and the larger elements on the left. Then perform this method recursively in the left and right sequences until there is one element left in each left and right sequence, and the whole sequence has been ordered.

Idea: Based on the benchmark value, the sequence is divided into two parts, left and right, which are relatively orderly, until each sequence is 1 long.

Practice: in each grouping, compare the reference value with the last element, from back to front, until you find an element smaller than the reference value and exchange positions; Then move from front to back until you find an element larger than the reference value and exchange positions. Until the relative position of the front and rear indexes changes, it indicates the end of the round. At this time, a reference value sequence can be determined. Then perform fast sorting in each left and right sequence.

 /**
     * Swap two elements in an array
     * @param a
     * @param n
     * @param m
     */
    private void swap(int[] arr, int a, int b) {
//        XOR exchange, there may be zero value when equal
        if(a==b){
            return;
        }else{
            arr[a] = arr[a] ^ arr[b];
            arr[b] = arr[a] ^ arr[b];
            arr[a] = arr[a] ^ arr[b];
        }
    }

    /**
     * Quick sort
     * @param arr
     * @param start Starting position
     * @param end End position
     * @return
     */
    public static void quickSort(int[] arr,int start,int end){
        //Mark the index and record the current position
        int low = start;
        int high = end;
        int key = arr[low]; //The reference value generally selects the first element of the sequence
        while(start<end){
            //Traverse back and forth until you find a smaller value
            while(start<end && arr[end]>=key){
                end--;
            }
            //If it is found during exit, the position is exchanged
            if(arr[end]<=key){
                swap(arr,start,end);
            }
            //Traverse from front to back until you find a larger value
            while(start<end && arr[start]<=key){
                start++;
            }
            if(arr[start]>=key){
                swap(arr,start,end);
            }
        }
        //After sorting, the benchmark position is determined, that is, the left is less than it and the right is greater than it
      
        //If the current starting position is greater than the mark, it indicates that there are still elements in the left sequence. The left sequence is recursively sorted
        if(start>low){
            quickSort(arr,low,start-1);
        }
        //If the current end position is less than the mark, it indicates that there are still elements in the right sequence. The right sequence is recursively sorted
        if(end<high){
            quickSort(arr,end+1,high);
        }
    }

6. Merge and sort

According to the idea of divide and conquer, divide the sequence into two sequences, merge and sort them respectively until the length of the subsequence is 1; Rule: merge each subsequence. Here, an additional sequence is added to store the merged results. Consolidation rules: compare from the starting position of the sequence, and fill the smaller ones into the result set; If a sequence is traversed, another sequence is directly filled into the result set.

/**
     * Merge and sort: divide and rule thought, divide and rule first
     * @param arr
     * @return
     */
    public static int[] mergeSort(int[] arr) {
        //Conditions for the end of "minute"
        if (arr.length < 2) {
            return arr;
        }
        int mid = arr.length / 2;
        //Are divided into two array sequences
        int[] left = Arrays.copyOfRange(arr, 0, mid);
        int[] right = Arrays.copyOfRange(arr, mid, arr.length);
        return merge(mergeSort(left), mergeSort(right));
    }

    /**
     * "Rule: combine the "divided" array sequences
     * @param left
     * @param right
     * @return
     */
    public static int[] merge(int[] left, int[] right) {
        //Returns the assembled result array
        int[] result = new int[left.length + right.length];
        //i. J is the index of the left and right sequences respectively, and index is the index of the result set
        for (int index = 0, i = 0, j = 0; index < result.length; index++) {
            if (i >= left.length) //When the index of the sequence exceeds its length, it indicates that the sequence has been arranged. Just add another sequence to the result set
                result[index] = right[j++];
            else if (j >= right.length)
                result[index] = left[i++];
            else if (left[i] > right[j]) //The data of the left and right sequences are compared in turn, and small ones are added to the result set
                result[index] = right[j++];
            else
                result[index] = left[i++];
        }
        return result;
    }

Summary:

seeing the name of a thing one thinks of its function:

Bubble sorting: Elements in adjacent positions are compared and exchanged, and the maximum value will be exchanged to the top shape, such as bubble;

Select Sorting: two rounds of for, select a target value in each round, compare and exchange;

Insertion sorting: select the appropriate element from the first position to insert and exchange, and the sequence is orderly;

Hill sort: the insertion sort of the group, and the insertion sort is performed in each sequence;

Merge sort: divide the sequence equally to make the sequence orderly; Then combine to make the sequence ordered as a whole.

Quick sort: Based on the benchmark value, the sequence is divided into two parts, left and right, which are relatively orderly, until each sequence is 1 long.

Tags: Algorithm data structure

Posted on Wed, 24 Nov 2021 07:57:35 -0500 by JSHINER