数据结构和算法学习第六节 排序算法 一 基本概念

算法的时间复杂度

概述

    排序算法:是将一组数据,按照指定的顺序进行排列的过程。
    排序的分类:
    1、内部排序:将需要处理的所有数据加载到内存储存器中排序
    2、外部排序:数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。
    常见的排序算法分类如下所示,外部排序先略过。

排序
内部排序
外部排序
插入排序
选择排序
交换排序
归并排序
基数排序 桶排序的扩展
直接插入排序
希尔排序
简单选择排序
堆排序
冒泡排序
快速排序

算法的时间复杂度

    衡量一个程序(算法)执行时间的两种方法
    1、事后统计法
    这种方法可行,但是有两个问题,1)如果想要对设计的算法进行运行性能评测,需要实际运行程序。2) 运算的所得的时间的统计量依赖于计算机的硬件、软件等环境因素,这种方式需要在同等条件、同等状态下运行,才能比较算法的速度。
    2、事前估算法:通过分析某个算法的时间复杂度来判断哪个算法更好。
    时间频度
    一个算法花费的时间与算法中语句的执行次数成正比,哪个算法语句执行次数越多,它消耗时间越多。一个算法中的语句执行次数称为语句频度或者时间频度,记为T(n)。
    时间频度简要说明

    @Test
    // 计算 1 + 2 + 3 …… + 99 + 100
    public void method1() {
        // 使用for循环
        // 时间复杂度 T(n) = n + 1
        // n + 1 的原因是最后一次还需要进行判断
        for (int i = 1; i <= end; i++) {
            total += i;
        }
        System.out.println(total);
    }

    @Test
    // 计算 1 + 2 + 3 …… + 99 + 100
    public void method2() {
        // 直接计算 时间复杂度 T(n) = 1
        total = (end + 1) * end / 2;
        System.out.println(total);
    }

    算法的时间复杂度可以忽略常数项。
    2n+5 随着n逐渐增加,执行曲线无限接近
    3n+10 随着n逐渐增加,执行曲线无限接近
在这里插入图片描述
    同理:可以忽略低次项 、忽略系数。比如 T(n) = 2n2 与 T(n) = 2n2 +3n,可以忽略低次项。比如 T(n) = 3n2 与 T(n) = 2n2 当n越来越大,系数也可以忽略。
    时间复杂度简要说明
    1、一般情况下,算法中的基本操作语句的重复执行次数是问题规模n的某个函数,使用T(n)表示。若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于0的常数,则称f(n)是T(n)的同数量级函数,记作T(n)= O(f(n)) ,称O(f(n))为算法的渐进时间复杂度,简称时间复杂度。
    2、T(n)不同,但是时间复杂度可能相同,比如 T(n) = n2+7n+6与T(n) = 2n2+3n+1,他们的T(n)不同,但是时间复杂度相同,都是O(n2)
    3、计算时间复杂的方法
        3.1、使用常数1代替运行时间中的所有加法常数。
        3.2、修改后得到运行次数函数中,只保留最高阶项。
        3.3、去除高阶项的系数。
    常见的时间复杂度
    1、常数阶O(1)
    2、对数阶O( log ⁡ 2 n \log_2 n log2n)
    3、线性阶O(n)
    4、常数对数阶O(n log ⁡ 2 n \log_2 n log2n)
    5、平方阶O(n2)
    6、立方阶O(n3)
    7、k次方阶O(nk)
    8、指数阶O(2n)
    常见的算法时间复杂度,由小到大依次为:O(1) < O( log ⁡ 2 n \log_2 n log2n) < O(n) < O(n log ⁡ 2 n \log_2 n log2n) < O(n2) < O(n3) < O(nk) < O(2n),随着问题规模n的不断增大,上述时间复杂度不断增大,算法的执行效率越低,应该尽可能避免使用指数阶的算法。简要示意图如下:
