一、什么是算法
在数学领域,算法是为了解决某一类问题的公式和思想。
在计算机领域,本质是一些计算机指令,解决特定运算和逻辑问题。
算法的掌握程度,一方面可以检验程序员对计算机底层的了解,一方面也可以衡量程序员的思维逻辑能力。
二、什么是数据结构
数据结构是数据的数据管理和组织的格式,使用目的是为了更高效的访问和修改数据。
1、数据结构的组成方式
1.1 线性结构
包含数组、链表、栈、队列等
1.2 树形结构
比较常用的是二叉树、二叉堆等
1.3 图
比较复杂的数据结构,在图中会呈现出多对多的关联关系。
1.4 其他类型数据结构
基本都是由基本数据结构演变而来,作用是为了解决某些特定问题。例如哈希表、跳表等。
三、数据结构和算法的关系
数据结构是算法的基石。如果算法是高速公路上行驶的汽车,那么数据结构就是高速公路。
不同的算法会采用不同的数据结构。例如:①堆排序算法中用的是二叉堆数据结构。②冒泡排序算法用的是数组数据结构。
四、算法的好坏标准
一次代码运行的时间和所占用的内存决定的这个代码的好坏。
算法最重要的两个标准:空间复杂度、时间复杂度。
复杂度也叫渐进复杂度,包括时间复杂度和空间复杂度,用来分析算法执行效率和数据规模之间的增长关系。
函数和复杂度的转换原则
① 如果是常量级,则使用常数1表示。
② 只保留函数中的最高阶项。
③ 如果最高阶项存在,则省去最高阶项前面的系数。
1、时间复杂度
时间复杂度是算法执行的时间成本
1.1 常见时间复杂度
1.1.1 O(n)
张三买了一屉包子,一屉包子中有10个,没三分钟吃掉一个。那么吃掉这一屉包子需要多久?
答案:3*10=30min。
如果有n个包子,可以记做T(n)=3n。转换为时间复杂度就是T(n)=O(n)
1.1.2 O(logn)
假设张三比较饿,所以买了16个包子,张三每5分钟吃掉一半的包子,也就是第一个5分钟吃了8个包子,第二个5分钟吃掉4个包子,以此类推。那么张三把包子吃的只剩一个的时候,需要多久呢?
答案:题目相当于让数字16不断的除以2,几次之后的结果为1。以2为底16的对数,也就是log2(16)。1次是5分钟,让5log2(16)=20。
如果有n个包子,可以记做T(n)=5log2(n),时间复杂度为T(n)=O(logn)
1.1.3 O(1)
张三买了n屉包子和1个鸡蛋,张三每2分钟吃掉1个鸡蛋。那么张三吃掉整个鸡蛋需要多久呢?
答案:2分钟
也就是无论多少个包子,张三只吃一个鸡蛋,那么吃鸡蛋这个行为的数学公式可以表述为T(n)=2,转换为时间复杂度T(n)=O(1)
1.1.4 O(n2)
张三买了一屉包子10个,吃掉第一个包子的时候需要花费1分钟,吃掉第二个包子的时候需要花费2分钟,吃掉第三个包子的时候需要花费3分钟,以此类推,每吃掉1个包子,所花费的时间就比上一次多1分钟,那么张三吃掉一屉包子需要多久呢?
答案:1+2+3+4+5+6+7+8+9+10=55
如果有n个包子,
T
(
n
)
=
1
2
n
2
+
1
2
T(n)=\frac 12n^2+ \frac 12
T(n)=21n2+21
转换为时间复杂度为T(n)=O(n2)
1.1.5 时长对比
如果n足够大:
O
(
1
)
<
O
(
l
o
g
n
<
O
(
n
)
<
O
(
n
2
)
)
O(1)<O(logn< O(n)<O(n^2))
O(1)<O(logn<O(n)<O(n2))
1.2 其他形式的时间复杂度
O ( n l o g n ) 、 O ( m n ) 、 O ( 2 n ) 、 O ( n ! ) 等 等 O(nlogn)、O(mn)、 O(2^n)、O(n!)等等 O(nlogn)、O(mn)、O(2n)、O(n!)等等
2、空间复杂度
在执行一段代码的时候,会用到一些中间数据,中间数据所占用内存空间的大小就是空间成本,描述空间成本的方法叫空间复杂度
2.1 常见的空间复杂度
2.1.1 常量空间O(1)
当算法的存储空间大小固定,和输入规模没有直接关系的时候,空间复杂度为O(1)
public static void method(int n)
{
int var = 3;
---
}
2.1.2 线性空间O(n)
算法分配的空间是一个线性集合,例如数组,并且集合大小和输入的数值n成正比,那么空间复杂度就是O(n)
public static void method(int n)
{
int[] var = new int[n];
---
}
2.1.3 二维空间O(n2)
算法分配的空间是一个二维数组集合的时候,并且集合大小和宽度都与输入的数值n成正比,那么空间复杂度就是O(n2)
public static void method(int n)
{
int[][] matrix = new int[n][n];
---
}
2.1.4 递归空间O(n)
递归是一个比较特殊的场景,虽然递归代码中并没有显示的声明变量或集合,但是计算机在执行程序时,会专门分配一块内存,用来存储“方法调用栈”
方法调用栈有入栈和出栈2个行为。当执行一个新的函数时,执行入栈操作,把调用的方法和参数信息压入栈中。当方法返回的时候,执行出栈操作,把调用的方法和参数信息从栈中弹出。
纯粹的递归空间也是线性O(n)的。
public static int method(int n)
{
if (n == 1)
{
return 1;
}
return n + method(n-1);
}