呼呼,这么晚才来更新。css
今天上了不少课,感受也没浪费到时间,但是就已经这么晚了,多是没有好好利用上课时间吧,明天开始要好好利用上课时间来作一些学习和计划。今天虽然有不少计划尚未完成。不过博客是必定要更的(必定要坚持下去!└(^o^)┘,并且好像写出来的文章,排版样子什么的不太好,我决定明天早上修饰一下本身的博客,好比安装客户端,安装插件,添加css什么的,尽可能弄得美观大方清楚一点。)算法
好了,正式进入正题。编程
--------------------------华丽分割线--------------------------------数据结构
今天学习了算法分析与设计,主要讲了一些算法思想和知识,如今来总结一下。数据结构和算法
编程的灵魂:函数
数据结构+算法=程序。性能
今天才正式注意到了这点,之前学了不少算法和数据结构,可是理论方面很凌乱,如今算是正确地认识到了何为程序,何为数据结构和算法的做用。简单来讲,算法就是解决问题的方法或者过程,若是把问题当作一个函数,算法能够把输入转化为输出。而数据结构是数据的计算机表示和相应的一组操做。这两大内容组合,就造成了咱们熟悉的程序。学习
算法:优化
由刘汝佳、黄亮著做的《算法艺术与信息学竞赛》可知,基本算法可分为四种,枚举、贪心、递归与分治法、递推。spa
今天暂时不对此进行详解,目测将于周五晚对此微博进行更新,详细阐述这四种方法并举些许例子来讲明。
时间复杂度和空间复杂度的计算:
今天主要讲的是这个。原本我对这方面的知识没有学的很详细,主要是之前使用的数据比较小,本身也没有对程序算法优化颇有兴趣,致使自身对算法的时间和空间复杂度理解不是很好。但这个方面的知识真的很重要,能够用来评估你的算法写的是否高效,合理,当初咱们的专业老师在上数据结构课时花了不少时间来说复杂度这门知识,惋惜我没有认真听,而不少算法书都把关于时间和空间复杂度的计算列入基本纲要,尤见其重要性。如今就来从新认识一下,也算是比较基础的认识吧,之后会逐渐深究,争取写出更优化的程序。
时间复杂度:
同一问题可用不一样算法解决,而一个算法的质量优劣将影响到算法乃至程序的效率。所以能够这样理解,计算机科学中,算法的时间复杂度做为一个函数,可以定量描述该算法的运行时间。
通常来讲,可以准确地判断两个算法的性能好坏的方法就是各写一个程序来观察它们的运行状况,可是这样异常耗时而且程序并非算法的直接对应结果,可能会没法避免一些和算法无关,只由程序代码产生的问题。所以,咱们能够运用时间复杂度,从理论上来估计和比较算法的运行效率。下面会详细解释时间复杂度的由来。
在具体了解时间复杂度以前,须要了解一个概念--基本操做。抽象来讲,基本操做,就是一个运行时间不依赖于操做数的操做。简单来讲,既然咱们是利用时间复杂度来估计算法的运行效率的,那咱们总得有个估量的依据吧,好比说哪些操做占时最大,哪些操做占时较小能够忽略,咱们就把占主要运行时间的操做看做为基本操做,并做为时间复杂度估计的依据。为何说基本操做是不依赖于操做数的操做?有点混乱吧。这里借鉴了《算法艺术与信息学竞赛》的一个小例子来讲明一下。好比两个不大于100的正整数相加,那么运行时间确定常数,基本操做就是加法操做,操做数就是那两个几乎不影响运行时间的不大于100的正整数,也就是加法操做并不依赖于操做数。可是,若是是两个大小无限制(位数特别大)的两个正整数相加呢?这时候,加法操做就不能当作是基本操做了,由于两个极大数相加,咱们计算时是须要将两个极大整数对应的位数相加,所以,这里的加法操做就不能当作是基本操做了,由于操做数(即极大整数)对其操做的影响很大。那么在这种状况下,什么才是基本操做?可能你已经想到了,将对应位数相加的操做,就能够当作是一个基本操做,由于每位位数是最大值为9的操做数,其运行时间不依赖于它的操做数。学习基础算法的时候可能不会发现这个概念的用处,但越往深研究越会发现,在不一样时候,能够把不一样的操做当作基本操做,而基本操做的选择就反映了你对问题的主要矛盾的认识。这个是很是重要的。
如今理解一下时间频度,参考百度百科,一个算法花费的时间与算法中语句(基本操做)的执行次数成正比例,所以,一个算法中的语句执行次数可称为语句频度或时间频度。记为T(n)。
如今咱们将输入n称为问题的规模(可理解为问题运行时间的大小),当n不断变化时,时间频度T(n)也会不断变化。但有时咱们想知道它变化时呈现什么规律。为此,咱们引入时间复杂度概念。
通常状况下,算法中基本操做重复执行的次数是问题规模n的某个函数,用T(n)表示,如有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记做T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。
时间频度不一样,但时间复杂度可能相同。如:T(n)=n2+3n+4与T(n)=4n2+2n+1它们的频度不一样,但时间复杂度相同,都为O(n2)。有点绕,有点理论化是吧?回去看高数书应该又能够理解了>_<|||。或者你能够简单得理解为时间复杂度就是时间频度的公式化,简单化,好比n2+3n+4能够简化为n2,由于在n无穷大时,他们趋近于相等。那为何能够这样简化呢?为何称之为渐进时间复杂度呢?在这里,咱们须要考虑一个问题,由于算法的运行时间可能和计算机的运行速度有关(好比某些操做运行快,某些操做运行慢),因此咱们只关心在问题规模扩大时时空开销的增加状况。是的,增加状况,这是特别须要注意的。
咱们再来看两个例子:
1 int num = 1;; 2 for (i = 1; i <=n; i++) { 3 num *= i; 4 }
int num = 1;; for (i = 1; i <= n; i++) { for (j = 1; j <= n; j++) { num = num + i +j; } }
这两个例子中,变量i,j的自增并不影响算法的运行时间,因此咱们把加法和乘法操做当作是基本操做。那么,第一份代码执行了n个操做,第二份代码执行了n2个操做。那么哪一个运行速度更快呢?答案是不知道。是的,由于不知道加法操做和乘法操做哪一个快(联系前面所说,算法运行时间依赖于计算机的运行速度)。如今假设加法速度是乘法的10倍,那如今谁更快呢?还不必定,假设加法操做时间为t,乘法操做时间为10t,第一份代码运行时间为n*10t,第二份代码运行时间为n2*t,当n小于10时,第二份代码运行较快,当n大于10时,第一代码运行较快。
可是,这样依赖于n的规模大小(或者依赖于计算机运行速度)来估量算法运行时间,那答案就不惟一不肯定了,这样的研究方法很不严谨。因此,在算法分析上来看,咱们观察增加状况来估量算法运行时间,会更优。好比,当n规模扩大10倍时,第一份代码运行时间只扩大了10倍,可是第二份代码运行时间会扩大100倍,就这样观察的话,第一份代码运行速度更快更优,而且不依赖于计算机的运行。
因此,进行算法分析的时候,咱们只对增加状况作分析。到这里就比较好理解为何叫作渐进时间复杂度了吧?就是n趋向于无限大的时候,得出与时间频度T(n)的增加状况趋近的时间复杂度O(f(n)),用来更简单直接得表示算法的运行时间。由于n越大,T(n)和时间复杂度越接近,因此就叫作渐进时间复杂度!(哎哟,解释得好辛苦,不知道是否是越解释越乱了=@~@=)
------------------- 停笔先 -----------
好吧!眨眼之间发现写了很久了,空间复杂度还没写呢 QAQ。但太晚了,周五再更吧。
努力,晚安。