1.数据结构
数据结构是计算机存储,组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合。
2.算法效率
算法效率分为两种:第一种是时间效率,第二种是空间效率。时间效率被称为时间复杂度,而空间效率 被称作空间复杂度。 时间复杂度主要衡量的是一个算法的运行速度,而空间复杂度主要衡量一个算法所需要 的额外空间。随着科技的发展,如今已经不需要再特别关注一个算法 的空间复杂度。
3.时间复杂度
3.1 时间复杂度的定义:
在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法 的时间复杂度。
3.2 大O的渐进表示法
大O符号(Big O notation):是用于描述函数渐进行为的数学符号。
推导大O阶方法:
1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数函数中,只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。
实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这 里我们使用大O的渐进表示法。大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。
另外有些算法的时间复杂度存在最好、平均和最坏情况:
最坏情况:任意输入规模的最大运行次数(上界)
平均情况:任意输入规模的期望运行次数
最好情况:任意输入规模的最小运行次数(下界)
3.3 常见时间复杂度计算举例
实例1:
// 计算BubbleSort 的时间复杂度?
void BubbleSort(int *arr, int sz)
{
int i = 0;
int j = 0;
assert(arr);
for (i = sz; i > 0; --i)
{
int exchange = 0;
for (j = 1; j < i; ++j)
{
if (arr[j - 1] > arr[j])
{
int temp = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = temp;
exchange = 1;
}
}
if (exchange == 0)
break;
}
}
基本操作执行最好N次,最坏执行了(N*(N+1)/2次,通过推导大O阶方法+时间复杂度一般看最坏,时间复杂度为 O(N^2) 。
实例2:
int BinarySearch(int arr[], int key, int sz)
{
int left = 0;
int right = sz - 1;
while (left <= right)
{
int mid = left + (right - left) / 2;
if (arr[mid] < key)
{
left =mid + 1;
}
else if (key < arr[mid])
{
right = mid - 1;
}
else
return mid;
}
return -1;
}
基本操作执行最好1次,最坏O(logN)次,时间复杂度为 O(logN) (可通过折纸查找的方式理解logN是怎么计算出来的。)
(ps:logN在算法分析中表示是底 数为2,对数为N。有些地方会写成lgN。)
实例三:
int fib2(int n)
{
if (n <= 2)
return 1;
else
return fib2(n - 1) + fib2(n - 2);
}
基本操作递归了2N次,时间复杂度为O(2N)。(可通过画图递归栈帧的二叉树的方法。)
4.空间复杂度
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度 。空间复杂度不是程序占用了多少 bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。空间复杂度计算规则基本跟实践复杂度类似,也使用大O渐进表示法。
1.BubbleSort使用了常数个额外空间,所以空间复杂度为 O(1) 。
2.斐波那契数动态开辟了N个空间,空间复杂度为 O(N) 。
3.阶乘递归递归调用了N次,开辟了N个栈帧,每个栈帧使用了常数个空间,空间复杂度为O(N) 。