算法,即计算的方法,使用计算的思想、方法、工具和技术来实现问题求解的思路和途径。计算机提供了计算的能力和硬件设施;算法则提供了计算的思想和软件技术,更好地发挥计算机的潜能。

—— 引

有人说,算法无用,这种观点就如同盲人看不到花开就说世界上没有花一样,是一个长眼睛的人无论如何也难以接受的。举个简单的例子,假如你要对1000,000条记录进行排序,你的计算机每秒可处理1000,000 条记录, 那么, 如果你选择 O(nlogn)的快速排序,所花时间大约是 log2(1000000) = 20s, 如果你选择O(n^2)的插入排序,所花时间大约是 1000000^2/1000000 = 1000000s = 11.57天;如果你选择O(n^3)的XX排序,所花时间大约是1000000^2 = 31709.791年。很明显,拥有子弹的不如拥有导弹的,拥有导弹的不如拥有核弹的。你很容易就可以知道,谁才是未来世界的王者。

算法大师Knuth曾说过:“……算法作为一种一般的智能性工具,有助于对各学科知识的理解……只有将知识教给计算机,才能真正理解知识……比起常规的问题理解来说,将知识表述成算法的形式将使理解更为深刻……”所以,算法不仅可以决定统治世界的王者(除非你将世界上的所有计算机全部销毁),还可以有助于个人的知识学习和理解,甚至,对生活的领悟;算法有助于高效工作的学习工作。

现在,就让我们来梳理一下常用的算法设计技术吧!

一、 分治法:

将问题实例 P(n) 分解为 b 个子问题实例 P(n/b) , 其中有 a 个子问题需要求解。 然后将子问题的解合并起来得到原问题的解。

一言以蔽之, 即“分而合之”。

例子:

①   归并排序: 将待排序列表先分成若干的子列表,分别排序,然后合并起来。归并排序 的关键在于“合”的过程;

②   快速排序: 选取列表中的某种元素,放在列表中的某个位置,使列表分为 小于该元素 和 不小于该元素 的两个子列表。然后, 分别对两个子列表重复上述步骤,直到整个列表有序为止。 快速排序法 关键在“分”的过程。

③    二叉树遍历: 分别遍历根结点、左子树和右子树。具有天然的分治和递归特性。

分治法的效率:

T(n) = aT(n/b) + f(n) , 其中  f(n) 是“分”或者“合”的过程中所耗费的时间。对于归并排序来说, f(n) 是将两个有序列表合并成一个更大的有序列表所耗费的时间; 对于快速排序来说, f(n) 是选取分割元素并将其放在最终位置所耗费的时间。

根据主定理: 令 f(n) = O(n^d),

① 当 d > log(a)/log(b) 时, T(n) = n^d; ② 当 d = log(a)/log(b) 时, T(n) = (n^d)log(n)

③ 当 d < log(a)/log(b) 时, T(n) = n^(log(a)/log(b))

主定理其实很好记: T(n) 的效率 由 aT(n/b) 和 f(n) 的效率比较而得, 其中 aT(n/b) 的效率可看成: n^(log(a)/log(b)),

只要比较幂数取大者就可以了。

常用的分治法,是将问题实例分成规模大致相等的2个子问题实例。根据主定理:

T(n) = 2T(n/2) + O(C) , C 是常数 --------- T(n) = O(n)

T(n) = 2T(n/2) + n   -----  T(n) = O(nlog2(n))

T(n) = 2T(n/2) + n^2 ------------------- T(n) = O(n^2)

可以看出, f(n) 也是起很重要作用的, f(n) 不能太大, 最好是线性的,否则, 采用分治法的效率就可能不高了。合理采用分治法的效率一般应该可以达到O(nlog2(n)),至少应该比采取其他算法技术的效率要高一个级别。

二、减治法:

当 a = 1 时, 即 T(n) = T(n/b) + f(n) 时, 分治法就退化为减治法。 此时,f(n) 的大小就起非常重要的影响了。

减治法有三种形式:

