程序设计=数据结构+算法
数据结构分为 逻辑结构(面向问题) 和 物理结构(面向计算机)。
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算法也不再有效,甚至现在所有的多项式复杂度的加密算法都没用了——不过这样一来程序猿也可以方便地找到妹子了,说起来并不是一无是处嘛……
常用的算法的时间复杂度和空间复杂度