排序算法详解(全网最全)!

简介: 本文用于讲解排序算法

冒泡排序

冒泡排序思想就是犹如冒泡一样,一级一级向上进行比较  
1. 从开头开始相邻两个数比较,后一个比前一个小的话进行交换,直到结尾,此时结尾为最大值  
2. 第二轮也从开始进行,继续进行比较,到结尾-1处  
3. 直到剩下最后一个元素
4. 通过一个flag判断,当在某一轮中没有进行元素的交换,则此时循环退出
复制代码

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

public static <T extends Comparable> void bubblingSort(T[] arrays) {  
    boolean flag = false;  
    for (int i = 0; i < arrays.length - 1; i++) {  
        for (int j = 0; j < arrays.length - 1 - i; j++) {  
            if (arrays[j].compareTo(arrays[j + 1]) == 1) {  
                swap(arrays, j, j + 1);  
                flag = true;  
            }  
        }  
        if (!flag) {  
            break;  
        }  
    }  
}
复制代码

2、选择排序

1. 选择排序会先选择一个数作为最小值,然后根后面的数据进行比较,选取到最小值,然后和最初的基准值进行交换
2. 循环进行,每一轮选取该轮的i元素作为基准,及第1轮为第一个元素作为基准,第二轮第二个元素作为基准
3. 比较的时候,从基准元素的下一个元素开始比较
4. 进行循环时,每一轮都会找到最小值放在前面
复制代码

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

public static <T extends Comparable> void selectSort(T[] arrays) {  
    for (int i = 0; i < arrays.length - 1; i++) {  
        int minIndex = i;  
        for (int j = i + 1; j < arrays.length; j++) {  
            if (arrays[j].compareTo(arrays[minIndex]) == -1) {  
                minIndex = j;  
            }  
        }  
        if (minIndex != i) {  
            swap(arrays, i, minIndex);  
        }  
    }  
}
复制代码

3、插入排序

插入排序是先预设一个有序数列,然后把后一个元素向数列中进行插入,是其到达有序的效果
1. 预设第一个元素为有序数列
2. 定义一个变量记录每次要向有序数列中插入的元素,及循环的次数,从i=1开始,及第一次要插入的元素为坐标i的元素
3. 待插入的元素和前面元素比较,每比较依次,元素向后移动依次,直到遇到小于待插入元素或者标记变量小于1的时候
4. 将该标记坐标赋值为待插入的原素
5. 重复循环
复制代码

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

public static <T extends Comparable> void insertSort(T[] arrays) {  
    for (int i = 1; i < arrays.length; i++) {  
        int index = i;  
        T indexValue = arrays[i];  
        //从后向前  
        while (index > 0 && arrays[index].compareTo(arrays[index - 1]) == -1) {  
            swap(arrays, index, index - 1);  
            index--;  
        }  
        arrays[index] = indexValue;  
    }  
}
复制代码

4、希尔排序

希尔排序是对插入排序的改进,插入排序当最小值一直在最后的时候需要一直对数组进行移动赋值,它又被称为缩小增量排序,它把数组进行增量分组,对每一组进行插入排序,当增量为1时,算法终止。它的好处是每一次插入排序后,在进行下一次增量排序的时候,不用频繁移动元素
1. 设值增量,length/2,对元素数列进行分组
2. 每一个元素的步长为length/2,替换原先的插入排序的步长1
3. 对每组进行插入排序
4. 继续缩小增量,循环进行,直到增量为1
复制代码

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

public static <T extends Comparable> void shellSort(T[] arrays) {  
    int step = arrays.length / 2;  
    while (step > 0) {  
        for (int i = step; i < arrays.length; i++) {  
            int index = i;  
            T indexValue = arrays[index];  
            while (index > step - 1 && arrays[index].compareTo(arrays[index - step]) == -1) {  
                swap(arrays, index, index - step);  
                index -= step;  
            }  
            if (index != i) {  
                arrays[index] = indexValue;  
            }  
        }  
        step /= 2;  
    }  
}
复制代码

5、快速排序

快速排序是用双指针法进行
1. 先取一个标准,通常取第一个元素  
2. 设置两个头尾指针,分别移动并和标准元素进行比较,当头指针遇到比标准元素大的,尾指针遇到比标准元素小的进行交换。  
3. 当头尾指针相遇时,本次循环结束,并把标准元素和相遇点元素互换  
4. 继续选取标准元素,进行递归操作
复制代码

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

public static <T extends Comparable> void quickSort(T[] arrays,int begin,int end){  
    if(begin > end || begin < 0 || end >= arrays.length){  
        return;  
    }  
    T standard = arrays[begin];  
    int i = begin;  
    int j = end;  
    while (i != j){  
        while (arrays[j].compareTo(standard) != -1 && j > i) {  
            j--;  
        }  
        while (arrays[i].compareTo(standard) != 1  && j > i) {  
            i++;  
        }  
        if (j > i) {  
            swap(arrays,j,i);  
        }  
    }  
    arrays[begin] = arrays[i];  
    arrays[i] = standard;  
    quickSort(arrays,begin,i-1);  
    quickSort(arrays,i+1,end);  
}
复制代码

6、归并排序

归并排序主要算法思想就是分治算法:先把大的问题分成一个个小的问题,然后把小的问题的答案结合在一起,归并排序先把数组分成一个个的小单元,然后每个小单元进行结合,组成单元,然后各个单元在进行结合排序最终组合成一个。
1. 先进性分,递归进行
2. 治:当递归到最后一次的时候进行合并
3. 借助辅助数组,双指针进行比较,小的加入辅助数组,并移动指针。直到其中一个移动到mid元素,把剩余元素加入到辅助数组
4. 然后在进行数组拷贝,把辅助数组中的数据移动到原数组中相应的位置
5. 递归进行治操作,直到最后一次拷贝全部数组
复制代码

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