① 减常量: T(n) = T(n-b) + f(n)  eg.

T(n) = T(n-1) + C, C为常数 -----  T(n) = O(n)

T(n) = T(n-1) + n  -----------  T(n) = O(n^2)

减常量的例子: 插入排序 -----  T(n) = T(n-1) + n   T(n) = O(n^2)

② 减常因子: T(n) = T(n/b) + f(n), eg.

T(n) = T(n/2) + C, C为常数 ------ T(n) = O(log2(n))   折半查找

T(n) = T(n/2) + n ---------------- T(n) = O(n^2)

③ 减可变规模: 例如 求最大公约数 gcd(m,n) = gcd(n, m%n)

总之,在使用分治法或者减治法时,应当合理地进行子问题分割,尽量使分和合的过程简单, 使 f(n) 保持线性,这样,才能达到分治法和减治法的高效。

三、动态规划法

动态规划法的解通常具有如下递推形式: S(n) = G(S(n-i) , f(n)) i = 1,2,……,n 其中  S(n-i) 和 S(n-j) 往往具有重合的子问题  S(n-k), k>i,k>j,此时,可以采用自底向上的迭代法或基于记忆功能的递归法来一步步地构造解S(1),S(2),……,S(n)。由于避免了对子问题的重复求解,因此,动态规划法显示出了比较高的效率。

动态规划法与分治法的区别: 分治法所分成的子问题实例通常没有重合的子问题实例,而动态规划法所分成的子问题实例通常有重合的地方,而且,动态规划法的最优解往往蕴含着子问题实例的最优解,因此,可以由子问题实例的最优解逐步构造最终的最优解。

动态规划法的典型例子: 求斐波那契数列、求二项式系数、背包问题、最长子序列问题、矩阵连乘问题。

四、变治法

变治法基于问题转化的思想,将所要求解的问题实例转化为更为特殊形式的问题实例,或者已被求解的其它问题实例。变治法要求对问题之间的联系具备非凡的洞察力。

典型的变治法包括预排序。将待处理列表先进行排序,然后再对有序列表进行其它处理。比如查找问题, 如果采用顺序查找,则需要O(n)的时间,而先排序后二分查找,则需要至少O(nlog2(n)),显然,预排序似乎是多余的。不过,如果要进行多次查找,则预排序就开始起作用了。假设要对1000条记录进行 C 次查找, 则有 Cn > nlog2(n) + Clog2(n), n=1000 可解得 C > 10. 也就是说,仅仅要查找十次以上,预排序就开始起作用了。

另一个变治法的简单例子是求解最小公倍数lcm(m,n)。如果你知道 lcm(m,n) = m*n/gcd(m,n) , gcd(m,n) 是最大公约数, 有一个非常高效的欧几里得算法,那么,这个问题就显得容易得多了。前提是,你要能够具备丰富的知识和良好的洞察力。该问题的最简单的算法是,从1开始,1,2,……,n, 逐个计算直到能被m和n整除为止。 效率为 O(mn); 较好的算法是,取其中最大数 max = max(m,n), 从1开始,逐个进行相乘,max, 2max,……,kmax, 直到能被n 整除位置,效率为 O(min(m,n)).

采用变治法往往可以收到意想不到的效果。要善于进行问题分析,转化问题。

五、 时空权衡

时空权衡基于“空间充裕廉价,时间宝贵”以及“空间极其有限,时间要求不高”的思想,要么以牺牲空间的代价换取时间的高效,要么以牺牲时间的代价换取空间的要求。前者在桌面PC领域更加常见,后者在单片机、嵌入式等产品中体现较明显。

典型的例子:

计数排序: 使用一个数组来存储比元素大或者小的元素个数,根据这些值来确定元素在最终列表中的位置。

散列法:    使用数组和链表的结合来实现字典的高效。首先,采用某种哈希函数hash(x) 将 基于键key 的记录映射到哈希表的相应位置hashtable[hash(key)]中,如果有冲突(多个键的记录被映射到同一个下标),则使用附在该下标的链表存储冲突的记录。这也是一个显示数据结构组合应用能够产生强大功能的令人深刻的例子。