在这里插入图片描述
    常见的时间复杂度举例说明:
    常数阶O(1)

// 常数阶 无论代码执行了多少行,只要没有循环等复杂结构,那么这个代码的时间复杂度都是O(1)
    public void m1() {
        // 这段代码在执行的事后,它的消耗并不随着某个变量的增长而增长,那么无论这类代码有多长
        //  都可以用O(1)来表示它的时间复杂度
        int i = 1;
        int j = 2;
        ++i;
        j++;
        int m = i + j;
        System.out.println(m);
    }

    2、对数阶O( log ⁡ 2 n \log_2 n log2n)

	// 对数阶说明
    public void m2(int n) {
        int i = 1;
        while (i < n) {
            // 每次都将 i * 2 ,i 与 n 的距离越来越小
            i = i * 2;
        }
    }

    对数阶简要说明:
    在while循环中,每次都将i乘以2,i的值与n越来越接近。假设循环k次,i就大于n了,此时这个循环就退出了,也就是说2k >= n,那么 k = log ⁡ 2 n \log_2 n log2n,当循环 log ⁡ 2 n \log_2 n log2n次以后,代码就结束向下执行。所以这段代码的时间复杂度为O( log ⁡ 2 n \log_2 n log2n)。假设,代码修改为i = i * 3;此时的时间复杂度为O( log ⁡ 3 n \log_3 n log3n)。
    如果 N = ax (a > 0,a ≠ \neq = 1),即a的x次方等于N(a > 0,a ≠ \neq = 1),那么数x就是以a为底N的对数,记作 x = log ⁡ a N \log_a N logaN,a是对数的底数,N是真数,x是“以a为底N的对数”。
    线性阶

// 线性阶说明
    public void m3(int n) {
        // 这段代码for循环会执行n遍,它消耗的时间随着n的变化而变化,
        // 这种类型的代码的时间复杂度,是O(n)
        for (int i = 0; i < n; i++) {
            //do something
        }
    }

    线性对数阶

    // 线性对数阶说明
    // 线性对数阶其实就是将对数阶代码循环了n遍
    public void m4(int m, int n) {
        for (int i = 0; i < m; i++) { // 线性阶
            int j = 1;
            while (j < n) { // 对数阶
                j = j * 2; 
            }
        }
    }

    平方阶

    // 平方阶
    public void m5(int n) {
        // 可以使用双层for循环来理解平方阶
        for (int i = 0; i < n; i++) { // 线性阶
            for (int j = 0; j < n; j++) {
                //do something
            }
        }
    }

    平均时间复杂度和最坏时间复杂度
    1、平均时间复杂度是指所有可能的输入实例以等概率出现的情况下,该算法的运行时间。
    2、最坏情况下的时间复杂度是最坏时间复杂度,一般讨论的时间复杂度是最坏情况下的时间复杂度,这样做的原因是:最坏情况下的时间复杂度,是算法在任何实例上运行时间的界限,这就保证了算法的运行时间不会比最坏情况更长。
    3、排序算法的时间复杂度如下图所示。

排序算法平均时间最坏情况稳定度额外空间备注
冒泡排序O(n2)O(n2)稳定O(1)n小时较好
交换排序O(n2)O(n2)不稳定O(1)n小时较好
选择排序O(n2)O(n2)不稳定O(1)n小时较好
插入排序O(n2)O(n2)稳定O(1)大部分已经排序好时较好
基数排序O( log ⁡ R B \log_R B logRB)O( log ⁡ R B \log_R B logRB)稳定O(1)B是真数,R是基数
希尔排序O(nlogn)O(ns) 1<s<2不稳定O(1)S是所选分组
快速排序O(nlogn)O(n2)不稳定Olognn大时较好
归并排序O(nlogn)O(nlogn)稳定O(n)n大时较好
堆排序O(nlogn)O(nlogn)不稳定O(1)n大时较好
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值