常用的经典排序算法【Java实现】

一、排序算法比较

排序算法平均时间复杂度最坏时间复杂度空间复杂度稳定性
冒泡排序O(n²)O(n²)O(1)稳定
选择排序O(n²)O(n²)O(1)不稳定
插入排序O(n²)O(n²)O(1)稳定
希尔排序O(n㏒n)O(n㏒²n)O(1)不稳定
快速排序O(n㏒n)O(n²)O(㏒n)不稳定
归并排序O(n㏒n)O(n㏒n)O(n)稳定
基数排序O(n*k)O(n*k)O(n+k)稳定
堆排序O(n㏒n)O(n㏒n)O(1)不稳定

二、冒泡排序

1. 原理

数组相邻两个元素之间两两比较,如果前一个元素大于后一个元素,则两个元素交换位置,第一轮结束后,最大值会到达最大索引处,重复前面的步骤,即可得到一个排好序的数组。

2. 思路

每一次数组相邻元素之间两两比较,如果前一个元素大于后一个元素,则交换位置
每一轮比较完毕,下一轮就会减少一个元素的比较:
	第一轮比较,有 0 个元素不比较
	第二轮比较,有 1 个元素不比较(最大值已到达最大索引,不需比较)
	… … … … … … … … … … … … … 
一共需要比较数组长度减 1 轮

思路图示:

3. 代码实现

代码如下:

public class BubbleSort {
    public static void main(String[] args) {
        int[] arr = {9, 3, 45, -2, 7, -23};
        bubbleSort(arr);
    }

    /**
     * 冒泡排序
     *
     * @param arr 待排序的数组
     */
    public static void bubbleSort(int[] arr) {
        //一共比较 arr.length - 1 轮
        for (int i = 0; i < arr.length - 1; i++) {
            //标识某一轮比较是否发生交换
            boolean flag = false;
            //每轮比较 arr.length - i - 1 次
            for (int j = 0; j < arr.length - i - 1; j++) {
                //如果前一个元素大于后一个元素,则两个元素交换位置
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    flag = true;
                }
            }
            //打印每一轮排序后的结果
            System.out.println("第" + (i + 1) + "轮排序后:");
            System.out.println(Arrays.toString(arr));
            if (!flag) {
                break;
            }
        }
    }
}

测试结果:

第1轮排序后:
[-23, -2, 7, 3, 9, 45]
第2轮排序后:
[-23, -2, 3, 7, 9, 45]
第3轮排序后:
[-23, -2, 3, 7, 9, 45]

三、选择排序

1. 原理

每次从数组中找到第 n 小的元素与数组中第 n 个元素交换位置,最后一次交换完成后,即可得到一个排好序的数组。

2. 思路

每轮比较假定当前索引数为最小数,和后面的数进行比较:
	如果发现有比当前数更小的数,就重新确定最小数,并得到索引
	当遍历到数组的最后就得到本轮比较最小数的索引
	交换数据
一共需要比较数组长度减 1 轮

思路图示:

3. 代码实现

代码如下:

public class SelectSort {
    public static void main(String[] args) {
        int[] arr = {9, 3, 45, -2, 7, -23};
        selectSort(arr);
    }

    /**
     * 选择排序
     * @param arr 待排序的数组
     */
    public static void selectSort(int[] arr) {
        //一共交换 arr.length-1 轮
        for (int i = 0; i < arr.length - 1; i++) {
            //假设当前索引元素是最小值
            int index = i;
            //最小元素依次与数组中后续元素比较
            for (int j = i + 1; j < arr.length; j++) {
                //如果当前索引元素值比最小值小,则更新最小值索引
                if (arr[index] > arr[j]) {
                    index = j;
                }
            }

            //如果最小值索引不是最初索引才进行数据交换
            if (index != i) {
                //交换数据
                int temp = arr[i];
                arr[i] = arr[index];
                arr[index] = temp;
            }

            //打印每一轮交换后结果
            System.out.println("第" + (i + 1) + "轮交换后:");
            System.out.println(Arrays.toString(arr));
        }
    }
}