递归/非递归遍历: 使用额外的栈或者标记来存储遍历过程中已经遍历了的元素,从而避免重复遍历。

六、 贪婪技术

总是从当前的可行选择中选取局部最优的部分解,一步步构造最终的解。贪婪技术逐步构造最优解的三个条件:

1. 可行:满足问题的约束条件

2. 局部最优:在当前可行的选择中总是选择局部最优的部分解。

3. 不可撤销:一旦做出选择,就不可撤销。

贪婪技术的典型例子: 找硬币、最小生成树的 Prim算法 和 Kruskal算法 , 单起点最短路径的 Dijskra算法。

七、 蛮力法

不要小看蛮力法。蛮力法总是可以找到一个解,虽然这个解通常并不实用。蛮力法的作用是,找到一个解,然后对其进行改进。蛮力法有时可以给人带来惊喜。比如 子字符串匹配(判断字符串str 中是否含有子字符串pattern) 的蛮力法版本,其最差效率O(mn),平均效率为O(m), m,n  分别是 str 和 pattern 的长度。也就是说,蛮力法版本的子字符串匹配算法是比较实用的。

蛮力法的典型例子: 排列组合问题的穷举查找法。

八、 迭代改进

迭代改进法,总是最先找到一个可行解,然后通过一些小的、局部的变化来改进这个可行解,使之趋向最优解。迭代改进的关键是稳定性、收敛性。

迭代法的典型例子: 遗传算法

九、 回溯法

回溯法是穷举查找法的改进版本,穷举查找法通常先列举出所有的候选解,然后根据目标问题来找出满足要求的解或最优解。而回溯法则“聪明”了一些,一步一步地构造解的分量,一旦有分量不可行,则此路不通,马上转道。回溯法通常根据问题构造一棵状态树,通过遍历状态树的结点来求解。叶子节点代表无解或可行解。

回溯法的典型例子: n 皇后问题,图的深度遍历

十、 分枝定界技术

分枝定界技术与回溯法非常相似。由于我还没有学到这里,因此,暂不作讨论。分枝定界技术常用来求解最优化问题。

十一、 求近似解

退而求其次,不失为一种明智的选择。如果花20分钟可以获得旅行商问题的实用解,那么,再多花十个小时,使解获得0.1%的改进,是否有必要?对于理论工作者来说,确实如此。但如果是实践工作者,我会选择前者。要学会权衡投资/收益比。

结语:

总结算法,应用算法。算法,当之无愧是计算机科学的灵魂和基石。无论是硬件还是软件,无论是专业还是生活,算法无处不在。不能因为暂时用不到就贬低它的价值,——事实上,这是一种掩耳盗铃的做法。你不用,别人总会用的,而且,别人可以从中体验乐趣,获取丰厚的回报。千万不要跟算法过不去。

参考书籍:

1. 《算法设计与分析基础》[第2版] ,  (美)Anany Levitin , 潘彦译, 2004/06, 清华大学出版社

2. 《算法导论》[第2版],Thomas H. Cormen,Charles E. Leiserson,Ronald L. Rivest,Clifford Stein, 潘金贵 等译, 2006/09, 机械工业出版社

