知乎连接:https://zhuanlan.zhihu.com/p/56583442程序员
算法思想有不少,业界公认的经常使用算法思想有8种,分别是枚举、递推、递归、分治、贪心、试探法、动态迭代和模拟。固然8种只是一个大概的划分,是一个“仁者见仁、智者见智”的问题。算法
枚举算法思想的最大特色是,在面对任何问题时它会去尝试每一种解决方法。在进行概括推理时,若是逐个考察了某类事件的全部可能状况,于是得出通常结论,那么这个结论是可靠的,这种概括方法叫做枚举法。编程
枚举算法基础函数
枚举算法的思想是:将问题的全部可能的答案一一列举,而后根据条件判断此答案是否合适,保留合适的,丢弃不合适的。在C语言中,枚举算法通常使用while循环实现。使用枚举算法解题的基本思路以下。设计
① 肯定枚举对象、枚举范围和断定条件。3d
② 逐一列举可能的解,验证每一个解是不是问题的解。orm
枚举算法通常按照以下3个步骤进行。对象
① 题解的可能范围,不能遗漏任何一个真正解,也要避免有重复。blog
② 判断是不是真正解的方法。递归
③ 使可能解的范围降至最小,以便提升解决问题的效率。
枚举算法的主要流程如图1-1所示。
1-1枚举算法流程图
与枚举算法思想相比,递推算法可以经过已知的某个条件,利用特定的关系得出中间推论,而后逐步递推,直到获得结果为止。因而可知,递推算法要比枚举算法聪明,它不会尝试每种可能的方案。
递推算法基础
递推算法能够不断利用已有的信息推导出新的东西,在平常应用中有以下两种递推 算法。
① 顺推法:从已知条件出发,逐步推算出要解决问题的方法。例如斐波那契数列就能够经过顺推法不断递推算出新的数据。
② 逆推法:从已知的结果出发,用迭表明达式逐步推算出问题开始的条件,即顺推法的逆过程。
由于递归算法思想每每用函数的形式来体现,因此递归算法须要预先编写功能函数。这些函数是独立的功能,可以实现解决某个问题的具体功能,当须要时直接调用这个函数便可。
在计算机编程应用中,递归算法对解决大多数问题是十分有效的,它可以使算法的描述变得简洁并且易于理解。递归算法有以下3个特色。
① 递归过程通常经过函数或子过程来实现。
② 递归算法在函数或子过程的内部,直接或者间接地调用本身的算法。
③ 递归算法其实是把问题转化为规模缩小了的同类问题的子问题,而后再递归调用函数或过程来表示问题的解。
在使用递归算法时,读者应该注意以下4点。
① 递归是在过程或函数中调用自身的过程。
② 在使用递归策略时,必须有一个明确的递归结束条件,这称为递归出口。
③ 递归算法一般显得很简洁,可是运行效率较低,因此通常不提倡用递归算法设计程序。
④ 在递归调用过程当中,系统用栈来存储每一层的返回点和局部量。若是递归次数过多,则容易形成栈溢出,因此通常不提倡用递归算法设计程序。
分治算法也采起了各个击破的方法,将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。只要求出子问题的解,就可获得原问题的解。
分治算法基础
在编程过程当中,常常遇处处理数据至关多、求解过程比较复杂、直接求解法会比较耗时的问题。在求解这类问题时,能够采用各个击破的方法。
具体作法是:先把这个问题分解成几个较小的子问题,找到求出这几个子问题的解法后,再找到合适的方法,把它们组合成求整个大问题的解。若是这些子问题仍是比较大,还能够继续再把它们分红几个更小的子问题,以此类推,直至能够直接求出解为止。这就是分治算法的基本思想。
使用分治算法解题的通常步骤以下。
① 分解,将要解决的问题划分红若干个规模较小的同类问题。
② 求解,当子问题划分得足够小时,用较简单的方法解决。
③ 合并,按原问题的要求,将子问题的解逐层合并构成原问题的解。
贪心算法也被称为贪婪算法,它在求解问题时总想用在当前看来是最好方法来实现。这种算法思想不从总体最优上考虑问题,仅仅是在某种意义上的局部最优求解。
虽然贪心算法并不能获得全部问题的总体最优解,可是面对范围至关普遍的许多问题时,能产生总体最优解或者是总体最优解的近似解。因而可知,贪心算法只是追求某个范围内的最优,能够称之为“温柔的贪婪”。
贪心算法基础
贪心算法从问题的某一个初始解出发,逐步逼近给定的目标,以便尽快求出更好的解。当达到算法中的某一步不能再继续前进时,就中止算法,给出一个近似解。由贪心算法的特色和思路可看出,贪心算法存在如下3个问题。
① 不能保证最后的解是最优的。
② 不能用来求最大或最小解问题。
③ 只能求知足某些约束条件的可行解的范围。
贪心算法的基本思路以下。
① 创建数学模型来描述问题。
② 把求解的问题分红若干个子问题。
③ 对每一子问题求解,获得子问题的局部最优解。
④ 把子问题的局部最优解合并成原来解问题的一个解。
实现该算法的基本过程以下。
(1)从问题的某一初始解出发。
(2)while能向给定总目标前进一步。
(3)求出可行解的一个解元素。
(4)由全部解元素组合成问题的一个可行解。
试探法也叫回溯法,试探法的处事方式比较委婉,它先暂时放弃关于问题规模大小的限制,并将问题的候选解按某种顺序逐一进行枚举和检验。当发现当前候选解不多是正确的解时,就选择下一个候选解。
若是当前候选解除了不知足问题规模要求外可以知足全部其余要求时,则继续扩大当前候选解的规模,并继续试探。若是当前候选解知足包括问题规模在内的全部要求时,该候选解就是问题的一个解。在试探算法中,放弃当前候选解,并继续寻找下一个候选解的过程称为回溯。扩大当前候选解的规模,并继续试探的过程称为向前试探。
试探法算法基础
使用试探算法解题的基本步骤以下所示。
① 针对所给问题,定义问题的解空间。
② 肯定易于搜索的解空间结构。
③ 以深度优先方式搜索解空间,并在搜索过程当中用剪枝函数避免无效搜索。
试探法为了求得问题的正确解,会先委婉地试探某一种可能的状况。在进行试探的过程当中,一旦发现原来选择的假设状况是不正确的,当即会自觉地退回一步从新选择,而后继续向前试探,如此这般反复进行,直至获得解或证实无解时才死心。
假设存在一个能够用试探法求解的问题P,该问题表达为:对于已知的由n元组(y1,y2,…,yn)组成的一个状态空间E={(y1,y2,…,yn)∣yi∈Si,i=1,2,…,n},给定关于n元组中的一个份量的一个约束集D,要求E中知足D的所有约束条件的全部n元组。其中,Si是份量yi的定义域,且|Si|有限,i=1,2,…,n。E中知足D的所有约束条件的任一n元组为问题P的一个解。
解问题P的最简单方法是使用枚举法,即对E中的全部n元组逐一检测其是否知足D的所有约束,若是知足,则为问题P的一个解。可是这种方法的计算量很是大。
对于现实中的许多问题,所给定的约束集D具备完备性,即i元组(y1,y2,…,yi)知足D中仅涉及y1,y2,…,yj的全部约束,这意味着j(j<i)元组(y1,y2,…,yj)必定也知足D中仅涉及y1,y2,…,yj的全部约束,i=1,2,…,n。换句话说,只要存在0<=j<=n−1,使得(y 1,y 2,…,yj)违反D中仅涉及y1,y2,…,yj的约束之一,则以(y1,y2,…,yj)为前缀的任何n元组(y1,y2,…,yj,yj+1,…,yn)必定也违反D中仅涉及y 1,y2,…,yi的一个约束,n>=i>;j。
所以,对于约束集D具备完备性的问题P,一旦检测判定某个j元组(y1,y2,…,yj)违反D中仅涉及y1,y2,…,yj的一个约束,就能够确定,以(y1,y2,…,yj)为前缀的任何n元组(y1,y2,…,yj,yj+1,…,yn)都不会是问题P的解,于是就没必要去搜索它们、检测它们。试探法是针对这类问题而推出的,比枚举算法的效率更高。
迭代法也称展转法,是一种不断用变量的旧值递推新值的过程,在解决问题时老是重复利用一种方法。与迭代法相对应的是直接法(或者称为一次解法),即一次性解决问题。迭代法又分为精确迭代和近似迭代。“二分法”和“牛顿迭代法”属于近似迭代法,功能都比较相似。
迭代算法基础
迭代算法是用计算机解决问题的一种基本方法。它利用计算机运算速度快、适合作重复性操做的特色,让计算机对一组指令(或必定步骤)进行重复执行,在每次执行这组指令(或这些步骤)时,都从变量的原值推出它的一个新值。
在使用迭代算法解决问题时,须要作好以下3个方面的工做。
(1)肯定迭代变量
在可使用迭代算法解决的问题中,至少存在一个迭代变量,即直接或间接地不断由旧值递推出新值的变量。
(2)创建迭代关系式
迭代关系式是指如何从变量的前一个值推出其下一个值的公式或关系。一般可使用递推或倒推的方法来创建迭代关系式,迭代关系式的创建是解决迭代问题的关键。
(3)对迭代过程进行控制
在编写迭代程序时,必须肯定在何时结束迭代过程,不能让迭代过程无休止地重复执行下去。一般可分为以下两种状况来控制迭代过程:
① 所需的迭代次数是个肯定的值,能够计算出来,能够构建一个固定次数的循环来实现对迭代过程的控制;
② 所需的迭代次数没法肯定,须要进一步分析出用来结束迭代过程的条件。
模拟是对真实事物或者过程的虚拟。在编程时为了实现某个功能,能够用语言来模拟那个功能,模拟成功也就相应地表示编程成功。
模拟算法的思路
模拟算法是一种基本的算法思想,可用于考查程序员的基本编程能力,其解决方法就是根据题目给出的规则对题目要求的相关过程进行编程模拟。在解决模拟类问题时,须要注意字符串处理、特殊状况处理和对题目意思的理解。
在C语言中,一般使用函数srand()和rand()来生成随机数。其中,函数srand()用于初始化随机数发生器,而后使用函数rand()来生成随机数。若是要使用上述两个函数,则须要在源程序头部包含time.h文件。在程序设计过程当中,可以使用随机函数来模拟天然界中发生的不可预测状况。在解题时,须要仔细分析题目给出的规则,要尽量地作到全面考虑全部可能出现的状况,这是解模拟类问题的关键点之一。