测试结果:

第1轮交换后:
[-23, 3, 45, -2, 7, 9]
第2轮交换后:
[-23, -2, 45, 3, 7, 9]
第3轮交换后:
[-23, -2, 3, 45, 7, 9]
第4轮交换后:
[-23, -2, 3, 7, 45, 9]
第5轮交换后:
[-23, -2, 3, 7, 9, 45]

四、插入排序

1. 原理

将 n 个待排序的元素看成一个有序表和一个无序表,开始时,有序表中只包含一个元素,无序表中包含 n-1 个元素,排序过程中每次从无序表中取出第一个元素,将其插入到有序表中适当的位置,使之成为新的有序表。

2. 思路

保证数组左侧有序
每次取出数组右侧第一个元素
将其依次与已经有序的左侧元素(从右往左)比较:
	如果到达数组最左侧或者当前元素大于或等于有序表中某一个元素,则将其插入
	否则将被比较的元素后移
从无序表第 2 个数据开始,一共插入数组长度 -1 轮

思路图示:

3. 代码实现

代码如下:

public class InsertSort {
    public static void main(String[] args) {
        int[] arr = {9, 3, 45, -2, 7, -23};
        insertSort(arr);
    }

    /**
     * 插入排序
     *
     * @param arr 待排序的数组
     */
    public static void insertSort(int[] arr) {
        //从无序表第 2 个数据开始,一共插入 arr.length-1 轮
        for (int i = 1; i < arr.length; i++) {
            //将当前要插入的数据取出
            int insertVal = arr[i];
            //从有序表最右侧元素开始遍历
            int insertIndex = i - 1;
            //当 insertIndex>=0 (还没到有序表最左侧元素)或者 即将插入数据小于有序表当前元素时
            while (insertIndex >= 0 && insertVal < arr[insertIndex]) {
                //将有序表当前元素后移
                arr[insertIndex + 1] = arr[insertIndex];
                //有序表元素索引减 1
                insertIndex--;
            }
            //循环结束,即找到元素插入位置
            // 循环中执行了 insertIndex--,所以此处 insertIndex 为插入位置的前一个索引
            //将元素插入有序表
            arr[insertIndex + 1] = insertVal;
            //打印每一轮插入后结果
            System.out.println("第" + i + "轮插入后:");
            System.out.println(Arrays.toString(arr));
        }
    }
}

测试结果:

第1轮插入后:
[3, 9, 45, -2, 7, -23]
第2轮插入后:
[3, 9, 45, -2, 7, -23]
第3轮插入后:
[-2, 3, 9, 45, 7, -23]
第4轮插入后:
[-2, 3, 7, 9, 45, -23]
第5轮插入后:
[-23, -2, 3, 7, 9, 45]

五、希尔排序

1. 插入排序存在的问题

在插入排序中,假定最小数据在数组最后,如:
	[-2, 3, 7, 9, 45, -23]
则当需要插入的数为 -23 时,其插入的过程为:
	[-2, 3, 7, 9, 45, 45],
	[-2, 3, 7, 9, 9, 45],
	[-2, 3, 7, 7, 9, 45],
	[-2, 3, 3, 7, 9, 45],
	[-2, -2, 3, 7, 9, 45],
	[-23, -2, 3, 7, 9, 45]
即当需要插入的数据是较小的数时,后移的次数会很多,对效率有影响

2. 原理

希尔排序是插入排序的优化版本:
将 n 个元素按一定增量分组,对每组使用插入排序,随着增量逐渐减小,每组包含的元素越来越多,当增量为 1 时,即可得到排好序的 n 个元素。

3. 思路

第一次增量取数组长度除以 2 
后续每次增量取上一次增量除以 2(一直取到增量为 1 )
每次取增量后,将对应的每组元素排好序
当增量为 1 时,为最后一轮排序

思路图示:

4. 代码实现

