第二篇 算法概述及复杂度

  虽然本系列随笔是记录数据结构相关的内容,但是我们都知晓算法和数据结构是密不可分的。我们也可以时常看到一个公式“程序设计=数据结构+算法”。数据结构是研究数据之前的关系,以及数据在计算机中的存储形式,而算法是让数据通过一定的形式得到我们需要的结果。这其中包含各种的逻辑运算等。

  提及算法,我们会自然的联想到一个关于数学牛人的故事:“高斯7岁那年开始上学。10岁的时候,一天,老师布置了一道题,1+2+3······这样从1一直加到100等于多少。高斯很快就算出了答案,起初高斯的老师布特纳并不相信高斯算出了正确答案:"你一定是算错了,回去再算算。”高斯说出答案就是5050,高斯是这样算的1+100=101,2+99=101······1加到100有50组这样的数,所以50X101=5050。“

  从上面的故事中我们可以得到以下几点:解决一个问题,往往可以采用的方式很多,第一种方式我们可以采用最原始的,从1一直加到100,第二中方式,(0+1+2+3+4+5+6+7+8+9)*10+100,可以理解为从1--100个位数先加,然后乘以十位数,第三种方式也就是高斯同学所采用的这种方式。除此之外还有许许多多可以运用的解法,而这种解法在数据结构中我们称为算法。同时我们在这种故事中也能看出算法的一些特性,首先,要具备正确性,其次算法要做到尽可能的优。

  首先给出算法的定义:算法是解决特定问噩求解步‘的描述,在计算机中表现为指令的有限序列,并且4事务指令亵示一个或多个操作。、

  算法的特性

    输入输出:任何算法都必须有零个或多个输入,但输出一定为大于等于一个。没有输出的算法是没有存在的必要,因为算法的本质就是经过某种处理得到预想的结果,只          是输出的方法可能不能。亦或是控制台,或者输出可见的文件资源等。

    有穷性:算法的执行必须要在有限的步骤中完成,同时在有限的时间里完成,步骤可以是千,万,甚至百万、亿,但是一定是有限的步骤来完成。而且时间的维度也是确

         定的。

    确定性:在同一个输入的情况下,输出的结果一定是确定的,同时是唯一的。不能存在二义性。

    可行性:算法在执行过程中,每一步都是可以通过有限的步骤来完成。

  算法设计的要求

   正确性:是指算法至少应该具有输入、输出和加工处理无歧义性、能正确反映问题的需求、能够得到问题的正确答案。这也是算法的最基本要求,如果一个算法连正确性都        无法保证。我们不能称之为算法。

     可读性:算法的设计其中有个很重要的目的是便于传阅和理解、交流。如果一个算法写的晦涩难懂,久而久而理解这个算法的人会越来越少,最终其价值也会大大折扣。

     健壮性:针对不能输入,得到的结果都是预想中的结果,而不会出现莫名其妙的结果。但是有时候我们很难做到面面俱到,因此在设计算法的时候,要考虑的更多,包括

         其各种临界点等。

     时间效率高存储率低:满足了上面的三点要求,并不能说明该算法就是一个好的算法,一个好的算法应该尽量的追求时间效率高和存储率低。而这两种有时候很难做到完        全的契合。因此在实际的开发过程中我们可能会根据实际应用场景来进行权衡。有时候时间效率高而牺牲一部分空间存储,反之则通过牺牲时间来换的空间存储         率。

  算法的度量方法

   事后统计方法:主要是通过设计好的测试程序和数据,利用计算机计时器对不同算法编制的程序的运行时间进行比较,从而确定算法效率的高低。其实这种做法即我        们日常生活中所说的“事后诸葛亮”。这显然不是一种好的做法。有时候可能因为一种恶劣的算法,而浪费大量的时间。

   事前分析估算法:在编写算法之前,先对算法使用合理的分析对其进行评估,从而择优选择。在分析时我们往往考虑的方面如:算法采用的策略、编译产生的代码质        量、问题的输入规模、机器执行指令的速度。

  函数的渐近增长

    由于输入规模的不同,我们很难准确的说一个算法比另一个算法优,比如说:10n+100与n*n,在输入规模较小的时候(<17),n*n很明显更加的优秀,但是当值大      于17后,n*n将大于10n+100,而且后面的值始终大于前面。而值17其实是一个临界值。

    函数渐近增长:给定两个函数f(n)和g(n),如果存在一个整数N,使得对于所有的n>N,f(n)总是比g(n)大。我们此时称f(n)的增长渐近快于g(n)。

    如图:

    我们一般在算法编写或设计时,都会参照这样的方式来判断一个算法是否优越。

  算法的时间复杂度

    概念:在进行算法分析时, 语句总的执行次次数T ( n )是关于问题规模n的函数,进而分析T ( n )随n 的变化情况并确定T(n)的数量级。算法的时间复         杂度.也就是算法的时间量度,记作: T ( n )= O(f(n))。它表示随问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的渐         近时间复杂度。简称为时间复杂度。其中f(n)是问题规模n的某个函数。

    我们使用O()来体现算法的时间复杂度,简称为大O记法。

    推导大O阶方法

    1. 用常数1取代运行时间中的所有加法常数;
    2. 在修改后的运行次数函数中,只保留最高阶项;
    3. 如果最高阶项存在且不为1,则去除与这个项相乘的常数,得到的结果就是大O阶。

      上面的推导步骤,只能提供一定的指引,在实际分析过程中往往会异常的复杂。

   

    常见的算法复杂度

    常数阶O(1)、线性阶O(n)、对数阶O(logn)、平方阶(n*n)、立方阶等...

    

     举例说明:

     示例1:如果算法的执行时间不随着问题规模n的增加而增长,即使算法中有上千条语句,其执行时间也不过是一个较大的常数。此类算法的时间复杂度是O(1)。

           int sum=0; int max=1000;

           for(int i=0;i<max; i++)

            {

              sum=sum+i;

            }

           解答: T(n)=O(1)

           推导步骤:在不考虑for循环条件中的计算次数,运行过程中共执行了一千次,即T(n)=1000,用常数1取代所有的加法常数,得到的为T(n)=1,其最高项                为0,因此T(n)=O(1)。

     示例2:当有若干个循环语句时,算法的时间复杂度是由嵌套层数最多的循环语句中最内层语句的频度f(n)决定的。

             x=1;

            for(i=1;i<=n;i++)

             for(j=1;j<=i;j++)

                for(k=1;k<=j;k++)

                    x++;   

          解答:T(n)=O(n3)

          推导步骤:忽略for循环中的计算次数。当n为1时,1*1*1;当n为2时,2*2*2...依此类推,每次执行的次数都为n*n*n。在得到T(n)=n3,不存在加法常                  数,因此步骤1保持不变。取得最高阶仍为n3,因此最终的解为n3

  

        示例3:对数

        

          

         解答:T(n)=O(logn)

  算法最坏情况和平均情况

       针对算法的这两个情况,从字面上我们就可以知晓。所以无须赘述。而我们提到的运行时间指的都是最坏情况下的运      行结果。 

    

  算法的空间复杂度

     概念:法的空间复杂度通过计算算法所需的存储空间实现,算法空间复杂度的计算公式记作: S(o)= O(f(o)) ,其中, 0 为问题的规模, f(n)为语          句关于n 所存储空间的函数。

        一个算法在计算机存储器上所占用的存储空间,包括存储算法本身所占用的存储空间,算法的输入输出数据所占用的存储空间和算法在运行过程中临时占用的存储        空间这三个方面。

