十大排序算法 (java实现)

2019-11-22  本文已影响0人  weihy

转自:https://zhuanlan.zhihu.com/p/80043870

1、冒泡排序(Bubble Sort)

冒泡排序:对每一对相邻的元素比较大小,若顺序错误则交换顺序(正确的顺序由排序方向决定,我们假定数组元素应该从小到大排序);这样从头到尾操作一遍,最大的元素将会在最后一个(操作的一组元素的最后一个);对前面未确认顺序的重复以上操作,直到没有元素可操作即排序完成。

1.1 算法描述:

(1)对一组元素,将相邻两个元素比较大小,如果顺序错误则交换顺序;
(2)对每一对相邻元素作同样的操作,从每一组开头一对到最后一对元素,这样每一组元素最后一个元素会是最大;
(3)循环n次(n为数组长度),每次选择前n - 1 - i个(i为第几次循环)元素重复(1)、(2)步骤;

1.2 代码实现:

    public static int[] bubbleSort(int[] arr){
        int len = arr.length;
        if (len == 0) return arr;
        for (int i = 0; i < len; i++){
            for (int j = 0; j < len - 1 - i; j++){
                if (arr[j+1] < arr[j]){
                    int temp = arr[j+1];
                    arr[j+1] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        return arr;
    }
2、选择排序(Selection Sort)

选择排序:是一种简单直接的排序算法,它的工作原理是:遍历未排序元素,将最小值(或者最大值)和遍历的第一个元素交换位置;然后继续在剩余未排序的元素中重复以上操作,直到将所有元素排序完成。

2.1 算法描述:
(1)初始状态:无序区为R[1..n],有序区为空;
(2)第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1..i-1]和R(i..n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和R[i+1..n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;
(3)n-1趟结束,数组有序化了。

2.2 代码实现:

    public static int[] selectorSort(int[] arr){
        int len = arr.length;
        if (len == 0) return arr;
        for (int i = 0; i < len-1; i++){
            int minIndex = i;
            //遍历出每趟的最小值
            for (int j = i+1; j < len; j++){
                if (arr[j] < arr[minIndex]){
                    minIndex = j;
                }
            }
            //把最小值与每趟第一个元素交换位置
            int temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
        return arr;
    }

3、插入排序(Insertion Sort)

插入排序:一种简单直观的排序算法。它的工作原理是:通过构建有序序列,依次取未排序序列元素,在有序序列后面从后往前扫描,找到相应位置插入,插入位置后面的元素需要依次外后移动,为新元素提供位置。

3.1 算法描述
(1)从第一个元素开始,可以认为是已经排好序了
(2)取出下一个新元素,依次从后往前扫描;
(3)如果扫描到的元素比新元素大,则将扫描到的元素依次往后移动一个位置;
(4)重复步骤(3)直到扫描到的元素小于等于新元素,则将新元素插入该位置之后;
(5)重复步骤(2)~(4),直到最后一个元素被插入正确的位置。

3.2 代码实现

    public static int[] insertionSort(int[] arr){
        int len = arr.length;
        if (len == 0) return arr;
        for (int i = 0;i < len -1; i++){
            int curr = arr[i+1];  //这是要插入的新元素
            int preIndex = i;
            //从后往前扫描有序序列,如果新元素小于等于扫描到的元素,则将被扫描的元素依次后移一个位置,注意不要下标不要越界
            while (preIndex >= 0 && arr[preIndex] > curr){
                arr[preIndex+1] = arr[preIndex];
                preIndex--;
            }
            //上面的while循环跳出则表示当前preIndex的元素比新元素小或者已经越界,应该把新元素插入preIndex+1位置
            arr[preIndex+1] = curr;
        }
        return arr;
    }
4、希尔排序(Shell Sort)

希尔排序:是插入排序的改良版本,又叫缩小增量排序。希尔排序是把记录按下表的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

4.1 算法描述:
在此我们选择增量为gap = length / 2,继续缩小增量gap = gap / 2直到 gap == 1,我们用一个序列来表示这些增量{len/2, (len/2)/2, ....,1} 这种增量序列的选择和证明是一种数学难题,在此选择的增量是比较常见的,也是希尔建议的称之为希尔增量。

先将整个待排序的序列分割为若干个子序列分别进行插入排序,具体如下
(1)选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
(2)按增量序列个数k,对序列进行k 趟排序;
(3)每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

4.2 代码实现:

    public static int[] shellSort(int[] arr){
        int len = arr.length;
        if (len == 0) return arr;
        int gap = len / 2;  //增量初始值
        while (gap > 0){
            for (int i = gap; i < len; i++){
                //对每个分组进行插入排序
                int curr = arr[i];
                int preIndex = i - gap;
                while (preIndex >= 0 && arr[preIndex] > curr){
                    arr[preIndex + gap] = arr[preIndex];
                    preIndex -= gap;
                }
                arr[preIndex + gap] = curr;
            }
            gap = gap / 2;  //缩小增量,重新分组进行插入排序
        }
        //gap==1时,将所有序列分为一组进行插入排序
        return arr;
    }
5、归并排序(Merge Sort)

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。归并排序是一种稳定的排序方法。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

5.1 算法描述:
(1)把长度为n的输入序列分成两个长度为n/2的子序列;
(2)对这两个子序列分别采用归并排序;
(3)将两个排序好的子序列合并成一个最终的排序序列。

5.2 代码实现:

    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));
    }

    /**
     * 将两个有序序列 组合成一个新的有序序列
     */
    private static int[] merge(int[] left, int[] right){
        int[] result = new int[left.length + right.length];
        for (int index = 0, i = 0, j = 0; index < result.length; index++){

            if (i < left.length && j < right.length){
                if (left[i] <= right[j]) {
                    result[index] = left[i++];
                } else if (left[i] > right[j]) {
                    result[index] = right[j++];
                }
            } else {
                if (i >= left.length) result[index] = right[j++];
                else if (j >= right.length) result[index] = left[i++];
            }

        }
        return result;
    }

未完待续。。。

上一篇下一篇

猜你喜欢

热点阅读