diff --git a/数据结构与算法.md b/数据结构与算法.md new file mode 100644 index 0000000..9506dfb --- /dev/null +++ b/数据结构与算法.md @@ -0,0 +1,235 @@ +### 1. 数学知识基础 + +#### 1.1 基本概念 + +##### 1.1.1 指数 + +$$ +X^AX^B = X^{A+B} +$$ + +$$ +X^A/X^B = X^{A-B} +$$ + +$$ +X^N+X^N = 2X^N +$$ + +$$ +2^N + 2^N = 2^{N+1} +$$ + +$$ +(X^A)^B = X^{AB} +$$ + +##### 1.1.2 对数 + +在计算机科学中,默认所有对数都是以2为底的。 +$$ +X^A = B <==> log_xB = A +$$ + +$$ +log_AB = log_cB/log_cA +$$ + +$$ +logAB = logA + logB +$$ + +$$ +log1=0,log2=1,log1024=10,log1048576=20 +$$ + +##### 1.1.3 级数 + +$$ +\sum_{i=0}^{N}2^i=2^{N+1}-1 +$$ + +$$ +\sum_{i=0}^NA^i=(A^{N+1}-1)/(A-1) +$$ + + + +#### 1.2 关于递归 + +base case (基准情况):也就是递归头,结束循环的情况。 + +circular logic(循环推理):方法内部调用自身, + + 递归的四个基本法则: + +- 基准情形(base case):必须有无需递归就能解出的结果 +- 不断推进(making progress):对于那些需要递归求解的情形,每一次递归调用都必须要使状况朝向一种基准情况推进 +- 设计法则:假设所有的递归调用都能运行 +- 合成效益法则:在求解一个问题的同一实例时,切勿在不同的递归调用中做重复性的工作。 + +### 2. 算法分析 + +​ 算法是为求解一个问题需要遵循的、被清楚指定的简单指令的集合。对于一个问题,一旦某种算法给定并且(以某种方式)被确定是正确的,那么重要的一步就是确定该算法将需要多少时间或空间等资源量的问题。从算法所占的时间和空间两个维度去衡量算法的优略。 + +#### 2.1 时间复杂度 + +**大O符号表示法:T(n) = O(f(n))** + +其中f(n) 表示每行代码执行次数之和,而 O 表示正比例关系,这个公式的全称是:**算法的渐进时间复杂度**。 + +大O符号表示法并不是用于来真实代表算法的执行时间的,它是用来表示代码执行时间的增长变化趋势的。 + +常见的时间复杂度量级有: + +- 常数阶O(1) +- 对数阶O(logN) +- 线性阶O(n) +- 线性对数阶O(nlogN) +- 平方阶O(n^2) +- 立方阶O(n^3) +- K次方阶O(n^k) +- 指数阶(2^n) + +##### 2.1.1 常数阶O(1) + +​ 代码当中没有循环等复杂结构,那这代码的时间复杂度都是O(1)。它的时间消耗不随着某个变量增长而增长,那么无论这类代码有多长,都可以用O(1)来表示它的时间复杂度。 + +```java +int i = 1; +int j = 2; +++i; +int m = i + j; +``` + +##### 2.1.2 线性阶O(n) + +简单的例子, + +```java +for(int i=0;i x=log_2n +$$ +也就是说当循环了logn (2为底)次后,这代码就结束了,所以这个代码的时间复杂度为:O(logn)。 + +##### 2.1.4 线性对数阶O(nlogN) + +线性对数阶O(nlogN) 其实非常容易理解,将时间复杂度为O(logn)的代码循环N遍,即 +$$ +n*O(logN) ==>O(nlogN) +$$ + +````java +for(int m=1;mO(n^2) +$$ + +这段代码嵌套了2层循环,时间复杂度是O(n*n),即O(n²),如果其中一个循环的n改为m,则时间复杂度变为O(n * m)。 + +#### 2.2 空间复杂度 + +空间复杂度是对一个算法在运行过程中临时占用存储空间大小的一个量度,同样是反映一个趋势,用S(n)来定义。 + +空间复杂度比较常用的有:O(1)、O(n)、O(n²) + +##### 2.2.1 空间复杂度O(1) + +如果算法执行所需的临时空间不随着某个变量n的大小而变化,即此算法空间复杂度为一个常量,可用O(1)表示。 + +```java +int i = 1; +int j = 2; +++i; +int m = i + j; +``` + +代码中的 i、j、m 所分配的空间都不随着处理数据量变化,因此它的空间复杂度 S(n) = O(1)。 + +##### 2.2.2 空间复杂度为O(n) + +```java +int[] m = new int[n] +for(i=1; i<=n; ++i) +{ + j = i; + j++; +} +``` + +这段代码中,第一行new了一个数组出来,这个数据占用的大小为n,这段代码的2-6行,虽然有循环,但没有再分配新的空间,因此,这段代码的空间复杂度主要看第一行即可,即 S(n) = O(n)。 + +### 3. 数组和链表 + +数据的逻辑分类: + +- **线性的**:连成一条线的结构,如数组、链表、队列、栈 +- **非线性的**:数据之间的关系是非线性的,如堆、树、图 + +#### 3.1 数组 + +数组是一个有限的、类型相同的数据的集合,在内存中是一段连续的内存区域。 + +![array](./images/perceive_array.jpg) + +​ 数组的下标是从0开始的,上图数组中有6个元素,对应着下标依次是0、1、2、3、4、5,同时,数组里面存的数据的类型必须是一致的,比如上图中存的都是数字类型。数组中的全部元素是“连续”的存储在一块内存空间中的,如上图右边部分,元素与元素之间是不会有别的存储隔离的。另外,也是因为数组需要连续的内存空间,所以数组在定义的时候就需要提前指定固定大小,不能改变。 + + + + + + + + + + + + + + + + + + + + +