public static <T extends Comparable> void mergeSort(T[] arrays,int left,int right,T[] result){  
    if (left < right){  
        int mid = (right + left) / 2;  
        mergeSort(arrays,left,mid,result);  
        mergeSort(arrays,mid + 1,right,result);  
        //合并  
        int i = left;  
        int j = mid + 1;  
        int t = 0;  
        while (i <= mid && j <= right){  
            if (arrays[i].compareTo(arrays[j]) != 1) {  
                result[t++] = arrays[i++];  
            }else {  
                result[t++] = arrays[j++];  
            }  
        }  
        while (i <= mid){  
            result[t++] = arrays[i++];  
        }  
        while (j <= right){  
            result[t++] = arrays[j++];  
        }  
        t = 0;  
        int index = left;  
        while (index <= right) {  
            arrays[index++] = result[t++];  
        }  
    }  
}
复制代码

7、基数排序

基数排序是基于桶排序进行的,他是采用分配式排序,采用空间换时间的方式进行。让所有数值补充为同样的长度,数位较短的补充零。从最低位开始,依次进行一次排序,从最低位到最高位直到排序完成
1. 定一个长度为10的二维数组,在定义一个长度为10的一维数组,记录每个桶保存的长度
2. 对排序的数字进行获取个位的操作,并根据个位数字的大小分别放入二维数组中,及各位数字为1放入arr[1]的桶中,并把记录长度的值加1
3. 根据记录长度一维数组的值从桶中获取值,并赋值给原数组,继续进行循环操作,大于当前数组的最大值的大小
复制代码

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

public static void radixSort(int[] arrays){  
    int[][] bucket = new int[10][arrays.length];  
    int[] bucketMark = new int[10];  
    Integer max = arrays[0];  
    for (int i = 1; i < arrays.length; i++) {  
        if (arrays[i] > max){  
            max = arrays[i];  
        }  
    }  
    int maxLength = max.toString().length();  
    for (int i = 0, n = 1; i < maxLength; i++,n *= 10) {  
        for (int j = 0; j < arrays.length; j++) {  
            int index = arrays[j] / n % 10;  
            bucket[index][bucketMark[index]] = arrays[j];  
            bucketMark[index]++;  
        }  
        int index = 0;  
        for (int m = 0; m < bucketMark.length; m++) {  
            if (bucketMark[m] != 0) {  
                for (int k = 0; k < bucketMark[m]; k++) {  
                    arrays[index++] = bucket[m][k];  
                }  
                bucketMark[m] = 0;  
            }  
        }  
    }  
}
复制代码

总结

排序 时间复杂度 稳定性 优缺点
冒泡排序 O(n2) 稳定 冒泡排序当有序的时候,最优,不用进行全部遍历,每次进行一轮都会获取到最大
或者最小元素
选择排序 O(n2) 不稳定 选择排序是根据每次循环获取最小值最大值进行替换
插入排序 O(n2) 稳定 插入排序是想预设有序数列,根据后续数值想有序数列中进行插入
,缺点是当小的数值越靠后,进行移动赋值的数据越多
希尔排序 O(nlogn) 不稳定 对插入排序的改进,每进行一轮,数值的序列就无限接近于有序数列,到最后一轮移动的元素就越少
快速排序 O(nlogn) 不稳定 利用双指针法进行性移动交换,并进行递归
归并排序 O(nlogn) 稳定 分治算法
基数排序 O(n * k) 稳定 只能运用于数值的排序,而且负数小数的时候要进行特殊处理


相关文章
|
7月前
|
搜索推荐 算法 C语言
归并排序深度剖析
归并排序深度剖析
|
4月前
|
搜索推荐
九大排序算法时间复杂度、空间复杂度、稳定性
九大排序算法的时间复杂度、空间复杂度和稳定性,提供了对各种排序方法效率和特性的比较分析。
162 1
|
7月前
|
算法 搜索推荐
归并排序图文详解(一篇讲透归并排序)
归并排序图文详解(一篇讲透归并排序)
归并排序图文详解(一篇讲透归并排序)
|
7月前
|
算法 搜索推荐
【六大排序详解】中篇 :选择排序 与 堆排序
选择排序可以用扑克牌理解,眼睛看一遍所有牌,选择最小的放在最左边。然后略过刚才排完的那张,继续进行至扑克牌有序。这样一次一次的挑选,思路很顺畅。总结为: 每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。
53 6
|
7月前
|
算法
【六大排序详解】终篇 :冒泡排序 与 快速排序
冒泡排序如同泡泡上升一样,逐个逐个向上冒,一个接一个的冒上去。两两比较,较大者(较小者)向后挪动。全部遍历一遍即可完成排序
47 2
|
7月前
|
搜索推荐 测试技术
【六大排序详解】开篇 :插入排序 与 希尔排序
排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。 排序存在稳定性,稳定性是评估排序的重要标准。
48 1
|
7月前
|
搜索推荐 算法
【排序算法】一文教你从零学会希尔排序
【排序算法】一文教你从零学会希尔排序
|
7月前
|
搜索推荐 算法
【八大经典排序算法】选择排序
【八大经典排序算法】选择排序
27 0
|
7月前
|
搜索推荐 算法
【八大经典排序算法】堆排序
【八大经典排序算法】堆排序
32 0
|
7月前
|
搜索推荐 算法 索引
【八大经典排序算法】快速排序
【八大经典排序算法】快速排序
59 0