C语言的六种常用算法

合集下载
相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

六种常用算法

一、有条不紊——递推法破解难题

问:“我对数据结构有了一定了解,但还是不太懂程序。从经典公式“程序=算法+数据结构”得知,是因为不了解算法。能不能介绍几种简单的算法,当然从最容易懂的那种开始了?”

答:“算法就是能够证明正确的解题步骤,算法有许多种,最简单的无非下面的六种:递推法、贪心法、列举法、递归法、分治法和模拟法。刚听名字挺吓人的,其实有好多程序我们平常都见过。这些算法当中,最最简单的莫过于递推算法了。下面举例说明。”

1、什么是递推法

递推法这种解题方法其实在我们编程的过程中用的很多,只不过没有将其上升到理论的高度罢了。所谓递推法,就是找出和时间先后相联系或和数的大小相联系的步骤,上一步和下一步和数字的增大或减小有一定的联系。我们要么从前向后(或从小到大)推导,也可从后向前(或从大到小)推导。由此得出两种推导方法:顺推法和倒推法。请看下面的示例。

示例:猴子分食桃子:五只猴子采得一堆桃子,猴子彼此约定隔天早起后再分食。不过,就在半夜里,一只猴子偷偷起来,把桃子均分成五堆后,发现还多一个,它吃掉这桃子,并拿走了其中一堆。第二只猴子醒来,又把桃子均分成五堆后,还是多了一个,它也吃掉这个桃子,并拿走了其中一堆。第三只,第四只,第五只猴子都依次如此分食桃子。那么桃子数最少应该有几个呢?

编程简析:怎样编程呢?先要找一下第N只猴子和其面前桃子数的关系。如果从第1只开始往第5只找,不好找,但如果思路一变,从第N到第1去,可得出下面的推导式:

第N只猴第N只猴前桃子数目

5 s5=x

4 s4=s5*5/4+1

3 s3=s4*5/4+1

2 s2=s3*5/4+1

1 s1=s2*5/4+1

s1即为所求。上面的规律中只要将s1-s5的下标去掉:

s=x

s=s*5/4+1

s=s*5/4+1

s=s*5/4+1

s=s*5/4+1

所以可以用循环语句加以解决。

综观程序的整体结构,最外是一个循环,因为循环次数不定,可以使用While循环,其结束条件则是找到第一个符合条件的数。为了做出上面while循环的结束条件,还需进一步分析上述规律的特点,要符合题目中的要求,s1-s4四个数必须全部为整数,这个可作为条件。具体实现请参看源程序。

int peach()

{ //最少最后应该是5 的倍数加1但同时又是4 的倍数, 从16 起加

int k = 0,s = 0, x = 16,i = 0;

while( k< 4)

{

k = 0;

s = x;

for(i=4; i>=1; i--)

{

if((s == (s/4)*4) && (s == ((s/5)*5 + 1))) //C 的整除判断

{

// 计一次数

k++;

printf("value s:%d k:%d i:%d\n", s, k, i);

}

s = (s/4)*5 + 1;

}

x += 5;

}

return s;

}

二、稳扎稳打——贪心法破解难题

问:“算法除了递推法,该轮到贪心法了吧,从字面上理解,这种方法有些贪得无厌还是…?”

答:“基本算法中的递推法是我们最常使用的,贪心法是另一种有意思的算法。贪心法不仅仅是贪婪,而且是每一步都贪婪!下面举例说明。”

1、什么是贪心法

贪心法就是做一种目前最贪婪的行动,一步步解决问题。贪心法和递推法有相似之外,也是从问题的某一个初始解出发,向给定的目标递推,但不同的是每一步不是依据某一个固定的递推式,而是做一个当时看似最佳的贪心选择,不断地将问题归结为更小的相似的问题。

示例:删数问题

链盘输入一个高精度的数N,去掉任意S个数字后剩下的数字按原左右次序组成一个新的正整数,编程对于给定的N和S,寻找一种方案使得剩下的数字组成的新数最小。

为了便于操作,将N做为字符串的形式输入,可以使用尽可能逼近目标的贪心算法来完成,删数的过程中是一个一个进行删除的,为了保证最后得到的数最小,每一步总是要删除使剩下的数最小的数字。之所以做出这样贪心的选择,是因为删S个数字的最优解,包含了删除一个数字的子问题的最优解。

为了实现上述目的,我们可以进行S次选择,每次都选择N中最大的数字,此数字选择后将不再参与下次的选择。

2、小结:

这就是有趣的贪心算法,说是贪得无厌可以,说是守住当前的既得利益,以此为基础,再稳扎稳打地进行下一步也行!

三、滴水不漏——列举法破解难题

问:“列举法是种什么样子的算法呢?”

答:“列举法是比贪心法还要贪得多的算法,列举法也是一种比较笨但却很有效的算法,他想要的东东,一种情况他都不想落下,大有宁可错杀一千,不可放过一个的阵势。下面举例说明。”

1、什么是列举法

列举是针对问题所有的可能一一查看是不是符合条件,有些“宁肯错杀一千,不可放过一个”的作风。下面的老题最能说明这种情况。

示例:百钱买百鸡:公鸡3元每只,母鸡5元每只,小鸡1元3只,一百元钱买一百只鸡。请求出公鸡,母鸡和小鸡的数目。

编程简析

我们做最极端的假设,公鸡可能是0-100,母鸡也可能是0-100,小鸡还可能是0-100,将这三种情况用循环套起来,那就是1000000种情况。这就是列举法。为了将题目再简化一下,我们还可以对上述题目进行一下优化处理:

假设公鸡数为x,母鸡数为y,则小鸡数是100-x-y,也就有了下面的方程式:3*x+5*y+(100-x-y)/3=100从这个方程式中,我们不难看出大体的情况:公鸡最多有33只,最少是没有,即x的范围是0-33;母鸡最多20只,最少0只,即母鸡的范围是0-20;有了公鸡母鸡,小鸡数自然就是100-x-y只。可能的方案一共有34*21种,在这么多的方案中,可能有一种或几种正好符合相等的条件。

电脑怎样工作呢?计算机事实上就是将上述34*21种方案全部过滤一遍,找出符合百钱买百鸡条件的(也即上式),只要符合,这就是我们要的输出结果。

程序实现:我们怎样将这34*21种方案罗列出呢?这么多的方案,最好的办法是还是用循环。可用循环和循环的嵌套,一个关于公鸡数和一个关于母鸡数的循环套起来,就能将所有的方案都遍历。后面的问题成了怎样判断哪一个方案是我们寻找的符合条件和方案呢?只能根据百钱买百鸡了,即3*x+5*y+(100-x-y)/3=100作为条件,在条件成立的一方输出x,y,和100-x-y的值就行了,这是分支要解决的问题,程序的整体结构有了,两个嵌套循环中套分支。

2、小结

这就是列举法,将可能的情况一网打尽;不过在应用过程中,我们最好还是做些优化,不然,要浪费好多没必要浪费的时间。

四、镜里照镜——递归法破解难题

问:“前几种办法的确名如其法,比较笨。有没有比较潇洒一点的算法?递归属不属于些类算法呀?”

答:“递归一种非常奇妙和美妙的算法形式,奇妙美妙的背后是比较难理解。但用起来却异常简洁。”

1、什么是递归

说白了递归就象我们讲的那个故事:山上有座庙,庙里有个老和尚,老和尚在讲故事,它讲的故事是:山上有座庙,庙里有个老和尚,老和尚在讲故事,它讲的故事是:……也就是直接或间接地调用了其自身。就象上面的故事那样,故事中包含了故事本身。因为对自身进行调用,所以需对程序段进行包装,也就出现了函数。

函数的利用是对数学上函数定义的推广,函数的正确运用有利于简化程序,也能使某些问题得到迅速实现。对于代码中功能性较强的、重复执行的或经常要用到的部分,将其功能加以集成,通过一个名称和相应的参数来完成,这就是函数或子程序,使用时只需对其名字进行简单调用就能来完成特定功能。

函数又可分为自定义的和系统附带的,但不管是自定义的还是系统的,他们都对相应的功能进行了封装,以利于我们经常性地使用。例如我们的对一个小数取整数INT()函数,不论什么样的小数,往()中一放,将来得到的值就自动将小数去除了。函数执行完将返回一个值,当然这个值可以是各种类型的,子程序仅仅执行一个过程,不返回数值。

函数和子程序是执行递归的干将。

示例:小猴吃枣:小猴第一天摘下若干枣子,当即吃掉了一半,不过瘾又多吃了一个;第二天吃了剩下的一半又多吃了一个;以后每一天都吃了前一天剩下的一半多一个。到第十天小猴再想吃时,见到只剩下一只枣子了。问第一天这堆枣子有多少?

从上题中我们可看到一个令人欣喜的规律,第十天为1,第一到第九天中后一天与1的和的两倍与前一天相等。

2、小结

相关文档
最新文档