可以使用交换法(每次交换元素位置),也可以使用移位法(参考插入排序,交换法虽然利用了希尔排序的思想,但是效率较低,一般采用移位法。

代码1 如下(交换法):

public class ShellSort1 {
    public static void main(String[] args) {
        int[] arr = {9, 3, 45, -2, 7, -23};
        shellSort(arr);
    }

    /**
     * 希尔排序(交换法)
     * @param arr 待排序的数组
     */
    public static void shellSort(int[] arr) {
        //初始化计数器
        int count = 0;
        //每一轮的增量
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
            //遍历各组中的所有元素(共 gap 组),每组 arr.length/gap(向上取整)个元素
            for (int i = gap; i < arr.length; i++) {
                for (int j = i - gap; j >= 0; j -= gap) {
                    //如果当前元素大于加上增量后的那个元素,则交换两个元素位置
                    if (arr[j] > arr[j + gap]) {
                        int temp = arr[j];
                        arr[j] = arr[j + gap];
                        arr[j + gap] = temp;
                    }
                }
            }
            //打印每一轮排序后结果
            System.out.println("第" + (++count) + "轮排序后:");
            System.out.println(Arrays.toString(arr));
        }
    }
}

代码2 如下(移位法):

public class ShellSort2 {
    public static void main(String[] args) {
        int[] arr = {9, 3, 45, -2, 7, -23};
        shellSort(arr);
    }

    /**
     * 希尔排序(移位法)
     * @param arr 待排序的数组
     */
    public static void shellSort(int[] arr) {
        //初始化计数器
        int count = 0;
        //每一轮的增量
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
            //遍历各组中的所有元素(共 gap 组),每组 arr.length/gap(向上取整)个元素
            //按照插入排序的思想对每组进行排序
            for (int i = gap; i < arr.length; i++) {
                //保存当前插入元素
                int insertVal = arr[i];
                //初始化插入元素位置的索引
                int insertIndex = i;
                //如果当前元素比前一个元素小,才进入循环(需要往前插入)
                if (insertVal < arr[insertIndex - gap]) {
                    //执行插入排序的逻辑
                    while (insertIndex - gap >= 0 && insertVal < arr[insertIndex - gap]) {
                        arr[insertIndex] = arr[insertIndex - gap];
                        insertIndex -= gap;
                    }
                }
                arr[insertIndex] = insertVal;
            }
            //打印每一轮排序后结果
            System.out.println("第" + (++count) + "轮排序后:");
            System.out.println(Arrays.toString(arr));
        }
    }
}

测试结果:

第1轮插入后:
[-2, 3, -23, 9, 7, 45]
第2轮插入后:
[-23, -2, 3, 7, 9, 45]

六、快速排序

1. 原理

快速排序是冒泡排序的优化版本:
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据比另外一部分的所有数据都要小,然后继续按照此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,直到整个序列变成有序。

2. 思路

参考:b站快速排序算法讲解

假定每趟快速排序的基准元素为第一个元素:
在所有元素最左侧与最右侧分别定义一个索引
先从右侧扫描数组元素:
	如果扫描到一个小于基准元素的数据,则将其放到左侧索引的位置
	右侧索引停止扫描,左侧索引开始扫描
	如果扫描到一个大于基准元素的数据,则将其放到右侧索引的位置
	左侧索引停止扫描,右侧索引开始扫描
直到左侧索引等于右侧索引,则将基准元素放于该位置

思路图示:

3. 代码实现

代码如下:

public class QuickSort {
    public static void main(String[] args) {
        int[] arr = {9, 3, 45, -2, 7, -23};
        quickSort(arr);
        System.out.println(Arrays.toString(arr));
    }

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

