Four common sorting methods (implemented in Java)

Insertion sort

Sorting principle:
1. Divide all elements into two groups , sorted and unsorted;
2. Find the first element in the unsorted group, and insert it into the sorted group;
3. Flashback traversal has been The sorted elements are compared with the elements to be inserted in turn, until an element is found to be less than or equal to the element to be inserted, then the element to be inserted is placed at this position, and the other elements are moved backward by one position;
The principle is as follows:
Insert picture description here
The first operation: The pointer points to the second element and compares it with the previous element.
If the conditions are met, exchange is performed, and the pointer is moved forward by one bit, and the above steps are repeated until the pointer reaches the head of the array,
otherwise it means there is already Sequence, exit the current loop;
second operation: the pointer points to the third element, compare it with the previous element...
Insert picture description here

/**
 * @author 悠一木碧
 * 插入排序类
 */
public class Insert {
    
    
    /**
     * 升序排序
     * @param a
     */
    public static void sort(Comparable[] a) {
    
    
        if (null == a) {
    
    
            throw new NullPointerException("空指针数组!");
        }
        int len = a.length;
//        1. 从第二个元素开始进行排序
//        2. 用temp记录当前索引位置, 索引必须 > 0(当索引为0的时候不需要再往前比较了)
//        3.如果满足条件, 则进行交换, 同时将索引前移一位----temp--        
        for (int i = 1; i < a.length; i++) {
    
    
            int temp = i;
            while (temp > 0 && bigger(a[temp - 1], a[temp])) {
    
    
                exchange(a, temp - 1, temp);
                temp--;
            }
        }
    }

    /**
     * 判断a 是否大于 b
     * @param a
     * @param b
     * @return
     */
    private static boolean bigger(Comparable a, Comparable b) {
    
    
        return a.compareTo(b) > 0;
    }

    /**
     * 交换索引index1, index2位置的元素
     * @param a
     * @param index1
     * @param index2
     */
    private static void exchange(Comparable[] a, int index1, int index2) {
    
    
        Comparable comparable = a[index1];
        a[index1] = a[index2];
        a[index2] = comparable;
    }
}

According to the Big O derivation rule, the time complexity of the final insertion sort is O(N^2) if the highest order term in the function is retained.

Hill sort

Hill sort is a kind of insertion sort, also known as " reduced incremental sort ", which is a more efficient and improved version of the insertion sort algorithm.
In the previous insertion sort, we compare again and again, and exchange elements again and again. For
example, to put 1 in the picture where 3 is located, we need to compare twice and swap twice.
Insert picture description here

The Hill sort is to use this to optimize, directly compare and exchange

Sorting principle:
1. Select an increment, and group the data according to the increment as the basis for data grouping;
2. Insert and sort each group of data in the group;
3. Reduce the increment to the smallest Reduce to 1, repeat the second step.
Regarding the determination of the increase amount:
we use

        int len = a.length;
        int increment = 1;
        while (increment < len / 2) {
    
    
            increment = increment * 2 + 1;
        }

Make sure that the increments are all odd numbers, and increment> len / 2, that is, the initial value of the increment is more than half of the array length

After determining the initial value of the increment, another thing that needs to be determined is the change mode of the increment. The
change trend of the increment: large----> small----------final increment = 1
The code can be written like this:

//      确保increment >= 1
        while (increment > 0) {
    
    
        	...
        	...
        	...
        	increment = increment / 2;
        }

Now for in-depth analysis of the similarities between Hill sorting and insertion sorting, and the different
Insert picture description here
Insert picture description here
code implementations:

/**
 * @author 悠一木碧
 * 希尔排序类
 */
