数据结构和算法(一)复杂度

介绍

随着开发进度渐进渐深和产品用户的更高台阶的突破,你回发现数据结构和算法的重要性,作为一个Android开发工程师随着技术的发展,你会发现你要掌握的知识点要越来越广,比如Kotlin,NDK,Flutter,主流框架的源码,线程的并发等,但是所有这些知识点都离不开数据结构和算法,掌握了算法思维在技术选项的时候能够快速的定位到合适自己项目的框架。我们上大学的时候在书本上看到过这句话:数据结构+算法=程序;可见算法和数据结构的重要性,我们就重温一下这两个课题。

复杂度

我们都是到算法的优劣和算法的复杂度息息相关,那么什么是复杂度?复杂度的计算规则是什么呢?算法就是一个计算机任务,将输入数据进行加工处理得到结果的过程。算法在计算的过程会消耗两部分资源:时间资源,内存资源,我们也称内存资源就是空间资源。在这个计算任务的过程中,消耗的资源和输入的数据量有直接的关系,那么我们称复杂度是一个关于数据量N的函数。通常我们使用O(n)等表示复杂度。复杂度的计算规则如下:

  • 复杂度与具体常数无关 当输入的数据量取向无穷大的时候,常数对函数的影响可以忽略不计。
  • 多项式复杂度相加的时候,选择高着作为结果,比如O(n2)+O(n),如果用坐标系图会指出来,你回发现当N越来越大,趋向无穷大的时候O(n2)的影响性是最大的。

为了方便你理解不同计算方法对复杂度的影响,我们来看一个代码任务:对于输入的数组,输出与之逆序的数组。例如,输入 a=[1,2,3,4,5],输出 [5,4,3,2,1]。

方法一建立并初始化数组 b,得到一个与输入数组等长的全零数组。通过一个 for 循环,从左到右将 a 数组的元素,从右到左地赋值到 b 数组中,最后输出数组 b 得到结果。

  fun reverseArray(){
        val a:IntArray = intArrayOf(1,2,3,4,5)
        val b:IntArray = IntArray(5)
        for (i in a.withIndex()) {
            b[b.size-1-i.index] = i.value
        }

        b.forEach(::println)
    }

这段代码使用for循环将数组a中的元素倒序的存入b数组中,其执行次数和a数组的长度成线性关系,因此时间复杂度是O(n)
方法二我们对数组的首位元素进行交换位置,实现方式如下:

 fun reverseArray2(){
        val a:IntArray = intArrayOf(1,2,3,4,5)
        val maxIndex = a.size-1
        for(i in 0..a.size/2){
            val tmp = a[i]
            a[i]=a[maxIndex-i]
            a[maxIndex-i]=tmp
        }

        a.forEach(::println)
    }

这个算法的循环计算次数是a.size/2,因此时间复杂度是O(n/2),根据复杂度计算规则1,忽略常数后的时间复杂度是O(n),那么空间复杂度呢?空间方面我们只是定义了一个临时变量tmp,这个临时变量与元素的个数无关因此空间复杂度是O(1)。

总结

通过前面的分析我们可以知道时间复杂度和代码结构紧密相关,空间复杂度和数据结构的设计相关。

你可能感兴趣的:(数据结构和算法(一)复杂度)