资源描述
001绪论撤据辖构和專倣緒枪什么是数据朿斷数据结构是一门研疣非数值计算的程厚设计问題中的操作对象,以及它们之诃的关糸和操作等相关问题的学科。这样的骨方陈词不是小甲鱼的凤格哈,如果是小甲鱼,会告诉你数据结构事实上就是这样子:-程序设计=教据结构+算去一再简单的采说救据结构就是关条,没错,就是数出元素相互之间存在的1种或多科特定关系的集看6鑿璧1严揖辖构和扬理辖构.爹iw件统上,我们把数据结构分为逻辑结构和场理结O逻辑结构:是指救据对象中救据元素之问的相互关系,也是我们今后最需要关注和讨论的问题。扬理结构:是指数据的邃辑结构在针算机中的存儲形式。好,那社小甲鱼图丈并茂地给丸家介绍下田大谡辑鉛构吧:(此戎可以有拳唐丿W集金籍枸班姑妁:藤金轴相中的致松比就橋丁冋禹子-介系金尹卜.咗:虫JW可也1冇我任不三不E硝其客7钱徃穡构线性结构:魏性结构中的数据元*之问是一对一的关紀树形猶构树形结枸:衲形结枸中的itifi元索之间存坯一科一对多的层次关系(像3p.4p等丿形转构图形结构;囲形结构的数摒元素是多对多的关*。物理穡枸说完逻辑结构,我们再来说说数据的物理结构。根据物理结构的定义,我们卖际上研兗的的就是如何把数据元素存儲列计算机的存储器中。存储翠主要是针对内存而言的,像硬盘、软盘、光盘等外部存赭器的数据组织通常用文件结构来描述。数据元素的存赭结构形式有两种:顺序存储和链式存储。W噸為鬲储转构顺序存储结构:是把数据元素存放在地址连续的存储单元里,其数据问的送辑关糸和物理关糸是一致的。例如我们编程语言的数组结构就是这样满。仔寻汙4号w铤式鬲储秸构从顺序存储结构我们想到了目常生活中我们的排队,有木有?但现卖生活中,我们发觉也并不完如此O例如有人排着排着她内急,她要彼迫离开队伍去上冼手间,还有人不連寺基本基本道德规范他插队,这些情况会大玻存伪存储结构的基本原则。面对这样时常要变化的结构,顺序存储是不科学的,那么就技让链式右儲结构疣而了。r现在如银行、医院等地方,都设置了排队糸统。也就是毎个人去了,先领一个号,等着叫号,叫到你的对候就可以去存一百块给小甲鱼或看病。而在等待的时候,你爰衣哪在哪,可以坐着、站着或者四处看看美眉,只要你及时回来就行。这些情况下,你关注的是前一个号有没有彼叫列,叫到了,下一个就该轮到你了。链式存储结构就是这样的原理,相此起顺序存俺;结构就灵涪多了。s链式存緖结构:是把数据元素存放蛊任意的存赭单元里这组存赭单元可以是医续的.也I可以是不的o很显然,这样说的话链式存儲结构的数据元素存緖关糸幷不能反腆其逻辑关糸,因此需要用一个指针存放敦摒元素的地址,这样子通过地址就可以找到相关朕数据元素的住置。Nopictureyousayaj8_丄2号If7号4号6号5号縫式為储穡枸002谈谈算法事卖上,数据结构和算法也有类很的关条。只挟数据结构我们可以農很短的肘间囱就把几科重要的数据结构介绍屯。不过听克忌,你可能没啥感觉,不知道这些教据结构有啥用处.但如果我们把扌6J应的算蛙结合起来讲一诜$擴示一b下你就会发现,总至开始感概:0,原来小甲鱼以及计算机界的侖辈们的确是一些很牛很年的人,他们的工作後很多看似很难解决的问题变得如此尊嫌和神奇A。、/算他初俸验小学学过珠算的鱼诂应技很有印象,每夭加法运算敲得手指都快断了就算那1+2+99+100。这会儿,小甲鱼就给丸彖介绍一个有关也是有关从1加到100的小故事作为开端吧!很久很久很久以前有部分询毛的鱼油可能不屑一顾切,我们刚开始学习小甲鱼你的零基础入门学习C语言的肘候,早就教过我们用C来写1加到100的代码略那时候祢还说咱计算机的速度是何其快啊!二我们这门课程叫”數据结构和算法”,有鱼油可能会问这不是两门课程呢?为什么整庄一起讲解呢?不是後增我们的脛想负担吗?殘油,这看来小甲鱼是有必要跟大象鮮猝一下数据结枸和算出的关纟啦。柑个比方,其卖数据结构和算垃的关案就比好基友是一辈子的关系口他们患难见箕情,他们生死不相弄,他们条辱电共,他们一生情一辈予*尊倣刼俸验intijsum=0n二166;for(i=l;i=n;i+)sum=sum+i;printf(%d,sum);对比下,用搞死先生的尊法,我们可以这么写:intijsum二0门=109;sum=(l+n)*n/2;*printffV.sum);尊该初俸验可能以计算机的神速,两个算去都可以秒杀解决掉!但是,如果我们杷条件换成1加到1千万,或者丄加fjl-f亿,爰距就可想而知了,芯至人脑都可以比色脑计算得快了。那么什么是算法呢?-算冻是解决特定问題求鮮步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。一懵了吧?用小甲鱼的话来讲,算由就是你泡奴丿枣歼技巧和方式。、f篇注初條验从刚才的例子中我们看到,对于给定的问题,是可以有多种算法来鮮决的。这就像追女孩子,总不可能每个人追女孩子的方式都一样吧?举个例子,小甲鱼當常衣街上看到很多美眉,但旁边都是挽着条件十分一般的男朋发。这时候,小甲鱼就会由袤的佩服该男同胞一定是用了特别牛掰的算法追列美眉的!就像没有药可以包治百病一样,一个问题可以由多个算冻鮮决,一个算法也不可能具有通鮮所有问题的能力。、刁/考虑到夬部分学习小甲鱼数据结构和算法的鱼油都是学生,都要对付各种考试和考核。,注意,小甲鱼这里用了“对付”而不是“应付”,虽然是填鸭式教育,但是,如果我们能从中学到有用的知识并且可以对付考试,是最好的!*所以小甲鱼这个糸列的视频教程也是针对性的要把经常考试的概念提一提说一说淡一淡侃一侃。嗯,算去具有五个基本特征:输入、输出.有號性、硝金性和可行柱。匚输入-算法具有零个或多个输入。-尽管对于绝大多教算法来说,输入参数都是必要的o但是有些肘候,像村印UI,就不需要啥参总啦。voidprint()printf(nIn);输出一算法至少有一个或多个输出。-算余是一楚要输出的,不需要它输出,那你要这个舜由来干啥?输岀的形式可以是4r印形无输出,迄可以是返回一个值或多个值等0有穷性一指算出莊执行有限的步骤之后,勺动结束而不会出现无限循环,并且每一个步骤壮可接受的财间内老成。一个永迄都不会结耒的算脇.我们还要他矢干、於?m确定性-算曲的每一个步骡都具有确定的舍义,不会出现二义性。-算法在一定条件下.只有一条执行路徑,相同的输入只能有唯一的输岀结崇。-算法的每个步骤都应该菠精确是义而无吱义。-可行性-算廉的每一步都她须是可行的,也就是说,每一步都能够通过执行有限次数老成。对上们解决问题很有帮助!正确性-算去的正确性是指算法至少反该具有输入、输出,加工处理无歧义性能正确及映问題的需求、能得到问題的正确答秦。大体分为以下曲个层次:算城程序没有语城错谍。算沽程序对于合烘输入能够产生满足要求的输出。算曲程序对于韭曲输入能够产生满足规格的说朗。算烘程序对于故意刁难的测试输入都有满足要亲W输出结果口、今时间放率高和存儲量低一生活中,毎个男人都希璽找一个贤惠的老婆.她们温柔又体贴.美丽又丸方,还会做着一手的好菜。-好算由就犹如好老婆,应该具备肘间救率嵩和存緒量低的特盍。所玖在设计算比的肘候我们应聂尽量脛考这两方面的问题!可读性一算廉谟讨另一期的是为了便于词读”理解和交流。一我么写代码的期的,一方面是为了让计尊机执行,但还有一个重要的目的是为了便于危人阑彼和自己目后词锲修故口健壮性当输入数据不合矗肘,算诜也能做出相关致理,而不是产生异常、崩溃或莫名其妙的结果。i003时间复杂度和空间复杂度算注致卑的决量方眩上一讲中我们提到设讨算法要尽量的提當数率.这里数率壽一般指的是算法的执行时间。那么我们如何来度量一个算法的执行肘间呢?所谓”是軀子是马拉出来-比较家易想到的方去就是我们把算城跑若干次.然后拿个计时薜”疫旁边计时。这种事后统计方法看上去的确不错,并且也并非真的要你拿个讨算器往那里计笫因为计算机鬟有计肘功能。i事后统计方去:这种方法主要是適过设计好的测式程序和教据,利用计算机计肘爰对不同毎法编制的程序的运行对问进行比较,从而确走算冻效率的高低Q但这科方法显烹是有很丸缺咯的:-必须俵据算垛事丸编制好测试程序P通當需要杞裁丸量时词和精力兜了发觉测试的是糟糕的算法,即不是功亏一簧?磅了娘子丈折兵?一不同测蹴环蜒篡别不县一般的犬!V我们把剛則的估异方迭稀为爭后诸葛壳。我们的计算机前辈们也I不一定知道错葛亮是推为了对算出的评判更为科学和便捷,他们研克出事前分祈牯算的方去。事前分祈牯算方法:在计算机程序编写前,傢据统计方法对算法进行估算。经过总结,我们发现一个當级语言编写的程辱在讨算机上运行肘所请耗的时问取决于下列因素12*:算法采用的策略,方秦编译戶生的代码质量问題的输入规栈机薜执行指令的速度由此可见,抛开这些与计算机硬件、软件有关的因素,个程序的运行时间依赖于算出的好坏和问題的输入规旗七(所谓的问題输入规核是指输入量的多少丿我们椒回搞死先生的即个算法来跟丸家淡谈:5第一种算法:/轨行1冼/轨行了rul攻intisum=0,门和100;for(i=l;in=100;for(i=l;i=n;i+)for(j=l;j2肘,#A1就开始优于算法BIT,随着n的继续增加,算法A1比算法B1逐奘因数的渐近增长:给定两个因数f(n)和g(n),如果存在一个整数N,使得对于所有的nN,f(n)总是比g(n)A,那么,我们说f(n)的增长渐近快于g(n)o从创才的对比中我们还发现,随着n的增大,后面的+3和+1其卖是不影响最终的第法变化曲线的。例如算法A2,B2,在图中他们压才艮儿彼覆盖了。所以,我们可以忽略这些加由常数。.后边我们给丸家举多几个例子,会灵朗显。2丝超的渐近橹农第二个测试,算法C是4n+8,算法D是2nA2+lo次数算法ClC4n+8J算法C2CnJ算法DIC2nA2+lJ算法D2fnA2Jn=l12131n=216294n=3203199n=104810201100n=1004081002000110000n=100040081000200000110000002500000法Cj(4n+8S法C0n)M法DK2nA2+l算法DIL(nA2)ffiClfEfiFISHCXOM我们观寨发现,哪怕去掉与n相乘的常教,两者6结果还是没有改变,算法C2的次数随着n的增长,迢是远小于算法D2。也就是说,与最寫次项相乘的常教并不重要,也前V2盘虬八我们再来看第三个测试,算法E是2nA2+3n+l,境去F是2nA+3n+lo次救算法E2C2nA2+3n+lJ算法E2fnA2JJ1算法F2C2nA3+3n+lJ算法F2fnA3Jn=l6161n=2154238n=32896427n=1023110020311000n=1002030110000_200030110000002500000算法El算法E2(nA2)算法Fl(2nA3+3n+l)法F2(nA3)(2nA2+3n+l)GDCTfESFISHC.COM这次我们又发现什么呢?小甲鱼没有小鸡鸡?不是的,我们通过观案又发现,最壽次项的指数丸的,函数随着n的增长,结果也会变得增长特别快。恩,我们进行最后一个小测试,把这些概念都总结起来吧!算法G是2nA2,算法H是胡+1,算去I是今2nA2+3n+lc】决数算法G(222丿算法H我们有了上一讲的准备环节0这一讲我们直接切入正題介绍计算复杂度的攻略,然后通过一条列例子和火家一起分析思结规i算法肘间复杂度的定乂:蛊进行算诜分析时,语句恁的执行次數T(n)是关于问题规模n的园数#进而分析T(门)咗门的变化情况并确走T(r)的埶量级算集釣肘间复杂度,也就是算诜的对间量度,询作:T(n)=0(f(n).它崔示随问题现模n的增丸,算法执行时间的增长率和于(门)的增长率相同,孫作算法的渐近肘问复杂度,简称另时问复杂度乜其中f(n)是问题规模n的荼个园欽。好長好长,没想到走义这个概念的老家伙比小F鱼还罗嗦。(关键需要知道执行次数=时间人这样用丸写0()来体现算法对闻复杂度的沉法.余们稀之为丸O询绘C一般情况下,Rt着输人规棋门飾增丸.T(n)增长最慢的算法箝最优算绥。翌然,由此算法时问复杂度的走乂可知,我们的三个乘和算法的肘问复杂度分别务0(1),O(n),O(nA2)Q三个录和算出?哪韦?忘了?e好吧,看看以下这菠图能不能勾起点回札?稚專丈0阶方法那么如何分析一个算法的时问复杂度呢?即如何推导大o阶呢?我们给丸家整理了以下攻略:一用常数1取代运行时间中的所有加法常教。一庄修改后的运行次数函数中,只保留最嵩阶项。-如果最需阶项存在且不是1,则去除与这个项相乘的常数。-得到的最后结果就是大0阶。世界上的东西就是这么简单,老头儿们把它杂,那么它就复杂了,举几个例子:irrtsum=0,n=100;printf(111lovefishccomrT);printf(Iprintf(Iprintf(Iprintf(Iprintf(I);););););loveFishccomrTnlovefishccomrTloveFishC.comrTnsum=(l+n)*n/2;丸家觉得这段代码的丸0是多少?0(8)?这是初学者常當犯的错谆,总认为有多少条语句就有多少。分析下,按照我们的概念“T(n)是关于问题规模n的因数”来说,这里大家表示对鱼C的爱固然是好的,要支持的,要誠励的,要丸力表彰的。但是,跟问题规模有关糸吗?没有,跟问题规模的表亲戚都没关糸!,所以我们记作0Q)就可以。另外,如果按照攻略来,那就更简单了,攻略第一条就说朗了所有加冻常敎给他个0(1)即可。一般含有非按套循环涉及线性Rs线性阶就是随着问题规模n的扩大,对应计算次教呈直线增长。inti,n=100,sum=0;for(i=0;in;i+)sum=sum+i;卫面这段代码,它的循环的时间复杂度为0(n),因为循环体中的代码需要执行n次。社年方阶创才是单个循环结构,即么炭套呢?intijj,n=100;for(i=0;in;i+)for(j=0;jn;j+)printf(/ZIloveFishCcomn);门等于100,也就是说外层循环每执行一次,内层循环就执行100次,那总共程序想要从这两个循环出来,需要执行100*200决,迄就是n的平方。所以这段代码的时间复杂度为0(22)。那如果有三个这样的嵌套循环呢?没错,那就是nA3o所以我们很汆易总结得出,循环的对间复杂度等于循环体的复杂度乘以该循环运行的次教T刚刖我们毎个循环的次教都是一样的,如果:弋分析下.由于i=0时,内循环执行了口決,当时,内循环则执行门-1次当i=n-l对,内循环执I行1次,所以恿的执行次数应孩是:n+(n-l)+(n-2)+,+l=n(n+l)/2丸家还记碍这个佥式吧?恩恩,没错啦,就是搞吧丸生发刚的算法丫。叩咱理讐居可以继续,n(n+l)/2=n2/2+n/2用我们推导大0的欢略,第一秦忽略,因為没有欝教相加。第二条只镣留最高项.所以门/2这项去掉箋三条,去除与最离项相柬的常救,最终将0(22花宀,注意上面这里不是负n而是一个横线对数,属于嵩中数学内家啦,对于有些鱼油可能对这玩意不丸理解F或者忘记了,也没事,咱分析的是程序为主,而不是数学为主,不怕。我们看下这个程库:inti=ljn=100;while(in)i*2;由于每次厂2之爲,就举例n更近一步,假设有x个2相乘為大于或等于m则务退出循环。于送由2=n得到x=log(2)n,所以这个循环的Mi可复杂度O(logn)0其卖理解大0推导不算难,难的是对教列的一些相关运算,这烫多的是考案你的数学知识和能力。所以这里小甲鱼要分两类来说下,对于氮考研的朋发,需要强化一下你的数学尤其是数刊方面的知识。对于想增长自己编程能力的朋友,丸城知道规律即辛门不要层嵩等数学的概念上死瑶!S005时间复杂度和空间复杂度窗叙调用的时间药粢炭金祈大家是否能自己如果我们把问题再卖际化一点,正确的分析出来呢?我们来看下边这个例子:inti,j;for(i=0;in;i+十)function(i);voidfun匚tion(intcount)printf(i!%dlf了count);函教体是柑印这个参教,这很好理鮮心function函数的对间复杂度是0(1),所以整体的肘间复杂度就是循环的决数0占1假如funtizion是下面这样,又该如何呢:voidfunction(intcount)intj;for(count;jn;j+)pnintf(Vj);1*匸J宀事卖上,这和之前我们讲解平方阶的对候举的第二个例子一样:function内部的循环次数随count的增加(接近n)而癞少,所以根据游戏攻略算法的时间复杂度为0(22)。接着使出杀手铜,给鱼油们一个挑战的机会!己分析以下程序的时间复杂度:百n+;function(n);for(i=0;in;i+)function(i);for(i=0;in;i+)for(j=i;jn;j+)printf(%6,j);円wy夂w*7(n+;汽function(n);for(i=0;in;i+)function;YY-for(i=0;in;i+)or(j二i;jn;j+)printf(%d,j);纟见的时间良粢庚例子肘间复杂度装遍术话52013140(1)常教阶3n+40(n)线性阶3nA2+4n+50(nA2)平方阶31og(2)n+4O(logn)对教阶2n+3nlog(2)n+14O(nlogn)nlogn阶nA3+2nA2+4n+60(nA3)立方阶250(2An)夷相京玻盼线性阶对数踰平魏nlognfcl平方阶立方盼指数阶纟见的时间衣京庚常用的肘间复杂度所耗费的时间从小到夬依次是:0(1)0(logn)(n)O(nlogn)0(nA2)0(nA3)0(2八巳)0(n!)0(nAn)0(1)J0(logn),0(n)?0(nA2)我们前边己经给丸家举例淡过了,至于O(nlogn)们将会在今后的课程中介绍。而像0(23)之后的这些,由于n值的增丸都会使得结果丸得难以想象,我们没必要去讨论它们总最坏晴况层年物情况从心理学角度讲,毎个人对将来要发生的事情都会有一个预期。譬如看半杯水,有人会说:哇哦,还有半杯哦!但有人就会失望的说:夭,只有半杯了。一般人常出于一种对未来失败的粗忧,而在预期的肘候超向做最坏打算。这样,即使最糟糕的结果出现,当事人有了心理准备,比较家易接受结果,假如结局并未出现最坏的状况,这也会使人更加快乐,M,事情发展的还不错嘛!嗯,这晏典型的自愈手出。、申算法的分析也是类似,我们查找一个有n个随机数字数组中的禁个数字,最好的情况是第一个数字就是,那么算法的时间复杂度为0(1),但也有可能这个数字就在最后一个住置,那么时间复杂度为0(n)。平均运行肘间是期望的运行对间。最坏运行时间是一种保证。在应用中,这是一种最重要的需求,通常除非特别指走,我们提到角运行时间都是最坏情况的运行时间。但是毎次查询只需要一次索引判断即可。这就是通过一笔空间上的开销来换取计畀肘间开鮪的小技巧。到底哪一种方余好?其罢还是要看你用在什么地方。产算法的空间复杂度通过计翼算法所需的存储空间卖现,算出的空间复杂度的计算丛式记作:S(n)=O(f(n),其中,n%问题的规模,f(n)为语句关于ri所占存儲空问的函数。通常,我们都是用篥肘间复杂度”来指运行肘间的需扎是用対空间复杂度”指症间需求。当直接要让我们求”复杂度”叭通療指的是肘
展开阅读全文