其他排序算法(冒泡排序,希尔排序)

简介: 其他排序算法(冒泡排序,希尔排序)

冒泡排序


冒泡排序的基本思想


  • 一轮循环一定会将最大的元素排序到指定的位置


  • 每次都比较相邻元素。


网络异常,图片无法展示
|


网络异常,图片无法展示
|


算法实现


public class BubbleSort {
        public static <E extends Comparable<E>> void sort(E[] arr) {
            for(int i = 0; i < arr.length; i++) {
                for(int j = 0; j < arr.length - 1 - i; j++) {
                    if(arr[j].compareTo(arr[j + 1]) > 0) {
                        swap(arr, j, j + 1);
                    }
                }
            }
        }
        public static <E extends Comparable<E>> void swap(E[] arr, int l, int r) {
            E temp = arr[l];
            arr[l] = arr[r];
            arr[r] = temp;
        }
    }


算法优化


当对于有序数组时,我们可以提前终止比较


因为在比较第一个元素的时候,就已经可以确定该数组是有序的,所以就可以提前终止了。


  • 添加一个判断的变量。


public static <E extends Comparable<E>> void sort2(E[] arr) {
    for(int i = 0; i < arr.length; i++) {
        boolean isWrap = false;
        for(int j = 0; j < arr.length - 1 - i; j++) {
            if(arr[j].compareTo(arr[j + 1]) > 0) {
                swap(arr, j, j + 1);
                isWrap = true;
            }
        }
        if(!isWrap) {
            // 一轮循环后,没有元素交换位置,那么将说明该数组有序。
            break;
        }
    }
}


部分有序时,不需要比较后面的元素了。


网络异常,图片无法展示
|


我们知道外层循环变量是表示是指当前已经排序好的元素的个数。所以我们可以控制外层循环变量,来控制比较的位置。


public static <E extends Comparable<E>> void sort3(E[] arr) {
        for(int i = 0; i < arr.length;) {
            int lastIndex = 0;
            for(int j = 0; j < arr.length - 1 - i; j++) {
                if(arr[j].compareTo(arr[j + 1]) > 0) {
                    swap(arr, j, j + 1);
                    lastIndex = j + 1; // 这个表示排序好的位置
                }
            }
            i  = arr.length - lastIndex; // 决定下次比较的元素到达的位置
        }
    }


希尔排序


就是将数组分组,然后使用插入排序。


不断让数组元素有序。通过将元素设置成更小的元素,让其有序,最后当间距为1。


网络异常,图片无法展示
|


public class ShellSort {
        public static <E extends Comparable<E>> void sort(E[] arr) {
            int h = arr.length / 2; // 表示间隔多少的元素组成一个数组进行插入排序
            while (h >= 1) { // 表示直到间隔为1时,为最后一次数组的插入排序
                for(int start = 0; start < h; start++) { // 表示处理多少个子数组。 h即可表示拆分为多少个数组
                    // 进行插入排序, [start, start + h, start + 2h ... start + nh];
                    for(int i = start + h; i < arr.length; i += h) { // 注意这里开始的下标是子数组的第二个元素,因为第一个元素前面没有元素了
                        E cur = arr[i];
                        int j;
                        for(j = i; j - h >= 0; j -= h) {
                            if(cur.compareTo(arr[j - h]) < 0) { // 当前比较的值小于当前值将向右移一位
                                arr[j] = arr[j - h];
                            }
                        }
                        arr[j] = cur;
                    }
                }
                h /= 2;
            }
        }
    }


简化希尔排序的写法


上面我们可以看出,内层循环实现了三层for循环的嵌套,比较麻烦。因为他是每次只去比较每个子数组。


但是我们可以依次处理元素,只不过需要偏移h个元素查看交换条件而已。


public static <E extends Comparable<E>> void sort2(E[] arr) {
        int h = arr.length / 2; // 表示间隔多少的元素组成一个数组进行插入排序
        while (h >= 1) { // 表示直到间隔为1时,为最后一次数组的插入排序
            // 进行插入排序, [start, start + h, start + 2h ... start + nh];
            for(int i = h; i < arr.length; i += h) { // 注意这里开始的下标是子数组的第二个元素,因为第一个元素前面没有元素了
                E cur = arr[i];
                int j;
                for(j = i; j - h >= 0; j -= h) {
                    if(cur.compareTo(arr[j - h]) < 0) { // 当前比较的值小于当前值将向右移一位
                        arr[j] = arr[j - h];
                    }
                }
                arr[j] = cur;
            }
            h /= 2;
        }
    }


复杂度分析


