排序算法总结

1.冒泡排序

冒泡排序是经典的入门算法,可以说每个人都会写它,但它也可以优化。在面试中让写冒泡排序,不要简单以为就是让你写两重循环,可能是在考察你对它的优化。

基础版本:

java 复制代码
 public  void sort(int[] arr){
    int len = arr.length;
    for(int i=len-1;i>0;i--)
        for(int j=0;j<i;j++){
            if(arr[j]>arr[j+1]){
                int tmp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = tmp;
            }
        }
  }

我们最常用的这种写法的时间复杂度始终为O(n^2),但其实可以利用数组中元素已有的顺序来优化该代码。

优化一:当算法执行过程中数组已经是有序数组了,这是就没有必要继续执行完n-1趟外循环,可以直接结束了。具体实现我们可以通过一个标志,来记录当前一趟外循环,在遍历过程中是否发生交换,如果没有交换说明,数组已经是有序数组,可以跳出循环了。

java 复制代码
public  void sort(int[] arr){
    int len = arr.length;
    boolean flag;
    for(int i=len-1;i>0;i--){
        flag = false;
        for(int j=0;j<i;j++){
            if(arr[j]>arr[j+1]){
                int tmp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = tmp;
                flag = true;
            }
        }
        if(!flag) break;
    
    }

优化二:在某种情况下,如果进行了若干次排序后,后面的若干个数已经是有序的,那么下一趟排序只需要比较前面无序的那部分即可。所以我们可以设置一个标志位记录每一趟排序中最后一次值交换的位置,下一趟排序只需比较到此位置即可。

java 复制代码
public static void sort(int[] arr){
    int len = arr.length;
    int i;
    int flag = len-1;
    while(flag>0){
        i = flag;
        for(int j=0;j<i;j++){
            if(arr[j]>arr[j+1]){
                int tmp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = tmp;
                flag = j;
            }
        }
    }
         
  }

经过优化后,冒泡排序平均时间复杂度为O ( n ^ 2 ) ,最好情况下O(n),最坏情况下O( n^2),是稳定的排序算法。

空间复杂度为O(1)

2.快速排序

快排对于已经有序的数组或者所有数据都相等的数组排序的时间复杂度是O(n^2),这种情况可以有多种方式优化。这种情况有多种方法优化,比如,可以尝试把数据分成3组,即大于枢值为一组,等于枢值为一组,小于枢值为一组,其原因很好理解,这里就不赘述了。也可以评估数据的个数,对于较少的数据,完全不需要使用快速排序,可以直接使用选择排序或者希尔排序。也可以通过随机获取枢值来解决。

快排的平均时间复杂度是O(nlogn),除了快速排序,堆排序和归并排序的时间复杂度也是O(nlogn),为什么一般都说快速排序是最快的排序算法呢?这是因为对于时间复杂度为O(nlogn)的算法,log的下标为常数c。快速排序之所以快,是因为它的常数c比较小,在具体应用中快排的表现也最好。

java 复制代码
public void quickSort(int[] nums,int low,int high){
        if(low<high){
             int pivotpos = partition(nums,low,high);
             quickSort(nums,low,pivotpos-1);
             quickSort(nums,pivotpos+1,high);

        }
       
    }
    public int partition(int[] nums,int low,int high){
        int pivot = nums[low];
        while(low<high){
            while(low<high&&nums[high]>=pivot) high--;
            nums[low] = nums[high];
            while(low<high && nums[low]<=pivot) low++;
            nums[high] = nums[low];
        }
        nums[low] = pivot;
        return low;
    }

稳定性:快排算法是一种不稳定的排序算法。比如在划分算法中,若右端有两个关键字相同,且均小于基准值的记录,则在交换到左端区间后,它们的相对位置会发生变化。

空间复杂度:最好情况O(log2n),最坏请开给你下O(n),平均情况下栈的深度为O(log2n)

时间复杂度:快速排序的运行时间与划分是否对称有关,最好是O(nlogn),平均也是O(nlogn),当数组基本有序后者基本逆序的情况下时间复杂度为O(n2);

为了解决在极端情况下时间复杂度为O(n2)的情况,可以在获取基准下标时使用随机数来获取,而不是默认区间的左侧下标。

java 复制代码
public void randomizedQuickSort(int[] nums,int low,int high){
        if(low<high){
             int pivotpos = randomizedPartition(nums,low,high);
             randomizedQuickSort(nums,low,pivotpos-1);
             randomizedQuickSort(nums,pivotpos+1,high);

        }
       
    }
    public int randomizedPartition(int[] nums,int low,int high){
        int i = new Random().nextInt(high - low +1)+low; //nextInt(x)会生成0-x的整数,不包含x
        swap(nums,low,i);
        return partition(nums,low,high);
    }
    public int partition(int[] nums,int low,int high){
        int pivot = nums[low];
        while(low<high){
            while(low<high&&nums[high]>=pivot) high--;
            nums[low] = nums[high];
            while(low<high && nums[low]<=pivot) low++;
            nums[high] = nums[low];
        }
        nums[low] = pivot;
        return low;
    }
    public void swap(int[] nums,int i ,int j){
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
相关推荐
我想吃余2 分钟前
【0基础学算法】前缀和刷题日志(三):连续数组、矩阵区域和
算法·矩阵·哈希算法
2501_9387739936 分钟前
文档搜索引擎搜索模块迭代:从基础检索到智能语义匹配升级
人工智能·算法·搜索引擎
CS创新实验室1 小时前
典型算法题解:长度最小的子数组
数据结构·c++·算法·考研408
我有一些感想……1 小时前
浅谈 BSGS(Baby-Step Giant-Step 大步小步)算法
c++·算法·数论·离散对数·bsgs
lkbhua莱克瓦241 小时前
Java基础——常用API2
java·笔记·github·学习方法
麦麦大数据1 小时前
F042 A星算法课程推荐(A*算法) | 课程知识图谱|课程推荐vue+flask+neo4j B/S架构前后端分离|课程知识图谱构造
vue.js·算法·知识图谱·neo4j·a星算法·路径推荐·课程推荐
摇滚侠1 小时前
Spring Boot3零基础教程,Lambda 表达式与函数式接口,笔记95
java·spring boot·笔记
好学且牛逼的马1 小时前
【JavaWeb|day19 Web后端进阶 SpringAOP、SpringBoot原理、自定义Starter、Maven高级】
java·spring boot·rpc
码界奇点1 小时前
Java 开发日记MySQL 与 Redis 双写一致性策略挑战与实战解析
java·redis·sql·mysql·java-ee
GHZero1 小时前
Java 之解读String源码(九)
java·开发语言