常用算法设计技术总结相关推荐

  1. 算法设计之五大常用算法设计方法总结

    算法设计之五大常用算法设计方法总结 一.[分治法] 在计算机科学中,分治法是一种很重要的算法.字面上的解释是"分而治之",就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再 ...

  2. 【算法】算法设计技术

    算法设计技巧 文章目录 算法设计技巧 贪心算法(贪婪算法) 多处理器情况 活动选择问题 活动选择问题(加权) 递归解 独立集问题 树上的独立集问题 装箱问题 联机和脱机 近似在线装箱算法 脱机算法 分 ...

  3. 【编程珠玑】第八章 算法设计技术

    一,概述 问题:求一维数组中连续子向量的最大和. 例如:a[6]={3,4,-2,-9,10,8}; 则最大连续子向量的和 为 10+8 = 18 1)解法一:简单算法 #include <st ...

  4. 计算机 五大算法类型,计算机算法设计五大常用算法的分析及实例.docx

    标准化管理处编码[BBX968T-XBB8968-NNJ668-MM9N] 标准化管理处编码[BBX968T-XBB8968-NNJ668-MM9N] 计算机算法设计五大常用算法的分析及实例 摘要 算 ...

  5. 算法设计与分析python_Python算法设计与分析

    内容提要 本书内容包括算法初步.排序算法.查找.双指针问题.哈希算法.深度优先搜索算法.广度优先搜索算法.回溯算法.动态规划.贪心算法.分治算法.并查集.最短路径算法和数论算法等常见算法.每个算法都做 ...

  6. 计算机算法设计与分析读后感,算法设计与分析基础经典读后感有感

    <算法设计与分析基础>是一本由Anany levitin著作,清华大学出版社出版的胶版纸图书,本书定价:49.00元,页数:409,特精心从网络上整理的一些读者的读后感,希望对大家能有帮助 ...

  7. 算法设计与分析基础知识点

    前言:全文参考徐承志老师的PPT 适合期末复习,查缺补漏,有缺漏或错误欢迎指正,后面的第九章内容之后会继续补充. 目录 一.算法基础概念 二.算法分析基础 1.概念 2.算法设计的一般过程 3.时间复 ...

  8. 游戏开发常用算法 (一)

    http://blog.csdn.net/pizi0475/article/details/9771957 要使计算机能完成人们预定的工作,首先必须为如何完成预定的工作设计一个算法,然后再根据算法编写 ...

  9. 海南大学期末复习——算法设计与分析

    目录 引言 算法基础知识 算法的五个特性:(必考) 常用的描述算法的方法: 时间复杂度: 基本的算法设计技术 分治法与减治法 基本思路: 同与异: 适用范围: 应用: 归并排序 快速排序: 堆排序: ...

最新文章

  1. vs2010 问题 LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
  2. OpenStack运维面试(1)
  3. c#中的23种设计模式
  4. linux物理内存地址与iomem,一种Linux系统物理内存镜像文件分析方法_4
  5. 组策略对应于注册表位置汇总
  6. unity DOTS的学习总结之Job System应用——绘制曼德勃罗集合
  7. spring 事务_极限 Spring (4) Spring 事务
  8. 通用程序算法和数据结构_了解通用数据结构
  9. 软件测试之SOL面试题(一)
  10. 关于Itext 报错-java.lang.NoClassDefFoundError: org/bouncycastle/asn1/ASN1Encodable
  11. STM32笔记之 SWJ(JTAG-DP和 SW-DP)
  12. miniusbpcb封装_USB接口封装及定义大全,不用去翻手册了
  13. 国美金融贷款绝对定位与相对定位的关系(国美金融贷款位置)
  14. NC21499-今天,你惹对象生气了吗(dfs)
  15. ios 开发者论坛和资料站点
  16. 利用计算机Tracert,tracert,教您tracert命令使用详解
  17. 访客机如何应用于小区门禁?
  18. Java开发岗:本硕211毕业一年,大厂面试最终拿下美团offer!献上我的面经+Java核心知识点(秋招适用)
  19. 去水印软件哪个好_去水印工具
  20. 启明创投投资企业神州细胞成功登陆科创板

热门文章

  1. aks Unable to connect to the server: x509
  2. js实现自定义打印区域
  3. java 阶梯_Java if-else-if阶梯语句
  4. 网络攻防——Goby+AWVS漏洞扫描
  5. ESP32 DEVKIT V1 资料分享-原理图+引脚图
  6. Android状态栏下拉处理
  7. Learn UML with JUDE
  8. 什么是 DNS 故障?常见原因和解决方案
  9. python分解word文档为多个_如何将一个word文档按页分割成多个word文档-百度经验...
  10. werfault.exe出现的原因与解决办法