网络异常,图片无法展示
|

网络异常,图片无法展示
|


通过步长序列,来优化希尔算法


// 步长序列
public static <E extends Comparable<E>> void sort3(E[] arr) {
    int h = 1;
    while(h < arr.length) { // 当不满足这个条件时,即为h的初始取值。
        h = h * 3 + 1; // [4, 13, 40, 121, ...]
    }
    while (h >= 1) { // 表示直到间隔为1时,为最后一次数组的插入排序
        // 进行插入排序, [start, start + h, start + 2h ... start + nh];
        for(int i = h; i < arr.length; i ++) { // 注意这里开始的下标是子数组的第二个元素,因为第一个元素前面没有元素了
            E cur = arr[i];
            int j;
            for(j = i; j - h >= 0; j -= h) {
                if(cur.compareTo(arr[j - h]) < 0) { // 当前比较的值小于当前值将向右移一位
                    arr[j] = arr[j - h];
                }
            }
            arr[j] = cur;
        }
        h /= 3;
    }
}


基于比较的选择排序算法总结


网络异常,图片无法展示
|


网络异常,图片无法展示
|


网络异常,图片无法展示
|


排序算法的稳定性


网络异常,图片无法展示
|


网络异常,图片无法展示
|


网络异常,图片无法展示
|


基本排序算法


  • 选择排序是不稳定的。


  • 插入排序是稳定的。每次都是比较相邻的元素,所以不会出现元素的跳跃。


  • 希尔排序是不稳定的。


  • 冒泡排序是稳定的。每次都是比较相邻的元素,所以不会出现元素的跳跃。高级排序算法


  • 堆排序不稳定。


  • 快速排序不稳定。


  • 归并排序稳定。


相关文章
|
26天前
|
搜索推荐 Python
利用Python内置函数实现的冒泡排序算法
在上述代码中,`bubble_sort` 函数接受一个列表 `arr` 作为输入。通过两层循环,外层循环控制排序的轮数,内层循环用于比较相邻的元素并进行交换。如果前一个元素大于后一个元素,就将它们交换位置。
126 67
|
2月前
|
搜索推荐
冒泡排序算法
【10月更文挑战第19天】冒泡排序是一种基础的排序算法,虽然在实际应用中可能不是最优的选择,但对于理解排序算法的基本原理和过程具有重要意义。
|
2月前
|
算法 搜索推荐 Shell
数据结构与算法学习十二:希尔排序、快速排序(递归、好理解)、归并排序(递归、难理解)
这篇文章介绍了希尔排序、快速排序和归并排序三种排序算法的基本概念、实现思路、代码实现及其测试结果。
37 1
|
2月前
|
算法 搜索推荐
数据结构与算法学习十一:冒泡排序、选择排序、插入排序
本文介绍了冒泡排序、选择排序和插入排序三种基础排序算法的原理、实现代码和测试结果。
25 0
数据结构与算法学习十一:冒泡排序、选择排序、插入排序
|
6月前
|
算法 搜索推荐
数据结构算法--6 希尔排序和计数排序
**希尔排序**是插入排序的改进版,通过分组插入来提高效率。它逐步减少元素间的间隔(增量序列),每次对每个间隔内的元素进行插入排序,最终增量为1时进行最后一次直接插入排序,实现整体接近有序到完全有序的过程。例如,对数组`5, 7, 4, 6, 3, 1, 2, 9, 8`,先以间隔`d=4`排序,然后`d=2`,最后`d=1`,完成排序。计数排序则适用于0到100的数值,通过统计每个数出现次数,创建对应计数数组,再根据计数重建有序数组,时间复杂度为`O(n)`。
|
2月前
|
搜索推荐 算法 数据可视化
深入解析冒泡排序算法
深入解析冒泡排序算法
50 4
|
2月前
|
搜索推荐 C语言
排序算法--冒泡排序
排序算法--冒泡排序
22 0
|
2月前
|
存储 搜索推荐 算法
【排序算法(二)】——冒泡排序、快速排序和归并排序—>深层解析
【排序算法(二)】——冒泡排序、快速排序和归并排序—>深层解析
|
2月前
|
算法 Python
Python算法编程:冒泡排序、选择排序、快速排序
Python算法编程:冒泡排序、选择排序、快速排序
35 0
|
4月前
|
搜索推荐 Java
经典排序算法---冒泡排序
这篇文章详细介绍了冒泡排序算法的基本思想、比较轮数和次数,并提供了Java语言实现冒泡排序的代码示例,展示了如何通过相邻元素的比较和交换来达到排序的目的。
经典排序算法---冒泡排序