引入原因
- 复杂度是衡量算法性能的重要指标之一,程序员在设计代码时应该从时间和空间两个角度去考虑代码的结构。虽然在计算机硬件在日新月异的提高性能,但在某些情况下,如在高负载或者数据规模很大时,时间和空间复杂度会成为算法性能的瓶颈。
- 从程序员自我进阶角度,编码不仅限于实现业务逻辑,而要去追求在尽可能少的资源下,完成功能的执行。以这个标准去要求自己,才可能成为一名优秀的程序员。
时间复杂度
1.分类
- 最坏时间复杂度:程序执行最坏情况下的耗时,执行时间最长。
- 最好时间复杂度:程序执行最好情况下的耗时,执行时间最短。
- 平均时间复杂度:累计所有情况下执行耗时,取平均值。
- 均摊时间复杂度:加权平均执行时间。
2. 表示方法
: 代码执行时间
: 每行代码执行次数的总和
3.分析方法
- 只关注循环执行次数最多的一段代码
- 加法法则:总复杂度等于量级最大的那段代码的复杂度
- 乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积
4.计算时间复杂度
// 简单冒泡排序(升序实现)
void BubbleSort(int *parr, int length)
{
for (int i = 0; i < length; i++)
{
for (int j = i+1; j < length; j++)
{
if (parr[j] < parr[i]){ swap(parr[j], parr[i]);} // swap(i,j)交换数值
}
}
}
上述代码是简单冒泡排序的一种实现,分析该段代码的时间复杂度,对于两层for循环,显然应该用乘法法则。
时间复杂度:
// 优化冒泡排序(升序实现)
void BubbleSort(int *parr, int length)
{
for (int i = 0; i < length; i++)
{
bool flag=false;
for (int j = i+1; j < length; j++)
{
if (parr[j] < parr[i]){ swap(parr[j], parr[i]); flag=true; } //swap(i,j)交换数值
}
if(flag=false) return;
}
}
上述是改进版的冒泡排序实现,当第二个for循环遍历执行一次后,如果标记为假,则表示排序完成。因此在待排序已经是升序排列时,此时,有最好的时间复杂度:
空间复杂度
void print(int n){
int i=0;
int[] parr=new int[n]; // 申请大小为n的int类型数组
for(int i=0;i<n;i++){
a[i]=i*i;
}
for(int i=n-1;i>=0;--i){
cout<<a[i]<<endl;
}
}
上述代码中,申请了大小为n的int类型数组,除此之外,剩余的代码没有占用更多的空间,即和数据规模无关,因此整段代码的空间复杂度为O(n)。
常见的空间复杂度有O(1)、O(n)、O(n*n),O(logn)、O(n*logn)这样的空间复杂度不太常见。