算法的优化

  算法的优化分为全局优化和局部优化两个层次。全局优化也称为结构优化,主要是从基本控制结构优化、算法、数据结构的选择上考虑;局部优化即为代码优化,包括使用尽量小的数据类型、优化表达式、优化赋值语句、优化函数参数、全局变量及宏的使用等内容。

  一、全局优化

    1.优化算法设计

      例如,在排序中用快速排序或者堆排序代替插入排序或冒泡排序;用较快的折半查找代替顺序查找法等,都可以极大地提高程序的执行效率。

    2.优化数据结构

      例如在一堆随机存放的数中使用了大量的插入和删除指令,那么使用链表要快得多。数组和指针具有十分密切的关系,一般来说,指针比较灵活简洁,而数组比较直观,容易理解。在许多情况下,可以用指针运算代替数组,这样做常常能产生又快又短的代码,并且运行速度快,占用空间少。

    3.优化选择结构

      ①嵌套if语句的使用。当if结构中要判断的并列条件较多的时候,最好将它们拆分成多个if语句结构,然后嵌套在一起,就可以减少不必要的判断。

      ②嵌套switch语句的使用。switch语句中的case很多时,为了减少比较次数,可以把大switch语句转化为嵌套switch语句。把频率较高的case标号放在一个switch语句中,而发生频率较低的case标号则放到另一个switch语句当中。

      ③给switch语句中的case排序。根据发生的可能性对case的值排序,最有可能的放在第一位就可以使选择过程更合理,从而提高了效率。

    4.优化循环结构

      提高程序效率的核心是对影响代码执行速度的关键程序段进行优化。在任何程序中,最影响代码速度的往往是循环结构,特别是多层嵌套的循环结构。掌握循环优化的的各种实用技术是提高程序效率的关键。

      常用的循环优化技术如下:

      ①降价策略。通过算法分析我们知道算法的事件复杂度主要是由循环嵌套的层数决定的,所以,算法中如果能够减少循环嵌套的层数,如将双重循环改写成单循环,则从事件复杂度上可达到降价的目的。

      ②加速原理。是指将循环体内的选择结构去掉,则加速循环结构的执行效率。

      ③代码外提。是指将循环体中与循环变量无关的运算提出,并将其放到循环之外,以避免每次循环过程中的重复操作。

      ④变换循环控制条件。当某循环变量在循环体中除自身引用外,已不再控制循环过程时,可以将其从循环中删去。

      ⑤合并循环。把两个或两个以上的循环合并放到一个循环里,这样会加快速度。使用循环虽然简单,但是使用不当,往往可能带来很大的性能影响。原则是将问题充分分解为小的循环,不在循环内的多余的工作(如赋值、常量计算等),避免死循环。还可以考虑将循环改为非循环来提高效率。

  二、局部优化

    1.使用尽量小的数据类型

      能够使用字符型(char)定义的变量,就不要使用整型(int)变量来定义;能够使用整型变量定义的变量就不要使用长整型(long int),能不使用浮点型(float)就不要使用浮点型变量。当然,在定义变量后不要超过变量的作用范围,如果超过变量的范围赋值,C编译器并不报错,但程序运行结果却错了,而且这样的错误很难发现。

    2.优化表达式

      对于一个表达式中各种运算执行的优先顺序不太明确或容易混淆的地方,应当采用圆括号明确指定他们的优先顺序。一个表达式通常不能写的太复杂,如果表达式太复杂,时间久了,自己也不容易看得懂,不利于以后的维护。

    3.使用自增、自减和复合赋值运算符

      通常使用自增、自减运算符和复合赋值表达式(如a-=1及a+=1等)都能够生成高质量的程序代码,编译器通常都能够生成inc和dec之类的指令,而使用a=a+1或a=a-1之类的指令,有很多C编译器都会生成二到三个字节的指令。

    4.使用运算量较小(但功能相同)的表达式代替复杂的表达式可以减少运算的强度。例如平方运算:a=pow(b,2.0)优化为:a=b*b。

    5.避免浮点运算。C语言中的浮点型float和双精度型double运算比短整型、整型、长整型运算要慢得多,因此避免浮点运算就非常有必要。

    6.优化赋值语句。在代码中,若一个变量经赋值后在后面语句的执行过程中不再引用,则这一赋值语句就称为无用赋值,可以不用。当赋值语句中出现多个已知量的运算时,可以将其合并成一个值,减少程序执行过程中重复计算的工作量。

    7.优化函数参数。在C语言中,调用函数的第一步是传递参数给寄存器或堆栈。当函数的参数很多时,就要调用大量的堆栈空间,开销会很大。当结构作为函数参数传递的内容时,编译器的第一步操作是把整个结构复制到堆栈,这种情况下堆栈空间的使用会非常大。此外,如果结构作为函数返回值,调用程序会把堆栈空间保留,把结构地址传递给函数同时调用函数,接着把函数返回。最后,调用程序需要把堆栈空间清除,并把返回的结构拷贝到第二个结构当中。这样代码和堆栈的开销就会非常惊人。因此应禁止传递结构,一般用结构指针作为函数的参数,来避免这种开销。

    8.宏的使用

    在程序设计过程中,对于经常使用的一些常数,如果将它直接写到程序中去,一旦常数的数值发生变化,就必须逐个找出程序中所有的常数,并逐一进行修改,这样必然会降低程序的可维护性。因此,应该采用预处理命令中的宏定义,而且还可以避免输入错误。

    宏定义除了一些大家所熟知的好处外,如可以提高程序的清晰性、可读性,便于修改移植等,还有一个很妙的地方:利用宏定义来代替函数可以提高程序设计的效率。

