易语言常用算法设计图书.docx
- 文档编号:30034031
- 上传时间:2023-08-04
- 格式:DOCX
- 页数:16
- 大小:71.86KB
易语言常用算法设计图书.docx
《易语言常用算法设计图书.docx》由会员分享,可在线阅读,更多相关《易语言常用算法设计图书.docx(16页珍藏版)》请在冰豆网上搜索。
易语言常用算法设计图书
常用算法设计
概括地说,“算法”是指解题方案的准确而完整的描述。
对于一个问题,如果可以通过一个计算机程序,在有限的存储空间内进行有限长的时间而得到正确的结果,则称该问题是算法可解的。
但算法不等于程序,也不等于计算方法。
程序可以作为算法的一种描述,但程序通常还需考虑很多与方法和分析无关的细节问题,这是因为在编写程序时要受到计算机系统运行环境的限制。
通常,程序设计的质量不可能优于算法的设计。
通常求解一个问题可能会有多种算法可供选择,选择的主要标准是算法的正确性和可靠性,简单性和易理解性。
其次是算法所需要的存储空间少和执行更快等。
算法设计是一件非常困难的工作,经常采用的算法设计技术主要有列举法、递推法、贪婪法、回溯法、分治法、动态规划法等等。
另外,为了更简洁的形式设计和藐视算法,在算法设计时又常常采用递归技术,用递归描述算法。
1.列举法(穷举)
列举法的基本思想是根据提出的问题,列举所有可能情况,并用问题中提出的条件检验哪些是需要的,哪些是不需要的。
因此,列举法常用于解决“是否存在”或“有多少种可能”等类型的问题。
例如,求解不定方程的问题可以采用列举法。
列举法的特点是算法比较简单,但当列举的可能情况较多时,执行列举算法的工作量将会很大。
因此,在用列举法设计算法时,应该重点注意使方案优化,尽量减少运算工作量。
通常,只要对实际问题作详细的分析,将与问题有关的知识条理化、完备化、系统化,从中找出规律,或对所有可能的情况进行分类,引出一些有用的信息,列举量是可以减少的
先介绍“列举法”在易语言中实现的方法。
列举法,顾名思义是列举出所有可能的情况,并用问题的条件来一一检验,并从中找出符合要求的解。
特点比较简单,但是在写列举算法时尽量过滤掉一些不必要的情况,优化算法。
下面举一个例子,在易语言中编写代码实现,来说明列举法的基本思想,以及如何减少列举量。
大家都知道百鸡的问题吧!
母鸡每只3元,公鸡每只2元,小鸡每只0.5元,计算一下如何100块钱买100只鸡。
计算中,只有以下两个条件成立,才输出结果。
母鸡数量+公鸡数量+小鸡数量=100只
3X母鸡数量+2X公鸡数量+0.5X小鸡数量=100元
列举所有可能的条件的代码如下:
可以看到,各层循环均需循环101次,因此总循环次数为1013,列举量太大。
但只对问题稍加分析,很容易发现这个算法还可以改进,减少不必要的循环次数。
首先,考虑到母鸡为3元一只,因此,最多只能买33只母鸡,即算法中的外循环只需要从0到33就可以了,没有必要从0到100。
其次,考虑到公鸡为2元一只,因此,最多只能买50只公鸡。
又考虑到对公鸡的列举是在算法的第二层循环中,因此,在第一层循环中已确定买母鸡数量的情况下,公鸡最多只能买50-母鸡数量,即第二层中对“公鸡”只需要从0到50-母鸡数量就可以了。
最后,考虑到总共买100只鸡,因此,在第一层循环中已确定买母鸡的数量,
且第二层已确定买公鸡的情况下,买小鸡的数量只能是100-母鸡数量-公鸡数量,
+公鸡数量
即第三层的循环已没有必要了。
并且,在这种情况下,条件:
母鸡数量
+小鸡数量=100只自然已经满足
优化后的代码如下丄一
■:
…变量循环首⑪50-母魂I.餉軸
列举(穷举)所有可能情形,最直观的是联系循环的算法。
但,循环层数的;:
.---3D果真(3址母鸿+2乂公鸭*0.5乂出鸡=100)
改变,就影响了这一问题的解,即即没有一般性。
例如:
有多种鸡,而每种鸡的价格又不同,每次根据一个固定的金额购买某几种鸡。
養量循环屋0
程序名称:
1列举法-百鸡.e
2.递推法
所谓递推,是指从已知的初始条件出发,逐次推出所要求的各中间结果和最
后结果。
其中初始条件或是问题本身已经给定,或是通过对问题的分析与化简后确定。
递推本质上也属于归纳法。
许多递推公式,实际上是通过对实际问题的分析与归纳而得到的,因此,递推是归纳的结果。
也就是利用问题本身所具有的一种递推关系求问题解的一种方法。
设要求问
题规模为N的解,当N=1时,解或者已知,或者能非常方便地得到解。
能采用递推法构造算法的问题有重要的递推性质,即当得到问题规模为i-1的解后,由问
题的递推性质,能从已求得的规模为1,2,…,i-1的一系列解,构造出问题规
模为|的解。
这样,程序可从i=0或i=1出发,重复地,由已知至i-1规模的解,通过递推,获得规模为i的解,直至得到规模为N的解。
递推法中最具代表的就是阶乘法,下面采用分段乘法进行大数求阶乘。
在计算阶乘的时候,随着数字的增加,计算的结果会以极快的速度激增。
当
使用整数型数据储存结果时,当超过12时,计算结果将溢出;当使用长整数型数
据储存结果时,当超过20时,计算结果将溢出。
为了能够计算较大的整数的阶乘并得到准确的结果,必须考虑适当的算法,分段乘法是其中的一种,将每一步的中间结果使用数组分段储存,数组的一个成员储存一段数据,由于我们经常使用的是10进制,因此以10的n次方为标准进行分段是可行的。
同时需要考虑分组相乘时,每组是否会出现溢出,因此数组的类型采用长整数型。
这里采用该算法写了一个模块,循环和数组配合,虽然能计算出正确的结果,但速度较慢,计算10000的阶乘需要50秒(最快的在1秒左右,大家可以使用Windows的计算器试试),计算50000的阶乘,耗时24分钟,估计不会有人尝试计算更大的数值。
分段相乘完毕后还要考虑每组的数值是否超过分段的标准,如果超过要进位。
代码参见例程。
例程名称:
2递推阶乘.e
3.递归算法描述递归定义的函数或求解递归问题的过程称为递归算法。
一个递归算法,本质上是将较复杂的处理归结为较简单的处理,直到最简单的处理。
因此,递归的基础也是归纳。
下面学习易语言中递归算法的运用。
在易语言中许多地方可以用到递归算法,典型特征是自己调用自己。
逐步到达条件边界,直到目的完成,如:
“寻找文件()”等,递归算法结构比较简练,清晰易读,但,缺点是执行效率比较抵。
下面来练习寻找的的写法。
首先需要作一个单独的寻找子程序,如:
名字取为“寻找”,参数为“寻找路
径”文本型
由于“寻找文件()”命令很特殊,好多初学者不好理解,因为寻找文件每次只返回一个匹配对象,所以一定要用循环才可以找到所有的匹配条件者,而第一次使用寻找到一个匹配条件者,再继续寻找其他文件就不需要指定寻找文件条件了。
代码可分为三部分,代码如下:
第一部分,判断指定“寻找路径”参数右边是否带“”,如果不带,就自动
加上。
第二部分是关键代码,首先调用
文件名=寻找文件(寻找路径+“*.tmp”,)
因为只返回一个文本,所以用一个判断循环,判断“文件名”是否为空,如
果不空继续寻找,否者……
这部分只寻找一个目录里所有匹配者,不会寻找里面文件夹里的匹配者,当然不能放过它们,下面的代码就是:
第三部分是递归算法,等于子程序调用自己寻找(寻找路径+文件名)
就是这句,你也许会问
如果真(取文本左边(文件名,1)工“•”)
是什么意思,其实就是判断文件名是不是文件夹,再XP命令提示符输入“dir
一看就知道了。
“.”是本级目录,“..”是上一级目录。
一定不要忘了在这个子程序里面加上处理事件()否则运行后机器会假死。
下面是另一个运用递归算法求最大公约数的例程,核心部分只用了6行代码,代码如下:
注意:
%是求余数的运算符,不是除号,也不是百分号。
此例中求最大公约数,没有使用常用的短除算法,使用辗转相除法更便于编程。
程序名称:
3.1递归算法.e
3.2递归算法.e
4.归纳法
了解算法的目的是提高大家的编程思路,优化编写代码的质量。
前面讲解过列举算法,它具有结构简单的优点,但是又有2个缺点:
一是数据量大时效率低,二是当列举量无限时,列举算法就无效了。
下面学习一下归纳法。
简单的说,就是列举少量的特殊情况,分析找出一般的关系,但是实际问题中不是件容易的事。
归纳即为抽象,对结果只是一种猜测(即归纳假象),所以必须严格的证明结果。
下面介绍一个典型的归纳法例子。
求n个自然数的平方之和。
Sn=12+22+32+…+n2
分析:
S1=12=1
S2=12+22=5
S3=12+22+32=14
S4=12+22+32+42=30
S5=12+22+32+42+52=55
S6=12+22+32+42+52+62=91
通过上速几个值,分析得出Sn与n之间的关系,
12/1=(2*1+1)/3//1=1
(12+22)/(1+2)=(2*2+1)/3//5/3=5/3
(12+22+32)/(1+2+3)=(2*3+1)/3//14/6=7/3
(12+22+32+42)/(1+2+3+4)=(2*4+1)/3//30/10=9/3
(12+22+32+...+n2)/(1+2+3+...+n)=(2n+1)/3
因为:
(1+2+3+...+n)=n*(n+1)/2
所以:
12+22+32+...+n2=n*(n+1)(2n+1)/6
这些都是数学公式换算,应该可以理解。
结果出来了。
请看易语言代码,代码如下:
由于数据的最大尺寸限制,再大就不准确了。
5.排序算法
5.1查找运算
顺序表上的查找运算有很多种。
如顺序查找法、二分法、分块查找法等。
我们先来介绍顺序查找法。
顺序查找法,就是在表中顺序对比节点和欲查找数据的值,相同则返回相应的位置值。
其过程,就是对表的顺序扫描。
这是一种方法简单,但效率不高的查找方式。
代码如下:
5.2对分(二分)查找
对分(二分)查找又称折半查找,它是一种效率高的查找方法。
对分(二分)查找的基本思想是:
1.首先确定该区的中点位置;
2.然后将待查的值与中间值进行比较,若相等,则查找成功并返回此位置,否则须确定新的查找区间,继续二分查找,具体方法如下:
(1)若中间值大于待查的值,则由表的有序性可知,中间值右表中的值均大于待查值,因此若表中存在等于待查值的值,则该值必定是在中间值左边的子表中,故新的查找区是左子表。
(2)类似地,若中间值小于待查值,则要查找的值必在中间值的右子表中,即新的查找区间是右子表。
下一次查找是针对新的查找区间进行的。
因此,从初始的查找区间开始,每经过一次与当前查找区间的中点位置上的节点的比较,就确定是否成功,不成功则当前的查找区间就缩小一半。
这一过程重复直至找到中间值的值,或者直至当前的查找区间为空(即查找失败)时为止。
数据越多越能体现对分查找法的好处。
其实,每次插入都是比较大小安排插入位置,为了插到大于和小于数值的中间。
如4、6、8、50、55、59,如果给一个56,当然知道插入到55后面,以前的代码是从4开始一一比较,而我们可以直接把数组对分,比一下是比前一部分大,还是比后一部分大,再在剩余结果对分比较,再对分……。
逐一比较平面需要比较5次,对分只需要比较2次,数据越多,越能体现。
代码如下:
5.3冒泡排序
冒泡排序是最简单也是最经典的。
这种方法的基本思想是,将待排序的元素看作是竖着排列的“气泡”,较小的元素比较轻,从而要往上浮(相反,较大的元素比较重,从而要往下沉)。
在冒泡排序算法中我们要对这个“气泡”序列处理若干遍。
所谓一遍处理,就是自底向上检查一遍这个序列,并同时注意两个相邻的元素的须序是否正确。
如果发现两个相邻元素的须序不对,即“轻”的元素在下面,就交换它们的位置。
显然,处理一遍之后,“最轻”的元素就浮到了最高位置(或最重的元素沉到最低位置);处理两遍之后,“次轻”的元素就浮到了次高位置。
在第二遍处理时,由于最高位置上的元素已是“最轻”元素,所以不必检查。
一般地,第i遍处理时,不需检查第i高位置以上的元素,因为经过前面i-1遍的处理,它们已正确地排好序了。
关键在于每循环一遍都记录交换的次数,避免下次不必要的比较,还要记住最后交换的位置,这个位置以后的数据下次可以在之前比较。
比如现在有一组数据,第一次先比较所有的数据,而后记下最后比较位,而每次如果有数据交换,就继续循环比较。
而比较的最后位置则是循环的最大值。
代码如下:
5.4插值排序
1.直接插值排序直接插入排序的基本思想是:
每次把一个待排序的节点,按其关键字的大小插入到前面已排序好节点中,直到全部节点插入完毕。
两个重要概念。
有序区:
是指顺序表中已排序好的部分。
无序区:
即表中未进行排序的区域。
例如,一维数组[2,5,6,2,9,5,47]有序区的范围是:
【1,3】(从1到3节点),无序区是:
【4,7】(从4到7节点)。
对于任何一个节点为n
(n>1)的顺序表,其初始有序区的范围是【1,1】无序区的范围是【2,n】。
插入
排序的基本思想就是不断增大有序区,减小无序。
直到无序区消失。
直接插入排序的原理:
每次将无序区的第一个节点插入到有序区中。
例如,无序数组[8,5,6,4,3,9,4],其初始有序区【1,1】,无序区【2,7】。
第一次插入运算,将无序区第一个节点“5”插到前面的有序区中。
运算后数组为[5,8,6,4,3,9,4],有序区为【1,2】无序区为【3,7】。
第二次插入运算,将
无序区的第一个节点“6”插入到前面的有序区中,运算后的数组为[5,6,8,4,3,9,4],其有序区为【1,3】,无序区减小成【4,7】。
如此重复,经过6次插入运算,有序区成为【1,7】,无序区消失。
此数组成为有序数组。
代码如下:
本段代码用到了查找算法和插入算法。
直接插入排序法的代码在执行过程中,大部分时间是消耗在查找插入点位置和移动节点上。
节点的移动是必须的,此类算法是无法减少移动次数的,除非是用新的算法。
而每次都从无序区首(即表的第一个节点)开始寻找插入点的过程是完全没有必要的,可以用我们讲过的二分查找法优化此过程。
以下是实现代码。
上面对直接插入排序进行了优化,我们暂且把优化算法称为二分直接插入排序,这种算法仅仅是对寻找插入点的过程做了优化。
如果我们能找到另一种方法,可同时减少寻找插入点的次数和移动节点的次数,就可显着的提高排序的运算速度。
以下介绍的希尔排序算法是直接插入排序法的一种变种,它能有效的减少这两个方面的运算量,从而显着的提高排序操作的运算速度。
原理:
先取一个小于节点数的整数k作为分组单位,把表上的所有相距k的节点逻辑上看成一组。
在个组内进行直接插入排序;减小k的取值,把表上的所有相距k的节点逻辑上看成一组。
在个组内进行直接插入排序;重复以上步骤;最后
一次k取1,即对整个表做直接插入排序
增量表我们取成“5,3,
其中k称为增量,增量的取值集合称为增量表例,无序数组[4,5,8,2,6,8,9,2,4,5,1,6,1,5,4,2]1”(k的取值集合)。
2,7,12】【3,
(1)当k=5时,表上的逻辑分组情况为:
【1,6,11o16】
直接插入排序过程为:
[1,5,8,2,6,2,9,2,4,5,4,6,1,5,4,8]
[1,5,8,2,6,2,6,2,4,5,4,9,1,5,4,8]
[1,5,1,2,6,2,6,2,4,5,4,9,8,5,4,8]
[1,5,1,2,6,2,6,2,4,5,4,9,8,5,4,8]
[1,5,1,2,4,2,6,2,4,5,4,9,8,5,6,8]
此次运算后数组为[1,5,1,2,4,2,6,2,4,5,4,9,8,5,6,8]
k=3时组内进行直
11,14】【3,6,9,12,15】(【】内均是数组的下标值)接插入排序过程为:
第一组:
数组成员分别为“1”,“2”,“6”,“5”,“8”,“8”
排序后的数组[1,5,1,2,4,2,5,2,4,6,4,9,8,5,6,8]第二组:
数组成员分别为“5”,“4”,“2”,“4”,“6”
排序后的数组[1,2,1,2,4,2,5,4,4,6,5,9,8,6,6,8]第三组:
数组成员分别为“1”,“2”,“4”,“9”,“6”
排序后的数组[1,2,1,2,6,2,6,2,4,5,4,6,8,5,9,8]此次运算后数组为[1,2,1,2,6,2,6,2,4,5,4,6,8,5,9,8]
(3)当k=1时,表上的逻辑分组情况为:
【1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16】(【】内均是数组的下标值)。
即整个表分为一个组,此时对整个表做直接插入表排序,可以发现此次运算时节点移动是非常少的。
此次运算后数组为有序数组。
通过以上详细的运算过程描述,我们可以发现:
当k值很大时,组很小,查找和移动量都很小,随着k值增大,组虽然增大,查找运算量增大了,但最耗时间的移动节点运算量却在减小。
总的排序运算耗时是显着的减小,效率成倍提高。
代码如下:
2.线表插值排序
在易语言中,一维数组上插入一个数据可以直接调用“插入成员(欲插入成员的数组变量,欲插入的位置,欲插入的成员数据)”系统命令。
我们来研究它是怎么实现的。
原理很简单,当向一维数组的第i个位置插入一个数据时,第i个位置及它以后的数据依次都向后移动,将第i个位置腾出来后,把所要插入的数据写入该位置。
具体的实现步骤如下:
(1)首先增加数组的长度。
在易语言中可以用“加入成员()”和“重定义数
组()”两种方法。
前者可能更快些。
(2)移动数据。
不破坏数据,当然是从数组的最后位置向前移动了。
可设一
个位置变量“数据位置”指向最后位置。
“数组”是定义的一维数组。
“数组[数
据位置]”,就是我们插入数组尾部的空数据。
数组[数据位置]=数组[数据位置-1]
把数组的倒数第二个数据移到尾部。
然后
数据位置=数据位置-1
“数据位置”指向数组的倒数第二个数据,
数组[数据位置]=数据[数据位置-1]
把数组的倒数第三个数据移到数组的倒数第二个位置上,……依次移动,
最后把数组的第i个位置上的数据移到i+1的位置上。
(3)把需要插入的数据插入到“数组[i]”。
代码如下:
3.数组插值排序
随机生成数字或文本。
按从大到小或从小到大排序。
现在我们用数组排序。
如果是数值可以用数组的“数组排序(,)”。
代码如
下:
上面的代码比较简短,但是在某些时候,比如多项排序,就不好控制了,多位数组动态加入会自动变成单维的。
下面是排序的标准写法,当然只是个框架,代码如下:
上面只是数值排序,大家可以练习一下文本、时间、逻辑
5.5删除运算
在易语言中,一维数组中数据(节点)在逻辑上是顺序相连的,并且它们在计算机中内存中也是顺序存储的,我们一般称顺序存储的线性表为顺序表。
注意,顺序表是从存储方式上来描述表结构的;线性表则是从逻辑上描述表结构的。
表结构从逻辑上可分为线性表和非线性表。
线性表和非线性表都可以用两种方式存储,即顺序存储(如数组),和链式存储。
表的链式存储方式需要指针。
在易语言中顺序表是建立在一维数组基础上的表结构。
本节讲述顺序表上的删除运算:
后面的
删除运算也是通过移动节点来完成的。
删除i节点时,我们只要把i节点依次向前移动。
在一维数组中把欲删除的位置后面的数据依次前移,把最后位置的数组成员删除,便完成了此运算。
只有删除最后位置上的数据时不需要移动数据,直接删除该成员。
代码如下:
例程名称:
5.5删除运算.e
6.贪婪算法
贪婪法是一种不追求最优解,只希望得到较为满意解的方法。
贪婪法一般可以快速得到满意的解,因为它省去了为找最优解要穷尽所有可能而必须耗费的大量时间。
贪婪法常以当前情况为基础作最优选择,而不考虑各种可能的整体情况。
例如平时购物找钱时,为使找回的零钱的硬币数最少,不考虑找零钱的所有各种方案,而是从最大面值的币种开始,按递减的顺序考虑各币种,先尽量用大面值的币种,当不足大面值币种的金额时才去考虑下一种较小面值的币种。
这就是贪婪法。
面我们一起练习一个装箱子问题在易语言中的求解
设有6种物品,它们的体积分别为:
60、45、35、20、20和20单位体积,箱子的容积为100个单位体积。
按上述算法计算,需三只箱子,各箱子所装物品分别为:
第一只箱子装物品1、3;第二只箱子装物品2、4、5;第三只箱子装物品6。
注意:
贪婪算法的解不是最优解而最优解是2个箱子:
第一只箱
1\4\5(60,20,20)第二只箱2\3\6(45,35,20)。
分析:
我们可以作成通用型的,其实就是一个判断循环嵌套一个计次循环。
在数据放入箱子之前先把数据从大到小排列一下,接着取一个最大数据先放
入箱子中,后面的数据依次与它相加比较,和小于箱子体积,加入到箱子中,原数据减一个,大于则继续向后比较。
到原数据尾后,一个箱子完成合理的数据匹配。
再从头开始装下一个箱子。
注意易语言中各变量的赋值和清空。
下面是易语言中的算法框架,代码如下:
7.其它例程
7.1猫吃老鼠问题
现有n个老鼠围成一圆圈,有一只猫从任意位置开始吃老鼠,每次都隔一个
老鼠吃,请给出最后一个老鼠的编号?
题目要求是任给老鼠数n,输出猫最后吃的
老鼠的编号。
我们假设老鼠按顺时针方向编号,猫从第一号老鼠开始吃。
比如现有4个老鼠围成一个圆,则猫吃老鼠的顺序应该为1->3->2->4,即最后一个吃的老鼠的编号是4。
例程名称:
7.1.1猫吃老鼠.e
7.1.2猫吃老鼠.e
7.2将一个整数的各个位分解并相加如的和。
代码如下:
7.3计算序列(样本)相关系数模块
程序中调用:
计算相关系数(序列,序列距平,相关系数)序列:
输入的样本数据,多维样本序列距平、相关系数为输出结果,序列距平、相关系数是对应序列的多维数
组,假设序列(3,20)对应序列距平(3,20)、相关系数(3,3)数理统计学基本概念,经常会碰到计算相关系数,有些行业软件(如财经分析、彩票预测等)一些分析预测类软件会经常用到。
还有矩阵的特征值和特征向量等。
例程名称:
7.3计算序列相关系数模块.e
7.4连连看核心算法连连看的基本游戏规则是可消除最多三条直线连通的两块。
因此可以把问题
分解为:
单线连通,双线连通和三线连通。
单线连通比较好理解,检查起始横(纵)坐标到终止横(纵)坐标畅通即可。
双线连通其实是两个单线连通。
比如判断块A(横A,纵A)与块B(横B,纵
B)是否双线连通,那么只要分别判断块A->(横A,纵B)—>块B及块A->
(横B,纵A)->块B的连通性即可。
A'(横A,纵B)—》块B(横B,纵B)
/|\/|\
||
A(横A,纵A)>A''(横B,纵A)
三线连通让不少朋友感到无从下手,主要是块A到块B中间有六种通路模式,大家可以自己画图看看是那六种模式,如果用代码来写实在是恐怖。
我们同样可以把它化简为一个单线连通和一个双线连通。
块A有上下左右四个方向,分
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 常用 算法 设计 图书