MATLAB程序设计方法及若干程序实例樊双喜(河南大学数学与信息科学学院开封475004)摘要本文通过对MATLAB程序设计中的若干典型问题做简要的分析和总结,并在此基础上着重讨论了有关算法设计、程序的调试与测试、算法与程序的优化以及循环控制等方面的问题.还通过对一些程序实例做具体解析,来方便读者进行编程训练并掌握一些有关MATLAB程序设计方面的基本概念、基本方法以及某些问题的处理技巧等.此外,在文章的最后还给出了几个常用数学方法的算法程序,供读者参考使用.希望能对初学者进行MATLAB编程训练提供一些可供参考的材料,并起到一定的指导和激励作用,进而为MATLAB编程入门打下好的基础.关键字算法设计;程序调试与测试;程序优化;循环控制1算法与程序1.1算法与程序的关系算法被称为程序的灵魂,因此在介绍程序之前应先了解什么是算法.所谓算法就是对特定问题求解步骤的一种描述.对于一个较复杂的计算或是数据处理的问题,通常是先设计出在理论上可行的算法,即程序的操作步骤,然后再按照算法逐步翻译成相应的程序语言,即计算机可识别的语言.所谓程序设计,就是使用在计算机上可执行的程序代码来有效的描述用于解决特定问题算法的过程.简单来说,程序就是指令的集合.结构化程序设计由于采用了模块分化与功能分解,自顶向下,即分而治之的方法,因而可将一个较复杂的问题分解为若干子问题,逐步求精.算法是操作的过程,而程序结构和程序流程则是算法的具体体现.1.2MATLAB语言的特点MATLAB语言简洁紧凑,使用方便灵活,库函数极其丰富,其语法规则与科技人员的思维和书写习惯相近,便于操作.MATLAB程序书写形式自由,利用其丰富的库函数避开繁杂的子程序编程任务,压缩了很多不必要的编程工作.另外,它的语法限制不严格,程序设计自由度大.其昀大的特点是以矩阵运算为昀强,而数值的矩阵化又为运算和处理提供了方便.除此之外,MATLAB还有着非常强大的绘图功能.1.3MATLAB程序设计练习MATLAB有着丰富的库函数,一般情况下应了解并学会使用一些常用的库函数,至少应熟悉函数库中都有哪些常用函数,当需要时可以现学现用.或者能对一些经典函数做一定的改造,以达到解决某一特定问题的目的.但,在大多情况下还需要自己编写程序去处理形形色色的问题.下面就先从一些较简单的程序入手来熟悉MATLAB的编程方式.例1一个分类统计函数的设计(分类统计_1)编写一个函数,统计出一组有序(按升序或降序排列)数字中每种数字的个数,并返回数字种类数.分析:设待统计数组为x,因为x有序,所以在设计算法时应抓住这个特点.若用s1记录已统计出的数字,则,在对x中的数字进行遍历时,每次只需让x(i)与s1中的昀后一个数字进行比较就可以了,若相等,则对应计数器加1,若不等,则说明测到新数,应开辟新的存储单元.其算法程序如下:function[s,k]=FLTJ_1(x)%x为待统计的一组有序数,返回值s为2列的数组,第一列为不同种类的数字%第二列为对应数字的个数,k记录统计出的数字种类数目n=length(x);s1=x(1);%s1记录测到的新数字,给其赋初值为x的第一个数字s2=1;%s2记录s1中每个数字的个数,赋初值为x(1)的初始个数1k=1;%k记录已统计出的数字种类数,初值赋为1fori=2:n%从第2项开始遍历数组xifx(i)==s1(k)%如果x(i)与已测出的昀后1个数字相同,s2(k)=s2(k)+1;%则对应的计数器加1else%否则,则说明测到新数字k=k+1;%k值加1s1=[s1;x(i)];%将此新数并入s1,s2=[s2;1];%对应的计数器为1endends=[s1,s2];%将s1与s2拼接成一个两列的数组s程序运行如下(“↵”代表回车,下同.)x=[1,2,2,3,3,4,5,5];↵[s,k]=FLTJ_1(x)↵s=1122324152k=5例2一个数字游戏的设计有这样一个数字游戏:在一个20×10的矩阵中,0~99这100个数顺序排列在奇数列中(每20个数组成一列),另有100个图案排列在偶数列中,这样每个数字右边就对应一个图案.你任意想一个两位数a,再让a减去它的个位数字与十位数字之和得到一个数b,然后,在上述矩阵的奇数列中找到b,将b右边的图案记在心里,昀后点击指定的按钮,你心里的那个图案将被显示.下面我们就来编写程序模拟一下这个小游戏,以[0,1]之间的小数代替矩阵中的图案,由MATLAB程序实现如下:程序I%“测心术”游戏formatshorta=1;t=0;whileaa1=rand(100,1);k=3;s=[];whilek=10a1(9*k+1)=a1(19);k=k+1;enda2=reshape(a1,20,5);a3=reshape(99:-1:0,20,5);fori=1:5s=[s,a3(:,i),a2(:,i)];%生成矩阵endif~tdisp('//任意想一个两位数a,然后将这个两位数减去它的个位数字与十位数字之和,');disp('//得到数字b,再在下面矩阵的奇数列中找到b,昀后记住其右边对应的小数c');pause(10);t=t+1;enddisp('');disp(s);pause(5);disp('');d=input('//确定你已经完成计算并记下了那个小数,摁‘Enter’键呈现此数字\n');disp(s(19,2));pause(3);disp('');a=input('//‘Enter’退出;=‘1’再试一次\n');end使用说明:运行程序I生成一个20×10的矩阵s,你任意想一个两位数a,按照上面所说的步骤操作,然后在s的奇数列中找到b,将b右边的小数记在心里,再调用程序II,则返回你所记下的那个小数.(运行演示略)原理说明:设任意一个两位数a=10+,则a-(+)=9=b,所以b一定是9的倍数,且只可能在9到81之间.明白了这一点,上面程序中的各种设置就一目了然了.1k2k1k2k1k例3折半查找算法要从一个数组x中找到一个指定的数a,通常的做法是从x的第一个数开始顺序查找.如果x是一个无序的数组,的确没有比顺序查找更好的方法了,但如果x有序,设计查找算法时就要充分利用这已有的规律,折半查找就是针对有序数组进行查找的一种效率较高的方法.对于一个维数组,折半查找昀多比较次数为,而顺序查找的平均比较次数为.n2log1n+⎢⎥⎣⎦/2n写一个算法:在数组x中查找数字a,其中x是一个元素各异并按升序排列的一维数组.若找到a,则返回a在x中的位置,若a不在x中则返回“找不到”.折半查找算法程序如下:functions=BinarySearch(x,a)%折半查找法,x是按升序排列的一维数组,a是待查找的数字n=length(x);sign=0;%用sign标记是否查找成功,赋初值为假,当查找成功时其值为真top=1;bott=n;%查找区间端点下标,top为“顶”,bott为“底”ifax(1)|ax(n)%当a比x的昀小值小或比x的昀大值大时,返回找不到此数,s='Thenumberisnotfound';%并终止程序,否则在x的内部查找areturn;elsewhile((sign==0)&(top=bott))mid=fix((bott+top)/2);%求中位数并取整ifa==x(mid)%若找到as=mid;%记录它在x中的下标,sign=1;%并置标志变量为真elseifax(mid)%否则,改变区间端点下标bott=mid-1;elsetop=mid+1;endendifsign==0%当sign为假,说明在x中找不到as='Thenumberisnotfound';endend运行情况如下:x=[1346891215];↵s=BinarySearch(x,6)↵s=4s=BinarySearch(x,7)↵s=Thenumberisnotfound例4对答卷中选择题的初步统计函数当做完一项问卷调查后,或举行完一次考试后,在对答卷中选择题的做答情况做统计分析时,需要知道每个选择题中每个选项的被选次数及所占的百分比.现假设选择题只有4个选项(A,B,C,D),某些题目允许多选,但不得选多于2项.(如果题目的选项或可选项增加的话,方法类似.)4个选项分别用1,2,3,4表示(若选择AB,则表示为12),缺选时用0表示.请编程序统计每个题目中每个选项的被选次数及所占的百分比.分析:若一共有n个题目,可用两个4×n的矩阵分别表示每个选项的被选次数与所占的百分比,在统计的过程中用数组分别为每个题目中的每个选项计数.MATLAB程序如下:function[s1,s2]=TongJi1(A)%A为答卷结果的数据,返回值s1,s2分别为每个%选项的被选次数与所占的百分比[m,n]=size(A);s1=[];s2=[];D=ones(1,n).*m;%D记录每个题目中每个选项被选次数总和,%给每个元素赋初值为mforj=1:nB=zeros(4,1);%B为计数器,记录每个题目中的每个选项的被选次数fori=1:mt=A(i,j);ift==0%缺选时,在该题的总数记录中减1D(j)=D(j)-1;elseift10%只选一项时,在该项的计数器上加1B(t)=B(t)+1;else%当选两项时,需分离数字,再让每项的计数器加1,%同时该题目的各项被选次数总和加1t1=floor(t/10);t2=t-t1*10;B(t1)=B(t1)+1;B(t2)=B(t2)+1;D(j)=D(j)+1;endends1=[s1,B];%组合矩阵B1=B./D(j);%求百分比s2=[s2,B1];end附录中表1是一个有20个学生作答记录的数据,若记该数据矩阵为A,调用上面的程序运行如下:?[s1,s2]=TongJi1(A)↵s1=3800200285571217444572137842953555s2=0.15790.4211000.1053000.10530.42110.26320.26320.36840.63160.05260.36840.21050.21050.21050.26320.36840.10530.68420.36840.42110.21050.10530.47370.26320.15790.26320.26320.2632例5列主元Gauss消去法解方程组列主元Gauss消去法是指在解方程组时,未知数顺序消去,在要消去的那个未知数的系数中找按模昀大者作为主元.完成消元后,系数矩阵化为上三角形,然后在逐步回代求解未知数.列主元Gauss消去法是在综合考虑运算量与舍人误差控制的情况下一种较为理想的算法.其算法描述如下:1.输入系数矩阵A,右端项b2.测A的阶数n,对k=1,2,…,n-1循环a)按列主元maxikkinaα≤≤=保存主元所在行的指标.kib)若0α=,则系数矩阵奇异,返回出错信息,计算停止;否则,顺序进行.c)若则转向d);否则kik=换行,…,n,1kijkjaajk↔=+1+kikbb↔d)计算乘子,…,/,ikikkkmaaik==ne)消元:,,1,ijijikikaamaijk=−=+…,n,1,iiikkbbmbik=−=+…,n3.回代1/,niiijjiijibbaba=−⎛⎞=−⎜⎟⎝⎠∑,1,nin−…,1=方程组的解X存放在右端项b中.MATLAB程序如下:functions=LZYgauss(A,b)%列主元高斯消去法解方程组:A为系数矩阵,b为右端项n=length(A(:,1));%测量A一行的长度,得出nfork=1:n-1%循环,消元[a,t]=max(abs(A(k:n,k)));%寻找昀大值(记为a)p=t+k-1;%昀大值所在的行记为pifa==0%若a=0,则A为奇异阵,返回出错信息error(‘Aisabizarrematrix’);else%若a不等于0,换行t1=A(k,:);A(k,:)=A(p,: