数据结构 时间复杂度

程序设计=数据结构+算法

 

数据结构分为 逻辑结构(面向问题) 和 物理结构(面向计算机)。

1、逻辑结构:数据元素之间的相互关系

     集合结构、线性结构(一对一)、树形结构(一对多)、图形结构(多对多)

2、物理结构:数据的逻辑结构在计算机中的存储形式

        顺序存储结构:

       数据元素放在地址连续的存储单元里,数据间的逻辑关系和物理关系是一致的。

       链式存储结构:

        时常要变化的结构,有添加、有删除。

       把数据元素存放在任意存储单元,存储单元可以连续可以不连续。

       单线联系。

 

数据类型:原子类型、结构类型、抽象数据类型

抽象数据类型(ADT):一个数据对象、数据对象中各数据元素之间的关系 及 对数据元素的操作。

体现了程序设计中问题分解、抽象和信息隐藏的特性。

标准格式:

ADT 抽象数据类型名
Data
       数据元素之间逻辑关系的定义
Operation
      操作1
             初始条件
         操作结果描述
       操作2
             ……
       操作3
            ……
endADT


 

算法:

对合法输入产生输出;

对非法输入产生输出;

对刁难的测试数据产生输出。

 

算法效率的度量:

测定运行时间的可靠方法,计算对运行时间有消耗的的基本操作的执行次数。运行时间与这个计数成正比。

基本操作数量表示成 输入规模的函数。

函数的渐进增长性。

推断算法效率时,常数和其他次要项可以忽略,应关注主项(最高阶项)的阶数。

大O记法:

常数1取代所有加法常数;

修改后的运行次数函数,只保留最高项;

若最高项存在不为1,取出这个项的系数,变为1.

最坏时间复杂度,是最重要的需求,一般提到的时间复杂度 都指这个。

平均运行时间 最有意义。

 

注意到所有的对数只不过相差一个常数,所以这里都用了常用对数。另外一般程序只处理32位的数据,因此最大整数是2^32-1,大约等于10^9。因此log n可以认为是近似等于10的常数,也就是说O(log n)的近似等于O(1),O(n * log n)近似等于O(n),这点也在上表中有所反应。

在时间复杂度计算中常见的级别有O(1)< O(log n) < O(n)<O(n * log n) <O(n^k)<O(a^n)<O(n!)<O(n^n),其大小逐级上升.

复杂度举例:

*  O(1) 常数级复杂度,也就是说程序运行的时间与需要处理的数据大小无关。通常把比较大小、加减乘除等简单的运算都当做常数级复杂度。 值得注意的是,在处理大数(二进制下数据长度超过32位或者十进制下超过8位)时,将加减乘除等运算当做常数复杂度不再适用。

*  O(log n) 将一个10进制整数转化为2进制整数

*  O(n):判断一个元素是否属于一个大小为n的集合/列表;找出n个数中的最大值;

*  O(n * log n) 快速排序法

*  O(n^2) 最直白的两两比较然后排序方法,需要n*(n-1)/2次比较,所以是O(n^2)级。

*  O(2^n) 列出所有长度为n的0,1字符串之类的穷举计算

*  O(n!) 列出n个元素的全排列之类的穷举计算

一般来说多项式级的复杂度是可以接受的,很多问题都有多项式级的解——也就是说,这样的问题,对于一个规模是n的输入,在n^k的时间内得到结果,称为P问题。有些问题要复杂些,没有多项式时间的解,但是可以在多项式时间里验证某个猜测是不是正确。比如问4294967297是不是质数?如果要直接入手的话,那么要把小于4294967297的平方根的所有素数都拿出来,看看能不能整除。还好欧拉告诉我们,这个数等于641和6700417的乘积,不是素数,很好验证的,顺便麻烦转告费马他的猜想不成立。大数分解、Hamilton回路之类的问题,都是可以多项式时间内验证一个“解”是否正确,这类问题叫做NP问题。(据信程序猿找妹子也是一个NP问题。。)

