转自【五月的仓颉】 http://www.cnblogs.com/xrq730/p/5122436.html
数据结构
数据结构是计算机存储、组织数据的方式,是指数据相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率(这就是为什么我们要研究数据结构的原因),数据结构往往同高效的检索算法和索引技术相关。
常见的数据结构有数组、栈、队列、链表、树、散列等,这些数据结构将是本数据结构的分类中重点研究的对象。
算法分析
算法是为求解一个问题需要遵循的、被清楚指定的简单指令的集合。对于一个问题,一旦某种算法给定并且(以某种方式)被确定是正确的,那么重要的异步就是确定该算法将需要多少注入时间或空间等资源量的问题。如果:
1、一个问题的求解算法竟然需要长达一年时间,那么这种算法就很难有什么用处
2、一个问题需要若干个 GB 的内存的算法,在当前大多数机器上也是无法使用的
数学基础
无论是数据结构还是算法分析,都用到了大量的数学基础,下面将这些数学的基础简单总结一下:
1、指数
(1)XAXB = XA+B
(2)XA/XB = XA-B
(3)(XA)B = XABsi
(4)XN + XN = 2XN ≠ X2N
(5)2N + 2N = 2N + 1
2、对数
(1)XA = B 当且仅当 logxB = A
(2)logAB = logCB / logCA
(3)logAB = logA + logB,A>0 且 B>0
3、级数
(1)∑2i = 2N+1 - 1
(2)∑Ai = (AN+1 - 1) / (A - 1),若 0i ≤ 1 / (1 - A)
4、模运算
如果 N 整除 A、N 整除 B,那么就说 A 与 B 模 N 同余,记为 A≡B(mod N)。直观地看,这意味着无论是 A 还是 B 被 N 去除,所得余数都是相同的,于是假如有 A≡B(mod N),则:
(1)A + C ≡ B + C(mod N)
(2)AD ≡ BD (mod N)
时间复杂度
在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。这是一个关于代表算法输入值的字符串的长度的函数,时间复杂度常用大 O 符号表述,不包括这个函数的低阶项和首项系数,使用这种方式时,时间复杂度可被称为是渐进的,他考察当输入值大小趋近无穷时的情况。
那么首先先看一个简单的例子,这里是计算Σi3 的一个简单程序片段:
- 1 public static void main(String[] args)
- 2 {
- 3 System.out.println(sum(5));
- 4 }
- 5
- 6 public static int sum(int n)
- 7 {
- 8 int partialSum;
- 9
- 10 partialSum = 0;
- 11 for (int i = 0; i <= n; i++)
- 12 partialSum += i * i * i;
- 13
- 14 return partialSum;
- 15 }
对这个程序片段的分析是简单的:
1、声明不记入时间
2、第 10 行和都 14 行各占一个时间单元
3、第 12 行每次执行占用 4 个时间单元(两次乘法、一次加法和一次赋值),而执行 N 次共占用 4N 个时间单元
4、第 11 行在初始化 i,测试 i≤n 和对 i 的自增都隐含着开销,所有这些总开销是初始化 1 个时间单元,所有的测试为 N+1 个时间单元,所有自增为 N 个时间单元,共 2N+2 个时间单元
忽略调用方法和返回值的开销,得到总量是 6N+4 个时间单元,按照最开始的定义不包括这个函数的低阶项和首项系数,因此我们说该方法的时间复杂度是 O(N)。继而,我们顺便得出若干个一般法则:
法则一 ----for 循环
一个 for 循环的运行时间至多是该 for 循环内部那些语句(包括测试)的运行时间乘以迭代的次数,因此假如一个 for 循环迭代 N 次,那么其时间复杂度应该为 O(N)
法则二 ---- 嵌套 for 循环
从里向外分析这些循环,在一组嵌套循环内部的一条语句总的运行时间为该语句的运行时间乘以该组所有的 for 循环的大小的乘积,因此假如有以下代码:
- 1 public static int mutliSum(int n) 2 {
- 3 int k = 0;
- 4
- for (int i = 0; i < n; i++) 5 {
- 6
- for (int j = 0; j < n; j++) 7 {
- 8 k++;
- 9
- }
- 10
- }
- 11 12
- return k;
- 13
- }
则其时间复杂度应为 O(N2)
法则三 ---- 顺序语句
将各个语句的运行时间求和即可,比如有以下代码:
- 1 public static int sum(int n) 2 {
- 3 int k = 0;
- 4 5
- for (int i = 0; i < n; i++) 6 k++;
- 7
- for (int i = 0; i < n; i++) 8 {
- 9
- for (int j = 0; j < n; j++) 10 {
- 11 k++;
- 12
- }
- 13
- }
- 14 15
- return k;
- 16
- }
第一个 for 循环的时间复杂度为 N,第二个嵌套 for 循环的时间复杂度为 N2,综合起来看 sum 方法的时间复杂度为 O(N2)
常见的时间复杂度与时间效率的关系有如下的经验规则:
O(1) < O(log2N) <O(n) < O(N * log2N) < O(N2) < O(N3) < 2n < 3n < n!
至于每种时间复杂度对应哪种数据结构和算法,后面都会讲到,从上面的经验规则来看:前四个算法效率比较高,中间两个差强人意,后三个比较差(只要 n 比较大,这个算法就动不了了)。
来源: http://www.bubuko.com/infodetail-2004312.html