public class Shell {
    
    
    /**
     * 对数组内元素进行排序(升序)
     * @param a
     */
    public static void sort(Comparable[] a) {
    
    
        if(null == a){
    
    
            throw new NullPointerException("空指针数组!");
        }
//        1.通过数组的长度确定增长量initialIncrement的初始值, 初始化值为1, 通过循环条件(<len / 2)进行确定
//        2.确定初始值后, 确定循环条件, 由于increment需要逐渐减小, 变换方法为increment /= 2
//        3.初始下标为0 + increment, 1+increment, 2+increment.....区间[increment, len-1]内
//        4.数与数之间的间隔为increment, 从当前的数开始, 与前一个数进行比较(假设前面的数成有序列)
//        5.如果不符合期待的大小关系, 则进行交换, 否则退出循环(说明已经成有序列了)
        int len = a.length;
        int increment = 1;
        while (increment < len / 2) {
    
    
            increment = increment * 2 + 1;
        }
        while (increment > 0) {
    
    
            for (int i = increment; i < len; i++) {
    
    
                int temp = i;
                while(temp >= increment && greater(a[temp - increment], a[temp])){
    
    
                    exchange(a, temp - increment, temp);
                    temp -= increment;
                }

            }
            increment /= 2;
        }
    }

    /**
     * 判断x是否大于y
     *
     * @param x
     * @param y
     * @return
     */
    private static boolean greater(Comparable x, Comparable y) {
    
    
        return x.compareTo(y) > 0;
    }

    /**
     * 交换a数组中, i,j索引处的值
     *
     * @param a
     * @param i
     * @param j
     */
    private static void exchange(Comparable[] a, int i, int j) {
    
    
        Comparable temp = a[i];
        a[i] = a[j];
        a[j] = temp;

    }


}

Note:
In Hill sorting, there is no fixed rule for the increase h. There are many papers that have studied various increasing sequences, but none of them can prove that a certain sequence is the best

Merge sort (like quick sort, apply the idea of ​​grouping and adopt a recursive strategy)

To be added:
Code implementation:

/**
 * @author 悠一木碧
 * 归并排序
 */
public class Merge {
    
    
//     辅助数组
    private static Comparable[] assitArray;
    /**
     * 对数组内的元素进行排序
     * @param array
     */
    public static void sort(Comparable[] array){
    
    
        if(null == array){
    
    
            throw new NullPointerException("空指针数组!");
        }
        int len = array.length;
        assitArray = new Comparable[len];
        sort(array, 0, len-1);
    }

    /**
     * 对区间[staIndex, endIndex]中的数组元素进行排序
     * 递归至 staIndex == endIndex停止
     * 在staIndex = endIndex - 1的时候开始调用merge进行归并
     * @param array
     * @param staIndex
     * @param endIndex
     */
    private static void sort(Comparable[] array, int staIndex, int endIndex){
    
    
        if(staIndex < endIndex){
    
    
            int mid = (staIndex + endIndex) / 2;
            sort(array, staIndex, mid);
            sort(array, mid + 1, endIndex);
            merge(array, staIndex, mid, endIndex);
        }
    }

    /**
     * [left, mid], [mid + 1, right]两个子组进行有序组合
     * 1. 定义辅助数组的初始指针, 定义原数组的两个区间的初始指针
     * 2. 依次移动两个区间的指针, 比较他们指向元素的大小, 按大小放入至辅助数组中
     * 3. 将排好序的辅助数组中的元素复制到原数组中
     * 两个区间的指针必定会有一个提前走完, 剩下没走完的指针, 将其剩余的元素放到辅助数组中即可
     * @param left
     * @param mid
     * @param right
     */
    private static void merge(Comparable[] array, int left, int mid, int right){
    
    
        int i = left;
        int index1 = left;
        int index2 = mid + 1;
        while(index1 <= mid && right >= index2){
    
    
            if(bigger(array[index1], array[index2])){
    
    
                assitArray[i++] = array[index2++];
            } else{
    
    
                assitArray[i++] = array[index1++];
            }
        }
        while(index1 <= mid){
    
    
            assitArray[i++] = array[index1++];
        }
        while(index2 <= right){
    
    
            assitArray[i++] = array[index2++];
        }
        if (right - left + 1 >= 0)
            System.arraycopy(assitArray, left, array, left, right + 1 - left);
    }