算法优化中的注意事项:

    1.程序的优化以不破坏程序的可读性、可理解性为原则。

    2.如果将程序的执行效率纳入软件的整个生命周期来考虑,为提高单个程序的效率而花费大量的开发时间往往得不偿失,在下列情况下,程序的优化才有意义。

      ①首先保证程序的正确性和健壮性,然后才考虑优化。

      ②严重影响效率的程序才值得优化。例如系统反复调用的核心模块,无关大局的模块没有优化的价值。

摘自《算法设计方法与优化》

      

      

算法的优化(C语言描述)的更多相关文章

  1. 图的建立(邻接矩阵)+深度优先遍历+广度优先遍历+Prim算法构造最小生成树(Java语言描述)

    主要参考资料:数据结构(C语言版)严蔚敏   ,http://blog.chinaunix.net/uid-25324849-id-2182922.html   代码测试通过. package 图的建 ...

  2. 常用排序算法总结(C语言描述)

    最近又把排序给复(yu)习(xi)了一遍,在此总结一下~具体理论思想持续补充完善中... 1.交换排序 (1)普通冒泡 时间复杂度:最差.平均都是O(n^2),最好是O(n) 空间复杂度:O(1) # ...

  3. 数据结构算法与应用c++语言描述 原书第二版 答案(更新中

    目录 第一章 C++回顾 函数与参数 1.交换两个整数的不正确代码. 异常 10.抛出并捕捉整型异常. 第一章 C++回顾 函数与参数 1.交换两个整数的不正确代码. //test_1 void sw ...

  4. 机器学习|线性回归算法详解 (Python 语言描述)

    原文地址 ? 传送门 线性回归 线性回归是一种较为简单,但十分重要的机器学习方法.掌握线性的原理及求解方法,是深入了解线性回归的基本要求.除此之外,线性回归也是监督学习回归部分的基石. 线性回归介绍 ...

  5. 用 C 语言描述几种排序算法

    排序算法是最基本且重要的一类算法,本文基于 VS2017,使用 C 语言来实现一些基本的排序算法. 一.选择排序 选择排序,先找到数组中最小的元素,然后将这个元素与数组的第一个元素位置互换(如果第一个 ...

  6. 快色排序算法(C语言描述)

    快速排序 算法思想 快速排序采用了一种分治策略,学术上称之为分治法(Divide-and-Conquer Method). 哨兵(如下算法中的key) 每趟排序将哨兵插入到数组的合适位置,使得哨兵左侧 ...

  7. 《算法详解:C++11语言描述》已出版

    经过漫长的编写.修订和印刷过程,书籍<算法详解:C++11语言描述>终于出版了!目前本书已在各大电商平台上架,搜索书名即可找到对应商品.本书的特色在于: 介绍最新的C++11.C++14和 ...

  8. 《数据结构与算法分析——C语言描述》ADT实现(NO.00) : 链表(Linked-List)

    开始学习数据结构,使用的教材是机械工业出版社的<数据结构与算法分析——C语言描述>,计划将书中的ADT用C语言实现一遍,记录于此.下面是第一个最简单的结构——链表. 链表(Linked-L ...

  9. 三元组表压缩存储稀疏矩阵实现稀疏矩阵的快速转置(Java语言描述)

    三元组表压缩存储稀疏矩阵实现稀疏矩阵的快速转置(Java语言描述) 用经典矩阵转置算法和普通的三元组矩阵转置在时间复杂度上都是不乐观的.快速转置算法在增加适当存储空间后实现快速转置具体原理见代码注释部 ...

随机推荐

  1. Delhi 安装ocx的方法

    Delhi 安装ocx的方法 1.通过cmd注册 2.通过delphi 注册 然后 可以修改 classnames  改成__tlb.pas单元中的控件的名称,就可以了 例如下图:

  2. linux 内核驱动加载过程中 向文件系统中的文件进行读写操作

    utils.h 文件: #ifndef __UTILS_H__ #define __UTILS_H__ void a2f(const char *s, ...); #endif utils.c 文件: ...

  3. Java 集合框架 ArrayList 源码剖析

    总体介绍 ArrayList实现了List接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入null元素,底层通过数组实现.除该类未实现同步外,其余跟Vector大致相同.每个ArrayL ...

  4. mapreduce 读写lzo文件

    1.读lzo文件 需要添加以下代码,并导入lzo相关的jar包  job.setInputFormatClass(LzoTextInputFormat.class); 2.写lzo文件 lzo格式默认 ...

  5. PPT扁平化手册 2

  6. 查看pid

    可以使用ps -ef | grep httpd查看PID 然后kill –l PID

  7. Java基础知识强化16:深入分析Java线程中断机制

    1.Thread.interrupt真的能中断线程吗?       在平时的开发过程中,相信都会使用到多线程,在使用多线程时,大家也会遇到各种各样的问题,今天我们就来说说一个多线程的问题——线程中断. ...

  8. codevs 3052 多米诺 二分图匹配

    /*codevs 3052 二分图匹配 把矩阵分两批 黑和白 且黑白不相交 这就构成了二分图的两部分 然后求最大匹配*/ #include<cstdio> #include<cstr ...

  9. 每次打开VS2010都会报“ devenv.exe -Assert Failure”这个错误

    把.net framework4.5中文包卸载掉,, 如果还不行就把.net framework4.5也卸载掉,,然后到微软官网下载net framework4.5安装包安装,安装完后把中文包卸载掉就 ...

  10. sql语句游标的写法

    当循环查找一张表的信息时,我们得写一张游标来对每条信息进行操作,具体格式如下 DECLARE @fitemid int DECLARE #point_cursor CURSORFORSELECT fi ...