[Data Structure] Analysis and Implementation of Top Ten Sorting Algorithms

Sorting Algorithm

Sorting algorithms can be divided into internal sorting and external sorting. Internal sorting is done in memory and does not require additional space; it can also be divided into comparative sorting and non-comparative sorting. The following figure is a performance comparison of ten common sorting algorithms. Stability is based on whether the sorting changes the relative positions of the original elements.

1. Bubble sort

Bubble sort uses pairwise comparisons of adjacent elements, and if the order is wrong, swaps their order, so that in one round, the largest or smallest element will be swapped to the top. Since the form is very similar to bubbling again and again, we call it bubble sort. The following demonstrates the case of sorting from small to large:

/**
     * 冒泡排序:优化:如果一趟排序中没有发生冒泡,说明数组已经有序即可退出循环
     * @param arr
     */
    public static int[] bubbleSort(int[] arr) {
    
    
        boolean flag = false;
        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;
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
           //优化代码
            if (!flag) {
    
    
                break;
            } else {
    
    
                System.out.println("第" + (i + 1) + "次冒泡" + Arrays.toString(arr));
                flag = false;
            }
        }
        return arr;
    }

2, selection sort

That is, in each round of comparison, the current element is selected as the possible maximum value of the round, and if the size is wrong, the maximum value is updated and exchanged. In this way, the position of a number can be determined every round.

