八大排序算法,一天一个

  因为还在学习的阶段,其实我对于八个排序算法中的堆排序和归并排序还是挺懵的…

1、冒泡排序

  冒泡排序是一个简单的排序算法,核心思想是两两比较,每次循环将最大(最小)的数移动到数组末端,然后进行第二次循环…直到数组有序。算法的时间复杂度为〇(n²),效率较低。
代码:

 public static void bubbleSort(int[] arr) {
        int n;
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[ j ] > arr[ j + 1 ]) {
                    n = arr[ j ];
                    arr[ j ] = arr[ j + 1 ];
                    arr[ j + 1 ] = n;
                }
            }
        }
    }

  冒泡排序的效率很低,所以我们对他进行改进,试想一下,如果一个数组是这样的 [1,0,2,3,4,5],(这个数组确实太极端了,但是我们只是想有一个可以对算法改进的例子而已)
对它进行排序,其实在第一次交换后就已经有序了,但还是需要循环n²次,所以我们对它改进:

public static void bubbleSort(int[] arr) {
        int n;
        boolean flag;
        for (int i = 0; i < arr.length - 1; i++) {
            flag = true;
            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[ j ] > arr[ j + 1 ]) {
                    n = arr[ j ];
                    arr[ j ] = arr[ j + 1 ];
                    arr[ j + 1 ] = n;
                    flag = false;
                }
            }
            if (flag) {
                break;
            }
        }
    }

  定义一个标志,如果需要交换就将标志赋值为false,每次外层循环开始时把标志置为true,内层循环遍历完数组后判断是否发生交换,若没有,falg的值应为true,说明数组已经有序,退出循环。

2、选择排序

  选择排序的宗旨是每次循环选择最大或最小的数,放在数组的第一位,然后进入下一次循环…直至数组有序,选择排序的每次排序仅仅只交换需要交换的数,而不是两两交换,时间复杂度为〇(n²)。
代码:

public static void selectSort(int[] arr) {
        int min;
        int index;
        for (int i = 0; i < arr.length - 1; i++) {
            index = i;
            min = arr[ i ];
            for (int j = i + 1; j < arr.length; j++) {
                if (min > arr[ j ]) {
                    min = arr[ j ];
                    index = j;
                }
            }
            arr[ index ] = arr[ i ];
            arr[ i ] = min;
        }
    }

还有个聊胜于无的优化,当需要交换的索引为自身的时候,不需要交换:

public static void selectSort(int[] arr) {
        int min;
        int index;
        for (int i = 0; i < arr.length - 1; i++) {
            index = i;
            min = arr[ i ];
            for (int j = i + 1; j < arr.length; j++) {
                if (min > arr[ j ]) {
                    min = arr[ j ];
                    index = j;
                }
            }
            if (index != i) {
                arr[ index ] = arr[ i ];
                arr[ i ] = min;
            }
        }
    }

3、插入排序

  插入排序的主要思想是把一个数组分为两个部分,前一个部分是有序的数组,后一个部分是无序的数组,每次把无序数组的第一个数插入到有序数组中,第一次数组第一个元素为一个有序的序列,时间复杂度为〇(n²)。
代码:

public static void insertionSort(int[] arr) {
        int indexVal;
        int index;
        for (int i = 1; i < arr.length; i++) {
            indexVal = arr[ i ];
            index = i;
            //在索引还能往前走的情况下,比较要插入有序序列的值 应该在哪个位置,
            // 每次循环前一个元素把当前元素覆盖,相当于把比目标元素小的元素后移,直到找到可以插入的位置 退出
            while (index - 1 >= 0 && indexVal < arr[ index - 1 ]) {
                arr[ index ] = arr[ index - 1 ];
                index--;
            }
            arr[ index ] = indexVal;
        }
    }

4、希尔排序

  希尔排序是选择排序的一个进阶版本,对选择排序进行了改进,使得效率更高,平均时间复杂度为〇(n ㏒n),最坏时间复杂度接近于〇(n²)。
  希尔排序又称为缩小增量排序,增量可以理解为把一个数组分为若干个小组,一般初始增量为数组长度的一半,然后每个小组进行选择排序,每次循环将增量折半,直到增量缩减为1,完成排序。其实比起增量我更喜欢叫步长,因为同一组元素的距离就是步长。

public static void shellSort(int[] arr) {
        int len = arr.length;
        int step = len;
        int index;
        int indexVal;
        while (step != 0) {
            step = step >> 1;
            //step指的是步长,即隔step个数为一组,step也指的是每次第一组的第二个数(因为第一个数默认有序)
            //例如:10/2=5,第一组第一个数是arr[0],第二个是arr[5]。。。5/2=2,第一组第一个数是arr[0],第二个数是arr[2]
            for (int i = step; i < len; i++) {
                index = i;
                indexVal = arr[ i ];
                if (arr[ i ] < arr[ i - step ]) {
                    while (index - step >= 0 && indexVal < arr[ index - step ]) {
                        arr[ index ] = arr[ index - step ];
                        index -= step;
                    }
                    arr[ index ] = indexVal;
                }
            }
        }
    }

5、快速排序

  快排利用递归,每次递归将数组(不是完整的数组,因为方法需要两个参数,一个左边界,一个右边界)看做两半,取中心轴,然后把数组中比中轴小的数放在数组的左边,大的放在数组的右边,最后把中轴插在中心,再次对中轴的左子数组和右子数组进行相同的操作,最后数组有序。
  我觉得快速排序要比归并排序更容易理解,而且jdk源码中Arrays工具类的sort方法使用的也是快速排序,平均时间复杂度为〇(n ㏒n),最坏时间复杂度为〇(n²)。

public static void quickSort(int[] arr, int left, int right) {
        if (left > right) {
            return;
        }
        int l = left;
        int r = right;
        //这个中轴取数组中的哪个数都是一样的,只是逻辑要修改一点
        int pivot = arr[ l ];
        while (l < r) {
            while (l < r && arr[ r ] >= pivot) {
                r--;
            }
            if (l < r) {
                arr[ l ] = arr[ r ];
            }
            while (l < r && arr[ l ] <= pivot) {
                l++;
            }
            if (l < r) {
                arr[ r ] = arr[ l ];
            }
            if (l >= r) {
                arr[ l ] = pivot;
            }
        }
        quickSort(arr, left, l - 1);
        quickSort(arr, l + 1, right);
    }

    /**
     * 重载方法
     * @param arr 要排序的数组
     */
    public static void quickSort(int[] arr) {
        quickSort(arr, 0, arr.length - 1);
    }

6、归并排序

7、桶排序

8、堆排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值