排序

什么是排序

  • 排序(sorting)的功能是将一个数据元素的任意序列,重新排列成一个按关键字有序的序列
  • 其确切定义为:
    假设有n个数据称元素序列{R1,R2,…,Rn},其相应关键字的序列是{K1,K2,…Kn},通过排序要求找出下表1,2,…,n的一种排列p1,p2,…,pn,使得相应关键字满足如下的非递减(或非递增)关系: Kp1 ≤ \leq Kp2 ≤ \leq ≤ \leq Kpn。这样,就得到一个按关键字有序的纪录序列:{Rp1,Rp2,…Rpn}

内部排序和外部排序

  • 一类是整个排序过程在内存储器中进行,称为内部排序
  • 另一类是由于待排序元素数量太大,以至于内存储器无法容纳全部数据,排序需要借助外部存储设备才能完成,这类排序称为外部排序。
  • 本章介绍的排序方法都属于内部排序

稳定排序和不稳定排序

  • 如果在待排序的序列中存在多个具有相同关键字的元素

  • 假设Ki=Kj (1 ≤ \leq i ≤ \leq n, 1 ≤ \leq j ≤ \leq n, i ≠ \neq =j),若在排序之前的序列中Ri在Rj之前

  • 经过排序后得到的序列中Ri仍在Rj之前,则称所用的排序方法是稳定的

  • 否则,当相同关键字元素的前后关系在排序中发生变化,则称所用的排序方法是不稳定的

  • 无论是稳定的还是不稳定的排序方法,均能玩车过排序的功能

  • 在某些场合可能对排序有稳定性的要求,此时就应当选择稳定的排序方法

  • 例如,假设一组学生纪录已经按照学号有序,现在需要根据学生的成绩排序,当分数相同时要求学号小的学生在前,显然此时对分数进行排序就必须选择稳定的排序方法
    在这里插入图片描述

比较排序和非比较排序
大部分排序都是需要通过比较首先来判断大小,作为排序的依据
但是也有例外的,比如计数排序、基数排序,不需要进行比较

  • 插入排序:将无序子序列中的一个或几个记录“插入”到有序序列中,从而增加记录的有序子序列的长度
  • 交换排序:通过“交换”无序序列中的纪录从而得到其中关键字最小或最大的记录,并将它加入到有序子序列中,以此方法增加记录的有序子序列的长度
  • 选择排序:从记录的无序子序列中“选择”关键字最小或最大的记录,并将它加入到有序子序列中,以此方法增加有序子序列的长度
  • 归并排序:通过“归并”两个或两个以上的记录有序子序列,逐步增加记录有序序列的长度

排序类型
在这里插入图片描述
一般说八大排序类型
另外还可以加上非比较的计数排序、选择排序中的属性选择排序、插入排序中的这般插入排序

排序效率
在这里插入图片描述
时间复杂度最高的就是三种基本排序:直接插入、简单选择、冒泡排序
建议优先掌握直接插入、简单选择、冒泡排序、快速排序

  1. 直接插入排序、简单选择排序、冒泡排序是最简单的三种排序算法,时间复杂度也最高O( n 2 n^2 n2),作为基础排序,面试中有被问到,三种都要掌握
  2. 三种简单排序算法虽然简单,但是效率低下;高级排序在简单排序的基础上优化,算法复杂,换取的是性能提高,同时可能需要更多的辅助空间
  3. 快速排序和归并排序都使用了分治和递归,所以面试时被问到的机会比较高,尤其是快速排序。
  4. 从时间性能上看,快速排序是所有排序算法中实际性能最好的,然而快速爬 u 需在最坏情况下(数据基本有序)的时间性能不如堆排序和归并排序,并且空间复杂度高,所以更适合数据不大的情况
  5. 堆排序在任何情况下,其时间复杂度为O(nlogn)。这相对于快速排序而言是堆排序的最大优点。堆排序在元素较少时由于消耗较多时间在初始建堆上,因此不值得提倡,然而当元素较多时还是很有效的排序算法
  6. 与快速排序和堆排序相比,归并排序的优点是它是一种稳定的排序方法,最坏情况下时间性能好
  7. 从方法稳定性上来看,大多数时间复杂度为O( n 2 n^2 n2)的排序均是稳定的排序方法,除简单选择排序外。而多数时间性能较好的排序,例如快速排序、堆排序、希尔排序都是不稳定的
  8. 基于比较的排序的时间复杂度的下限是Ω(nlogn),即这已经是最高的效率了
  9. 如果在面试中有面试官要求你写一个O(n)时间复杂度的排序算法,使用非比较的排序(计数排序、基数排序)可以达到线性时间O(n)复杂度的排序。只不过有前提条件,就是待排序的数要满足一定的范围的整数,而且可能需要较多辅助空间
  10. 需要结合具体的要求和场景来选择甚至组合使用,才能达到高效稳定的目的。没有最好的排序,只有最适合的排序