    /**
     * 快速排序
     *
     * @param arr   待排序的数组
     * @param left  待排序数组最左侧索引
     * @param right 待排序数组最右侧索引
     */
    public static void quickSort(int[] arr, int left, int right) {
        //当左侧索引大于右侧索引时,结束递归
        if (left > right) {
            return;
        }
        //取出左右侧索引,是为了方便后续递归
        int l = left;
        int r = right;
        //取出基准元素(每次取第一个元素作为基准元素)
        int pivot = arr[left];
        //只要左侧索引小于右侧索引
        //两侧索引分别从两侧扫描数组(一侧扫描时,另一侧停止)
        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];
            }
        }
        //退出整个扫描循环时,l==r
        //此时将基准元素放入该位置
        //即可保证基准元素左侧全为小于它的数
        //基准元素右侧全为大于它的数
        arr[l] = pivot;
        //继续对基准元素左侧元素与基准元素右侧元素分别进行快速排序
        quickSort(arr, left, l - 1);
        quickSort(arr, l + 1, right);
    }
}

测试结果:

[-23, -2, 3, 7, 9, 45]

七、归并排序

1. 原理

归并排序是利用分治思想的一种排序方法:

将所有元素递归拆分至无法拆分的子序列

每轮将子序列组合并排序
最后一次组合即可得到排好序的序列

2. 思路

递归将数组拆分成无法拆分的子序列
在拆分完后开始合并,在合并的过程中:
	保证每一轮合并后的子序列为排好序的序列
在最后一轮合并后,即可得到排好序的数组

思路图示:
最后一轮合并过程图示:

3. 代码实现

代码如下:

public class MergeSort {
    public static void main(String[] args) {
        int[] arr = new int[]{9, 3, 45, -2, 7, -23};
        mergeSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    /**
     * 基数排序方法的重载,方便传参
     *
     * @param arr 待排序的数组
     */
    public static void mergeSort(int[] arr) {
        mergeSort(arr, 0, arr.length - 1);
    }

    /**
     * 归并排序
     *
     * @param arr   待排序的数组
     * @param left  待排序的序列左侧索引
     * @param right 待排序的序列右侧索引
     */
    public static void mergeSort(int[] arr, int left, int right) {
        //只要左侧索引小于右侧索引,就一直递归拆分数组
        if (left < right) {
            //数组中间位置索引
            int mid = (left + right) / 2;
            //递归拆分左右两侧元素,并合并
            mergeSort(arr, left, mid);
            mergeSort(arr, mid + 1, right);
            merge(arr, left, mid, right);
        }
    }

    /**
     * 合并拆分后的数组元素
     *
     * @param arr   待排序的数组
     * @param left  待排序的序列左侧索引
     * @param mid   数组中值索引
     * @param right 待排序的序列右侧索引
     */
    public static void merge(int[] arr, int left, int mid, int right) {
        //初始化数组 temp ,辅助数组
        //数组长度为每次需要合并的序列长度
        int[] temp = new int[right - left + 1];
        //初始化 i ,数组左侧有序序列初始索引
        int i = left;
        //初始化 j ,数组右侧有序序列初始索引
        int j = mid + 1;
        //初始化 k ,辅助数组初始索引
        int k = 0;
        //当 i>mid 或者 j>right 则退出循环
        //说明左侧或者右侧序列已经全部放进辅助数组中
        while (i <= mid && j <= right) {
            //如果左侧索引当前元素小于右侧索引当前元素
            if (arr[i] <= arr[j]) {
                //则将左侧索引当前元素放进辅助数组中
                //且 辅助数组索引 及 左侧索引 分别加 1
                temp[k++] = arr[i++];
            } else {
                //反之,则将右侧索引当前元素放进辅助数组中
                //且 辅助数组索引 及 右侧索引 分别加 1
                temp[k++] = arr[j++];
            }
        }
        //如果此时 i 仍然小于或者等于 mid
        //说明左侧序列还没有全部放入辅助数组(剩下的所有元素都比右侧序列所有元素大)
        //则将左侧序列剩余元素依次放入辅助数组
        while (i <= mid) {
            temp[k++] = arr[i++];
        }
        //如果此时 j 仍然小于或者等于 right
        //说明右侧序列还没有全部放入辅助数组(剩下的所有元素都比左侧序列所有元素大)
        //则将右侧序列剩余元素依次放入辅助数组
        while (j <= right) {
            temp[k++] = arr[j++];
        }
        //将辅助数组中的有序序列复制进初始数组中
        for (k = 0; k < temp.length; k++) {
            arr[k + left] = temp[k];
        }
    }
}

测试结果:

[-23, -2, 3, 7, 9, 45]

八、基数排序

1. 原理

基数排序是桶排序的扩展:
将所有待排序的数据统一为同样的数位长度,数位较短的数前面补 0 ,然后从最低位开始,依次进行一次排序。当从最低位排序到最高位排序完成以后,即可得到排好序的序列。

2. 思路

每一轮排序的过程:
先定义一个二维数组,作为桶,用来存放每次取出的数据:
	二维数组中的第几个一维数组表示桶的值为几
	将取出的数据放到对应的桶
再定义一个一维数组,用来存放每个桶中存放的数据个数
将桶中的数据依次取出,放回原数组
在数组中最大数据的位数轮过后,即可得到排好序的数组

思路图示:

3. 代码实现

代码如下:

public class RadixSort {
    public static void main(String[] args) {
        int[] arr = {9, 357, 45, 285, 787, 23, 429, 1436};
        radixSort(arr);
    }

