常见排序算法总结

6 篇文章 0 订阅
本文详细介绍了三种经典排序算法:冒泡排序、快速排序和桶排序。冒泡排序时间复杂度为O(n^2),适合小规模数据;快速排序平均时间复杂度为O(nlogn),但不稳定性可能影响特定场景应用;桶排序在均匀分布时可达线性时间复杂度O(n),但在数据分布不均时性能会下降。理解这些排序算法的时间和空间复杂度,有助于选择适合特定需求的排序方法。
摘要由CSDN通过智能技术生成
排序分类

根据时间复杂度的不同,常见的排序算法可以分为三大类:

  1. 时间复杂度为O(n^2)的算法
    冒泡排序、选择排序、插入排序、希尔排序等。
  2. 时间复杂读为O(nlogn)的算法
    快速排序、归并排序、堆排序等。
  3. 时间复杂度为O(n)的排序算法
    计数排序、桶排序、基数排序等。

以下将挑选三种较为经典的算法进行介绍。

冒泡排序

冒泡排序是一种基础的交换排序,是稳定排序类型。

package main.java;

import java.util.Arrays;

public class Sort {
    public static void sort(int arrry[]) {
        //记录最后一次交换的位置
        int lastExchangeIndex = 0;
        //无序数组的边界,每次比较只需要比较到这里为止
        int sortBorder = arrry.length - 1;
        for (int i = 0; i < arrry.length - 1; i++) {
            //有序标记,每一轮的初始值都是True
            boolean isSorted = true;
            for (int j = 0; j < arrry.length - i - 1; j++) {
                int tep = 0;
                if (arrry[j] > arrry[j + 1]) {
                    tep = arrry[j];
                    arrry[j] = arrry[j + 1];
                    arrry[j + 1] = tep;
                    //因为有元素进行交换,所以不是有序的,标记为false
                    isSorted = false;
                    //跟新为最后一次交换元素的位置
                    lastExchangeIndex = j;
                }
            }
            sortBorder = lastExchangeIndex;
            if (isSorted) {
                break;
            }
        }
    }

    public static void main(String[] args) {
        int[] array = new int[]{5, 8, 6, 3, 2, 14, 1};
        sort(array);
        System.out.println(Arrays.toString(array));
    }
}
快速排序

快速排序在每一轮挑选一个基准元素,并让其它比它大的元素移动到数列一边,比它小的元素移动到数列的另一边,从而把数列拆解成两个部分。快速排序是不稳定的排序类型。

package main.java;

import java.util.Arrays;

public class QuickSort {
    public static void quickSort(int[] array, int startIndex, int endIndex){
        //递归结束条件,startIndex大于或等于endIndex时
        if (startIndex>=endIndex){
            return;
        }
        //等到基准元素位置
        int pivotIndex = partition(array, startIndex, endIndex);
        //根据基准元素,分成两部分进行递归排序
        quickSort(array, startIndex, pivotIndex-1);
        quickSort(array, pivotIndex+1, endIndex);
    }

    /**
     * 分治 单边循环法
     */
    private  static int partition(int[] array, int startIndex, int endIndex){
        // 取第一个位置(也可以随机位置的元素)做基准元素
        int pivot = array[startIndex];
        int mark = startIndex;
        
        for(int i=startIndex+1;i<=endIndex; i++){
            if(array[i]<pivot){
                mark++;
                int p = array[mark];
                array[mark]=array[i];
                array[i]=p;
            }
        }
        
        array[startIndex] = array[mark];
        array[mark] = pivot;
        return mark;
    }

    public static void main(String[] args) {
        int[] array = new int[]{1,3,8,7,9,6,14};
        quickSort(array, 0, array.length-1);
        System.out.println(Arrays.toString(array));
    }
}
桶排序

桶排序是基于计数排序衍生出来的排序,借助桶来解决计数排序只能对整数进行排序的问题,是可以达到线性时间复杂度的稳定排序类型。

package main.java;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;

public class BucketSort {
    public static double[] bucketSort(double[] array) {
        //1.得到数列的最大值和最小值,并求出差值d
        double max = array[0];
        double min = array[0];
        for (int i = 0; i < array.length; i++) {
            if (array[i] > max) {
                max = array[i];
            }
            if (array[i] < min) {
                min = array[i];
            }
        }
        double d = max - min;
        //2.初始化桶
        int bucketNum = array.length;
        ArrayList<LinkedList<Double>> bucketList = new ArrayList<LinkedList<Double>>(bucketNum);
        for (int i = 0; i < bucketNum; i++) {
            bucketList.add(new LinkedList<Double>());
        }
        //3.遍历原始数组,将每个元素放入桶中
        for (int i = 0; i < array.length; i++) {
            int num = (int) ((array[i] - min) * (bucketNum - 1) / d);
            bucketList.get(num).add(array[i]);
        }
        //4.对每个桶内部进行排序
        for (int i = 0; i < bucketList.size(); i++) {
            //JDK底层采用归并排序
            Collections.sort(bucketList.get(i));
        }
        //5.输出全部元素
        double[] sortedArray = new double[array.length];
        int index = 0;
        for (LinkedList<Double> list : bucketList) {
            for (double element : list) {
                sortedArray[index] = element;
                index++;
            }
        }
        return sortedArray;
    }

    public static void main(String[] args) {
        double[] array = new double[]{1.1, 5.5, 6.6, 7.6, 3.4, 9.9, 2.1, 14.4, 12.1};
        double[] sortedArray = bucketSort(array);
        System.out.println(Arrays.toString(sortedArray));
    }
}
总结

通过对比这几种排序算法:

  1. 冒泡排序的平均时间复杂度为O(n^2),空间复杂度为O(1),稳定排序;
  2. 快速排序的平均时间复杂度为O(nlogn),空间复杂度O(logn),不稳定排序;
  3. 桶排序的平均时间复杂度为O(n),空间复杂度O(n),稳定排序;

通过对比这几类排序算法即可发现,桶排序的时间复杂度是最优的。但即使是桶排序的性能也并非稳定,如果元素分布极其不均衡,在极端情况下,第一个桶中一个元素,最后一个桶中1各元素,时间复杂度将退化为O(nlogn)。

由此可见,没有绝对好的算法,也没有绝对不好的算法,只不过是通过时间换空间或者空间换时间罢了,关键要看具体的使用场景。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值