快速排序

  • 快速排序是冒泡排序的改进版,也是最好的一种内排序,还涉及到分治和递归,在很多面试题中都会出现,也是作为程序员必须掌握的一种排序方法
  • 冒泡排序记录的比较和交换是在相邻的单元中进行,每次交换只能上移或者下移一个单元,因而总的比较和移动次数较多。
  • 快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-Conquer Method)。该方法的基本思想是:
    (1)先从数列中取出一个数作为基准数(简单起见可以取第一个数)
    (2)分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边(分区)
    (3)再对左右区间重复第一步、第二步,直到各区间只有一个数(递归)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
快速排序=冒泡+分治+递归
快速排序的过程:东拆西补或西拆东补,一边拆一边补

public class TestQuickSort{
    public static void main(String[] args){
        //给出无序数组
        int arr[] = {72,6,57,88,60,42,83,73,48,85};
        //输出无序数组
        System.out.println(Arrays.toString(arr));
        //快速排序
        quickSort(arr);
        //输出有序数组
        System.out.println(Arrays.toString(arr));
    }
    
    private static int partition(int[] arr, int low, int high){
        //指定左指针i和右指针j
        int i=low;
        int j=high;
        //将第一个数作为基准值,挖坑
        int x=arr[low];
        //使用循环实现分区操作
        while(i<j){
            //从右向左移动j,找到第一个小于基准值的值arr[j]
            while(arr[j]>=x && i<j){
                j--;
            }
            
            //将右侧找到的小于基准数的值加入到左边的坑中,左指针i++,向中间移动一个位置
            if(i<j){
               arr[i] = arr[j];
               i++;
            }
            //从左向右移动i,找到第一个大于等于基准值的值arr[i]
            while(arr[i]<x && i<j){
                i++;
            }
            //将左侧找到的大于等于基准值的值加入到右边的坑中,右指针j--,向中间移动一个位置
            if(i<j){
                arr[i]=arr[j];
                j--;
            }
        }
        //使用基准值填坑,这就是基准值的最终位置
        arr[i] = x; //arr[j] = x;
        //返回基准值的位置索引
        return i; //return j;
    }
    
    private static void quickSort(int[] arr,int low, int high){
        //分区操作,将一个数组分成两个分区,返回分区界限的索引
        if(low<high){
            int index = partition(arr,low,high);
            //对左分区进行快排
            quickSort(arr,low,index-1);
            //对右分区进行快排
            quickSort(arr,index+1,high);
        }
    }
    
    
    
    public static void quickSort(int[] arr){
        int low = 0;
        int high = arr.length-1;
        quickSort(arr,low,high);
    }

}

快速排序算法的分析

  1. 当分区选取的基准元素为待排序元素中的最大或最小值时,为最坏情况,时间复杂度和直接插入排序的一样,移动次数达到最大值
    Cmax = 1 +2 +…+(n-1) = n*(n-1)/2 = O(n2),此时最好时间复杂度为O( n 2 n^2 n2)
  2. 当分区选取的基准元素为待排序元素中的“中值”,为最好的情况,时间复杂度为O( n l o g 2 n nlog_2n nlog2n)
  3. 快速排序的空间复杂度为O( l o g 2 n log_2n log2n)(用到了递归,当然占用空间多了)
  4. 当待排序元素类似[6,1,3,7,3]且基准元素为6时,经过分区,形成[1,3,3,6,7],两个3的相对位置发生了改变,所以快速排序是一种不稳定排序

快速排序算法的分析2

  • 时间效率:快速排序算法的运行时间依赖于划分是否平衡,即根据枢轴元素pivot将序列划分为两个子序列中的元素个数
  • 而划分是否平衡又依赖于所使用的枢轴元素
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值