/**
     * 选择排序
     * @param arr
     * @return
     */
    public static int[] selectSort(int[] arr) {
    
    
        for (int i = 0; i < arr.length - 1; i++) {
    
    
            int min = arr[i]; //选择一个作为最小值
            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. Insertion sort

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

Similar to the way of inserting playing cards: starting from the second card, compare with the cards in the first position in turn, and the order is appropriate, that is, insert the element into the first position, and don't compare the element is equivalent to moving backward.

During the comparison, the front elements are ordered and the rear elements are unordered.

/**
     * 插入排序
     * @param arr
     * @return
     */
    public static int[] insertSort(int[] arr) {
    
    
        for (int i = 1; i < arr.length; i++) {
    
    
            //当前需要插入的元素
            int current = arr[i];
            //被插入的位置,即当前数的前一个
            int preIndex = i - 1;
            while (preIndex >= 0 && current < arr[preIndex]) {
    
    
                //被插入位置的元素后移
                arr[preIndex +1] = arr[preIndex];
                //索引向前移动
                preIndex--;
            }
            //当前值插入的位置
            arr[preIndex + 1] = current;
        }
        return arr;
    }

4, Hill sort

Hill sort is an improvement on the original simple insertion sort, also known as shrinking incremental sort. For example, for an already ordered sequence, when inserting, it may be unnecessary to perform multiple moves, which affects the efficiency.

Idea: Divide the sequence into groups according to a certain incremental gap (usually length/2), and perform a simple insertion sort on each group of data; then continue to group according to the gap/=2 method, and repeat the above method. Until gap=1, that is, when one group is left, the effect of Hill sorting has been achieved. At this time, the sequence is mostly ordered, and then a simple sorting can be performed.

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

Thinking: Why is the 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 previous insertion sorting, the two positions are exchanged, and the elements in the position spacing will be moved. Sorting according to the grouping, only one time Just move the distance.

  /**
     * 希尔排序
     *
     * @param arr
     * @return
     */
    public static int[] shellSort(int[] arr) {
    
    
        //控制每次的步长
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
    
    
            //按照步长分组
            for (int i = gap; i < arr.length; i++) {
    
    
                //对每次分组的元素进行比较
                int preIndex = i - gap; //组内的前一个元素位置
                int current = arr[i];   //当前值
                //比较组内的所以元素,并移动位置
                while (preIndex >= 0 && arr[preIndex] > current) {
    
     
                    arr[preIndex + gap] = arr[preIndex];
                    preIndex -= gap;
                }
                //退出循环后,位置找到插入
                arr[preIndex + gap] = current;
            }
        }
        return arr;
    }

5. Quick sort

The principle of quick sorting: find an element as the reference value (usually select the first element), put elements smaller than it on the right, and elements larger than it on the left . Then perform this recursively in the left and right sequences until there is one element left in each left and right sequence, at which point the entire sequence is in order.

Idea: Divide the sequence into left and right relatively ordered parts based on the reference value, until each sequence is 1 long.

Practice : In each grouping, compare the reference value with the last element, from back to front, until an element smaller than the reference value is found, and exchange positions; then from front to back, until a larger element than the reference value is found elements, swap positions. Until the relative positions of the front and rear indexes change, indicating that one round is over, a reference value sequence can be determined at this time. Then perform quicksort in each left and right sequence in turn.

 /**
     * 交换数组内的两个元素
     * @param a
     * @param n
     * @param m
     */
    private void swap(int[] arr, int a, int b) {
    
    
//        异或交换,可能存在相等时的零值情况
        if(a==b){
    
    
            return;
        }else{
    
    
            arr[a] = arr[a] ^ arr[b];
            arr[b] = arr[a] ^ arr[b];
            arr[a] = arr[a] ^ arr[b];
        }
    }

    /**
     * 快速排序
     * @param arr
     * @param start 起始位置
     * @param end 终点位置
     * @return
     */
    public static void quickSort(int[] arr,int start,int end){
    
    
        //标记索引,记录当前位置
        int low = start;
        int high = end;
        int key = arr[low]; //基准值一般选择序列第一个元素
        while(start<end){
    
    
            //从后往前遍历,直到找到较小值
            while(start<end && arr[end]>=key){
    
    
                end--;
            }
            //退出时如果找到,即交换位置
            if(arr[end]<=key){
    
    
                swap(arr,start,end);
            }
            //从前往后遍历,直到找到较大值
            while(start<end && arr[start]<=key){
    
    
                start++;
            }
            if(arr[start]>=key){
    
    
                swap(arr,start,end);
            }
        }
        //一遍排序结束,基准值位置就确定了,即左边均小于它,右边均大于它
      
        //如果当前起始位置大于标记,说明左边序列仍有元素,对左序列递归进行快速排序
        if(start>low){
    
    
            quickSort(arr,low,start-1);
        }
        //如果当前终点位置小于标记,说明右边序列仍有元素,对右序列递归进行快速排序
        if(end<high){
    
    
            quickSort(arr,end+1,high);
        }
    }

6. Merge sort

According to the idea of ​​divide and conquer, divide : divide the sequence into two sequences, and 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 result. Merging rule: compare from the starting position of the sequence, the smaller one is filled into the result set; if a sequence is traversed, another sequence is directly filled into the result set.

/**
     * 归并排序:分治思想,先分再治
     * @param arr
     * @return
     */
    public static int[] mergeSort(int[] arr) {
    
    
        //“分”结束的条件
        if (arr.length < 2) {
    
    
            return arr;
        }
        int mid = arr.length / 2;
        //均分成两个数组序列
        int[] left = Arrays.copyOfRange(arr, 0, mid);
        int[] right = Arrays.copyOfRange(arr, mid, arr.length);
        return merge(mergeSort(left), mergeSort(right));
    }

    /**
     * “治”:将"分"好的数组序列组合起来
     * @param left
     * @param right
     * @return
     */
    public static int[] merge(int[] left, int[] right) {
    
    
        //返回拼装好的结果数组
        int[] result = new int[left.length + right.length];
        //i,j,分别为左右序列的索引,index为结果集的索引
        for (int index = 0, i = 0, j = 0; index < result.length; index++) {
    
    
            if (i >= left.length) //当序列的索引超过其长度时说明序列已经排完,只需将另一序加入结果集中即可
                result[index] = right[j++];
            else if (j >= right.length)
                result[index] = left[i++];
            else if (left[i] > right[j]) //左右序列的数据依次进行比较,小的加入到结果集中
                result[index] = right[j++];
            else
                result[index] = left[i++];
        }
        return result;
    }

Summarize:

As the name suggests:

Bubble sort: The elements in adjacent positions are compared and exchanged, and the most value will be exchanged to the top to form a bubble;

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

Insertion sort: Select appropriate elements from the first position to insert and exchange, and the front of the sequence is ordered;

Hill sort: Insertion sort for grouping, insertion sort within each sequence;

Merge sort: Divide the sequence equally to make the sequence internally ordered; then combine to make the sequence overall ordered.

Quick Sort: Divide the sequence into two parts that are ordered relative to the left and right based on the reference value, until each sequence has a length of 1.

Guess you like

Origin blog.csdn.net/qq_40589204/article/details/121523972