    /**
     * 判断a > b
     * @param a
     * @param b
     * @return
     */
    private static boolean bigger(Comparable a, Comparable b){
    
    
        return a.compareTo(b) > 0;
    }

    /**
     * 元素a[index1] 和 元素a[index2]进行交换
     * @param a
     * @param index1
     * @param index2
     */
    private static void exchange(Comparable[] a, int index1, int index2){
    
    
        Comparable comparable = a[index1];
        a[index1] = a[index2];
        a[index2] = comparable;
    }
}

Quick sort (recursive, double pointer)

To be added:
Code implementation:

/**
 * @author 悠一木碧
 * 快速排序
 */
public class Quick {
    
    
    public static void sort(Comparable[] a) {
    
    
        if(null == a){
    
    
            throw new NullPointerException("传入数组参数为空!");
        }
        int len = a.length;
        if(0 != len){
    
    
            sort(a, 0, len - 1);
        }
    }

    /**
     * 对区间[staIndex, endIndex]中的数组元素进行排序
     * 将其拆分为[lowerLimit, demarcationIndex-1], [demarcationIndex+1, upperLimit]两个区间排序
     * 递归至 staIndex == endIndex停止--------分成只有一个元素的时候停止
     * @param array
     * @param lowerLimit
     * @param upperLimit
     */
    private static void sort(Comparable[] array, int lowerLimit,  int upperLimit){
    
    
        if(lowerLimit >= upperLimit){
    
    
            return;
        }
        int demarcationIndex = grouping(array, lowerLimit, upperLimit);
        sort(array, lowerLimit, demarcationIndex - 1);
        sort(array, demarcationIndex + 1, upperLimit);
    }

    /**
     * 对索引在区间[lowerLimit, upperLimit]内的数组元素进行切分, 并返回切分后分界元素的索引
     * 这里是将左边第一个元素作为分界元素, 所以先让右边的指针先动
     * @param array
     * @param lowerLimit
     * @param upperLimit
     * @return 返回的是变换后的索引
     */
    private static int grouping(Comparable[] array, int lowerLimit, int upperLimit){
    
    
//      1. 定义两个指针, 分别指向待切区间的最小索引 和 最大索引的下一个位置
        int left = lowerLimit;
        int right = upperLimit + 1;
        while (true) {
    
    
//          2. 先移动右指针, 自右向左扫描, 直到找到比分界元素小的元素停止
//          3. 然后移动左指针, 自坐向右扫描, 直到找到比分界元素大的元素停止

            while(less(array[lowerLimit], array[--right])){
    
    
                if(left == right){
    
    
                    break;
                }
            }
//          5. 两个指针重合的时候, 交换分界元素和指针当前指向的元素并返回索引
            if(left == right){
    
    
                exchange(array, lowerLimit, right);
                return right;
            }
            while(less(array[++left], array[lowerLimit])){
    
    
                if(left == right){
    
    
                    break;
                }
            }
//          4. 交换左右指针指向的元素
            if(left == right){
    
    
                exchange(array, lowerLimit, right);
                return right;
            } else{
    
    
                exchange(array, left, right);
            }

        }
    }
    /**
     * 判断x是否小于y
     * @param x
     * @param y
     * @return
     */
    private static boolean less(Comparable x, Comparable y) {
    
    
        return x.compareTo(y) < 0;
    }

    /**
     * 交换a数组中, i,j索引处的值
     * @param a
     * @param i
     * @param j
     */
    private static void exchange(Comparable[] a, int i, int j) {
    
    
        Comparable temp = a[i];
        a[i] = a[j];
        a[j] = temp;

    }
}

Guess you like

Origin blog.csdn.net/Valishment/article/details/107749862