自编教材分享:第六章—程序编写优化(一)


算法简介
任何问题的解决都有一定的方法和步骤,算法就是计算机解决问题过程的描述。从程序设计的角度看,算法由一系列求解问题的指令构成,能根据规范的输入,在有限的时间内获得有效的输出结果,代表了用系统的方法来描述解决问题的一种策略机制。

算法复杂度这一指标用于考量算法需要的时间和空间。算法的时间复杂度,即程序执行时间增长的变化趋势。空间复杂度是指一个程序在运行过程中临时占用存储空间大小的一个量度。
一般来说,常见的时间复杂度量级有常数阶、对数阶、线性阶、线性对数阶、平方阶、指数阶、阶乘阶等,依次按照顺序时间复杂度越来越大,执行效率也越来越低。

选择适合算法
算法优化是指通过对算法进行更好的设计以提升程序的性能,程序中的算法优化可以从选择合适的算法以及算法自身的优化这两方面进行考虑,本节结合常用的排序算法进行说明。
常用的排序算法有十余种,分为基于比较的插入、选择、交换这三类,如冒泡排序、快速排序等。下面选择三类排序算法中的几个典型算法及优化思路进行介绍,分析每种算法的复杂度及其性能的差异,阐述不同应用场景下选择合适算法对程序性能的影响:
冒泡排序
冒泡排序是一种简单的交换排序算法。通过元素的两两比较,判断是否符合排序要求,如果不符合就交换位置来达到排序的目的。对于n个需要排序的数据来说,其算法复杂度为。其每次排序之后仍会继续进行下一轮的比较,无效计算较多,因此只适用于数据量较小的场景。
直接插入排序
插入排序是通过把序列中的值插入一个有序序列对应的位置上,直到该序列结束。插入排序的赋值操作次数是比较操作次数减去(n-1)次,平均来说插入排序算法复杂度为,但在部分数据有序的情况下其效率比冒泡排序更快。
简单选择排序
这种排序方式每次从待处理数据中选出最小的,放在已经排好序的序列末尾,直至所有排序结束。假设有n个待排序的数据,则比较的总次数为n*(n-1)/2,时间复杂度为。可以看出选择排序的对比次数较多但数据移动次数较少,在数据量大的情况下其效率明显优于冒泡排序,适用于大多数排序场景。
改进算法策略
通过前文的描述已经说明了算法的性能表现会对程序性能产生较大影响,所以在保证正确性的前提下通过改进算法策略提升程序性能是十分有必要的。改进算法策略的方法归结起来可以分为以下两点:
从算法过程出发,尽量减少算法复杂度,提高其运行的效率。
从算法编码出发,运用一些技巧优化算法中的编码方式,从编码角度提升算法性能。
枚举算法
假设输入向量包含下面7个元素,分别为(8,-33,16,9,-12,45,67),则该向量的连续子向量的最大和为x[3-7]的总和125,此算法实现及改进思路如下:
枚举算法实现。此向量中所有子向量数都是正数时,显然子向量最大和就是整个输入向量的和。当输入向量中含有负数时,遍历所有数组下标范围[i,j]的子向量求和,通过比较计算出最大和。
枚举算法优化
上述枚举算法示例中存在部分重复运算,此时可以利用一个变量保存之前的运算结果避免部分冗余计算。经过改进后算法的复杂度为,改进后部分代码如下:
分治算法
可以采用分治技术将问题分解成2个与原问题形式相同的子问题分别递归求解。把向量序列从中间分为左右A和B两部分,把A作为新的输入序列求出左半部分的最大子向量和A1,同理求出右半部分的最大子向量和B1,将跨越左右部分的最大向量和称为C1。最后取这三个子向量和中的最大值即可。该算法的时间复杂度为,整体性能高于前两种算法。
线性算法
此问题还可以从头到尾扫描数组的思路求解。假设往一个长度为i的向量后面插入第i+1个数,此时只需要从包含第i+1个数和不包含第i+1个数的序列中选出最大的子向量和,而后者是已知的。因此x[i]作为末尾元素时能找到的最大子向量和和要么是x[i]本身,要么是x[i-1]作为末尾元素时能找到的最大子向量和再拼接上x[i]。该代码时间复杂度为。