P问题显然都是NP问题——既然你能在多项式时间里得到答案,那么只要比较一下答案和猜测是不是一样就可以验证一个解。反过来,多数人相信,NP问题不都是P问题。几个月前看到一篇论文说NP不等于P,但没有看到后续报道,也读不懂原文,摊手……如果NP问题都是P问题,那么大数分解不再是难题,从而基于大数分解的RSA加密系统顿时崩溃;同样md5算法也不再有效,甚至现在所有的多项式复杂度的加密算法都没用了——不过这样一来程序猿也可以方便地找到妹子了,说起来并不是一无是处嘛……

常用的算法的时间复杂度和空间复杂度

排序法

最差时间分析 平均时间复杂度 稳定度 空间复杂度
冒泡排序 O(n2) O(n2) 稳定 O(1)
快速排序 O(n2) O(n*log2n) 不稳定 O(log2n)~O(n)
选择排序 O(n2) O(n2) 稳定 O(1)
二叉树排序 O(n2) O(n*log2n) 不一顶 O(n)

插入排序

O(n2) O(n2) 稳定 O(1)
堆排序 O(n*log2n) O(n*log2n) 不稳定 O(1)
希尔排序 O O 不稳定 O(1)

1、时间复杂度
(1)时间频度 一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)。
(2)时间复杂度 在刚才提到的时间频度中,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)) 为算法的渐进时间复杂度,简称时间复杂度。
在各种不同算法中,若算法中语句执行次数为一个常数,则时间复杂度为O(1),另外,在时间频度不相同时,时间复杂度有可能相同,如T(n)=n2+3n+4与T(n)=4n2+2n+1它们的频度不同,但时间复杂度相同,都为O(n2)。 按数量级递增排列,常见的时间复杂度有:常数阶O(1),对数阶O(log2n),线性阶O(n), 线性对数阶O(nlog2n),平方阶O(n2),立方阶O(n3),..., k次方阶O(nk),指数阶O(2n)。随着问题规模n的不断增大,上述时间复杂度不断增大,算法的执行效率越低。 2、空间复杂度 与时间复杂度类似,空间复杂度是指算法在计算机内执行时所需存储空间的度量。记作: S(n)=O(f(n)) 我们一般所讨论的是除正常占用内存开销外的辅助存储单元规模。讨论方法与时间复杂度类似,不再赘述。
(3)渐进时间复杂度评价算法时间性能   主要用算法时间复杂度的数量级(即算法的渐近时间复杂度)评价一个算法的时间性能。

2、类似于时间复杂度的讨论,一个算法的空间复杂度(Space Complexity)S(n)定义为该算法所耗费的存储空间,它也是问题规模n的函数。渐近空间复杂度也常常简称为空间复杂度。
空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度。一个算法在计算机存储器上所占用的存储空间,包括存储算法本身所占用的存储空间,算法的输入输出数据所占用的存储空间和算法在运行过程中临时占用的存储空间这三个方面。算法的输入输出数据所占用的存储空间是由要解决的问题决定的,是通过参数表由调用函数传递而来的,它不随本算法的不同而改变。存储算法本身所占用的存储空间与算法书写的长短成正比,要压缩这方面的存储空间,就必须编写出较短的算法。算法在运行过程中临时占用的存储空间随算法的不同而异,有的算法只需要占用少量的临时工作单元,而且不随问题规模的大小而改变,我们称这种算法是“就地\"进行的,是节省存储的算法,如这一节介绍过的几个算法都是如此;有的算法需要占用的临时工作单元数与解决问题的规模n有关,它随着n的增大而增大,当n较大时,将占用较多的存储单元,例如将在第九章介绍的快速排序和归并排序算法就属于这种情况。

当一个算法的空间复杂度为一个常量,即不随被处理数据量n的大小而改变时,可表示为O(1);当一个算法的空间复杂度与以2为底的n的对数成正比时,可表示为0(10g2n);当一个算法的空I司复杂度与n成线性比例关系时,可表示为0(n).若形参为数组,则只需要为它分配一个存储由实参传送来的一个地址指针的空间,即一个机器字长空间;若形参为引用方式,则也只需要为其分配存储一个地址的空间,用它来存储对应实参变量的地址,以便由系统自动引用实参变量。

 
求1到100的和:
1、一个for
2、高斯公式:(1+n)*n/2 
展开阅读全文

没有更多推荐了,返回首页