    /**
     * 基数排序
     *
     * @param arr 待排序的数组
     */
    public static void radixSort(int[] arr) {
        //先假定数组中的最大值为第一个元素
        int max = arr[0];
        //遍历数组
        for (int value : arr) {
            //如果遍历当前元素大于最大值,则更新最大值
            if (value > max) {
                max = value;
            }
        }
        //获取数组中最大值的位数
        int maxLength = (max + "").length();
        //定义十个桶,用来存放对应的数据
        //为防止数据溢出,桶的大小为 arr.length
        //      可能数组中的元素在某一位上都是同一个数字
        int[][] bucket = new int[10][arr.length];
        //用来保存每个桶中数据个数的一维数组
        int[] bucketElementCount = new int[10];
        //一共要进行 maxLength 轮排序
        //每轮根据数组中数据某一位的值排序
        //      第一轮为个位,第二轮为十位,第三轮为百位……
        for (int i = 0, n = 1; i < maxLength; i++, n *= 10) {
            //将数组中的数据放到对应的桶中
            for (int value : arr) {
                //取出数组中对应位的值
                int digitOfElement = value / n % 10;
                //将数据放到对应的桶
                bucket[digitOfElement][bucketElementCount[digitOfElement]] = value;
                //将该桶的数据个数加 1
                bucketElementCount[digitOfElement]++;
            }
            //初始数组索引
            int index = 0;
            //将桶中的数据依次取出
            for (int k = 0; k < bucketElementCount.length; k++) {
                //如果桶中有数据
                if (bucketElementCount[k] != 0) {
                    //则依次取出桶中所有数据
                    for (int l = 0; l < bucketElementCount[k]; l++) {
                        //将取出的数据放回初始数组
                        arr[index++] = bucket[k][l];
                    }
                }
                //将桶中元素个数置零
                //后续每轮要重新放数据
                bucketElementCount[k] = 0;
            }
            //打印每一轮结果
            System.out.println("第" + (i + 1) + "轮排序的结果为:" + Arrays.toString(arr));
        }
    }
}

测试结果:

第1轮排序的结果为:[23, 45, 285, 1436, 357, 787, 9, 429]
第2轮排序的结果为:[9, 23, 429, 1436, 45, 357, 285, 787]
第3轮排序的结果为:[9, 23, 45, 285, 357, 429, 1436, 787]
第4轮排序的结果为:[9, 23, 45, 285, 357, 429, 787, 1436]

九、堆排序

1. 堆的概念

堆是具有以下性质的完全二叉树:每个节点的值都大于等于左右孩子的值(大根堆)或小于等于左右孩子的值(小根堆),对节点左孩子和右孩子值的大小关系没有要求。

概念图示:

2. 堆排序思路

1. 将待排序序列构成一个大根堆(升序用大根堆,降序用小根堆)
2. 此时,整个序列的最大值就是堆顶的根节点
3. 将其与末尾元素交换,此时末尾就是最大值
4. 然后将剩余 n-1 个元素重新构建成一个堆,这样就会得到 n 个元素的次小值
5. 反复执行,即可得到一个有序序列

3. 堆排序图解

参考:顺序存储二叉树的遍历【Java实现】