参考资料:http://www.nowamagic.net/librarys/veda/detail/2197 算法的空间复杂度

      http://www.nowamagic.net/librarys/veda/detail/2195 算法的时间复杂度

      http://blog.csdn.net/booirror/article/details/7707551  算法的时间复杂度举例

时间: 2024-08-05 23:20:01

第二篇 算法概述及复杂度的相关文章

[C#] 软硬结合第二篇——酷我音乐盒的逆天玩法

1.灵感来源: LZ是纯宅男,一天从早上8:00起一直要呆在电脑旁到晚上12:00左右吧~平时也没人来闲聊几句,刷空间暑假也没啥动态,听音乐吧...~有些确实不好听,于是就不得不打断手头的工作去点击下一曲或是找个好听的歌来听...但是,[移动手锁定鼠标-->移动鼠标关闭当前页面选择音乐软件页面-->选择合适的音乐-->恢复原来的界面] 这一过程也会烦人不少,如果说软件的设计要在用户体验上做足功夫,感觉这一点是软件设计人员很难管住的方面,毕竟操作系统也就这样安排的嘛(当然,有些机智的开发人

目标反射回波检测算法及其FPGA实现 之一:算法概述

目标反射回波检测算法及其FPGA实现之一:算法概述 前段时间,接触了一个声呐目标反射回波检测的项目.声呐接收机要实现的核心功能是在含有大量噪声的反射回波中,识别出发射机发出的激励信号的回波.我会分几篇文章分享这个基于FPGA的回波识别算法的开发过程和原码,欢迎大家不吝赐教.以下原创内容欢迎网友转载,但请注明出处: https://www.cnblogs.com/helesheng.本文首先简要介绍基于FPGA的互相关反射回波检测算法的主要设计思路. 声呐测距的原理非常简单,如下图所示,抹香鲸在水

【java算法】---余弦相似度计算字符串相似率

余弦相似度计算字符串相似率 功能需求:最近在做通过爬虫技术去爬取各大相关网站的新闻,储存到公司数据中.这里面就有一个技术点,就是如何保证你已爬取的新闻,再有相似的新闻 或者一样的新闻,那就不存储到数据库中.(因为有网站会去引用其它网站新闻,或者把其它网站新闻拿过来稍微改下内容就发布到自己网站中). 解析方案:最终就是采用余弦相似度算法,来计算两个新闻正文的相似度.现在自己写一篇博客总结下. 一.理论知识 先推荐一篇博客,对于余弦相似度算法的理论讲的比较清晰,我们也是按照这个方式来计算相似度的.网

[C++11新特性]第二篇

0.可变数量参数,可变函数模版,变长模版类 c++98可变数量参数 #include<cstdio> #include<cstdarg> double SumOfFloat(int count, ...) { va_list ap; double sum=0; va_start(ap,count); for(int i=0;i<count;i++) sum+=va_arg(ap,double); va_end(ap); return sum; } int main() { p

泛型算法概述

顺序容器只定义了很少的操作:在多数情况下,我们可以添加和删除元素.访问首尾元素.确定容器是否为空以及获得指向首元素或尾元素之后位置的迭代器. 如果我们想要做:查找特定元素.替换或删除一个特定值.重排元素顺序等.标准库并未给每个容器都定义成员函数来实现这些操作,而是定义了一组泛型算法:称它们为“算法”,是因为它们实现了一些经典算法的公共接口,如排序和搜索:称它们是“泛型的”,是因为它们可用于不同类型的元素和多种容器类型(不仅包括标准库类型,如vector或list,还包括内置的数组类型). 概述

LeetCode题解 15题 第二篇

之前写过一篇,这是第二篇.上一篇用了多种编程语言来做,这一次是以学算法为主,所以打算都用python来完成. 4. Median of Two Sorted Arrays There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log

SQL Server 非聚集索引的覆盖,连接,交叉和过滤 &lt;第二篇&gt;

在SQL Server中,非聚集索引其实可以看做是一个含有聚集索引的表,但相对实际的表来说,非聚集索引中所存储的表的列数要少得多,一般就是索引列,聚集键(或RID).非聚集索引仅仅包含源表中的非聚集索引的列和指向实际物理表的指针. 一.非聚集索引之INCLUDE 非聚集索引其实可以看做一个含有聚集索引的列表,当这个非聚集索引中包含了查询所需要的所有信息的时候,则就不再需要去查基本表,仅仅做非聚集索引就能够得到所需要的数据.INCLUDE实际上也能称为覆盖索引,但它不影响索引键的大小. 先来看下面

Android开源项目第二篇——工具库篇

本文为那些不错的Android开源项目第二篇——开发工具库篇,主要介绍常用的开发库,包括依赖注入框架.图片缓存.网络相关.数据库ORM建模.Android公共库.Android 高版本向低版本兼容.多媒体相关及其他. Android开源项目系列汇总已完成,包括: Android开源项目第一篇——个性化控件(View)篇 Android开源项目第二篇——工具库篇 Android开源项目第三篇——优秀项目篇 Android开源项目第四篇——开发及测试工具篇 Android开源项目第五篇——优秀个人和

java学习笔记 第二篇 核心技术(二)

第十四章 集合类 集合类用来存放对象的引用.继承关系如下图: 14.1 Collection 接口 是层次结构中的根接口,构成Collection的单位称为元素.Collection接口不能直接使用,但该接口提供了添加元素.删除元素.管理数据的方法. Collection接口常用方法: 14.2 List 集合 包括List接口以及List集合的所有实现类.List集合中的元素允许重复,各元素循序就是对象插入的顺序 1.List接口,两个重要方法: get(int index): 获取指定索引位