  1. 构造初始堆,将给定的无序序列构建成一个大根堆
    1. 初始数组:[ 9, 3, 45, -2, 7, -23 ],构建堆如下:
    2. 此时从最后一个非叶子节点开始(叶子节点不用调整,第一个非叶子节点索引 arr.length-1 / 2 - 1 = 6 / 2 - 1= 2,即元素为 45 的叶子节点 ),从左至右,从下至上调整
    3. 找到第二个非叶子节点 3,其孩子节点 7 > -3,且 3 < 7,所以将两个节点交换
    4. 继续找到下一个非叶子节点 9,其孩子节点 45 > 7,且 9 < 45,所以交换两个节点,交换过后就实现了将无序序列构建成大根堆
  2. 将堆顶元素与末尾元素交换,使末尾元素最大,然后将堆调整为大根堆,再将堆顶元素与末尾元素交换,得到第二大元素,反复交换、调整,得到有序序列
    1. 将堆顶元素 45 与 末尾元素 -23 交换,得到最大元素 45
    2. 重新调整为大根堆
    3. 再将堆顶元素 9 与 末尾元素 3 交换,得到第二大元素 9
    4. 一直重复上面的步骤,直到得到有序序列

4. 代码实现

代码如下:

public class HeapSort {
    public static void main(String[] args) {
        //初始化数组
        int[] arr = new int[]{9, 3, 45, -2, 7, -23};
        heapSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    /**
     * 堆排序
     *
     * @param arr 待排序的数组
     */
    public static void heapSort(int[] arr) {
        //将无序序列构建成大根堆
        //从最后一个非叶子节点开始依次往前调整
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            //调整节点位置
            adjustHeap(arr, i, arr.length);
        }
        //每次交换后,需要排序的元素减 1
        for (int i = arr.length - 1; i >= 0; i--) {
            //将堆顶元素与末尾元素交换
            int temp = arr[i];
            arr[i] = arr[0];
            arr[0] = temp;
            //重新调整为大根堆
            adjustHeap(arr, 0, i);
        }
    }

    /**
     * 将以 arr[index] 作为根节点的二叉树调整为大根堆
     * 如:
     * 初始数组:arr: [ 9, 3, 45, -2, 7, -23 ]
     * 第一次传入的 index = arr.length/2-1 = 6/2-1 = 2
     * 调整得到:arr: [ 9, 3, 45, -2, 7, -23 ]
     * 再次调整则传入 index = arr.length/2-2 = 6/2-2 = 1
     * 调整得到:arr: [ 9, 7, 45, -2, 3, -23 ]
     *
     * @param arr    待调整为大根堆的数组
     * @param index  非叶子节点在数组中的索引
     * @param length 对多少个元素进行调整
     *               开始排序后,每次交换,length - 1
     */
    public static void adjustHeap(int[] arr, int index, int length) {
        //保存当前索引元素
        int temp = arr[index];
        // index*2+1 为当前节点左子节点
        for (int i = index * 2 + 1; i < length; i = i * 2 + 1) {
            //如果右子节点存在
            //且左子节点值小于右子节点值
            if (i + 1 < length && arr[i] < arr[i + 1]) {
                //则将 i 指向右子节点
                i++;
            }
            //如果 i 指向的子节点值大于父节点的值
            if (arr[i] > temp) {
                //则将子节点的值赋给父节点
                arr[index] = arr[i];
                //将 index 指向被交换的元素位置
                //继续向下调整(可能上面节点调整后会打乱其子树)
                index = i;
            } else {
                //如果不需交换,则直接结束循环
                //说明该节点及其子树已经调整好了
                break;
            }
        }
        //再将 temp 的值放到调整后的位置
        arr[index] = temp;
    }
}

测试结果:

[-23, -2, 3, 7, 9, 45]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值