我们编过不少代码,起初学习的时候我们习惯性的认为,只要代码能正确的运行就ok啦~很少考虑代码的优化带来的好处。今天说一下影响代码性能的两个重要指标--时间复杂度&空间复杂度。
时间复杂度:就是函数(指数学中的函数),具体执行的操作次数。通常用渐进表达式O()来表示。
空间复杂度:对象的个数。占用的空间。
算法分析一般分为三类:最坏情况、平均情况、最好情况。
算法分析要保持大局观,忽略掉常数,关注增长最快的表达式。
我们通常见到的算法的时间复杂度有:
斐波那契数列 (递归:O(2^N)非递归:O(N))
冒泡:O(N^2)
选择:O(N^2)
插入:O(N^2)
这里,主要举两个例子加以说明:
例子1:斐波那契数列
这就是著名的斐波那契数列啦。
下面讲讲斐波那契数列的两种算法,并剖析时间复杂度。
(1)递归算法
<span style="font-size:18px;">#include<iostream>
using namespace std;
#include<assert.h>unsigned long long Fib(long long n)
{assert(n >= 0);return n < 2 ? 1 : Fib(n-1)+Fib(n-2);
}
int main()
{cout<<Fib(5)<<endl;return 0;
}</span>
斐波那契数列的递归算法:由于每一步计算都调用两次递归,即Fib(n-1)= Fib(n-2)+ Fib(n-3) = Fib(n-3)+Fib(n-4)+Fib(n-4)+Fib(n-5)=... 这样下来,就相当于二叉树,所以其时间复杂度为O(2^N),空间复杂度为O(N)。
(2)非递归算法
#include<iostream>
using namespace std;
unsigned long long Fib(long long n)
{long long s0 = 0;long long s1 = 1;long long s = 0;for(int i = 0; i < n;i++){s1 = s0+s1;s0 = s1-s0; }return s1;
}int main()
{cout<<Fib(5)<<endl;return 0;
}
非递归算法只是在for循环里边数值的相互转换,其时间复杂度为O(N),空间复杂度为O(N)。
例子2:二分查找算法
二分查找的基本思想是将n个元素分成大致相等的两部分,a[n/2]与data做比较,如果data=a[n/2],则找到data,算法中止;如果data<a[n/2],则只要在数组a的左半部分继续搜索data,如果data>a[n/2],则只要在数组a的右半部搜索data.
(1)非递归算法
int BinaryFind(int arr[],int size,int data)
{int left = 0;int right = size-1;while(left <= right) //区间[]{int mid = left-(left-right)/2;if(arr[mid] > data){right = mid-1;}else if(arr[mid] < data){left = mid+1;}else{return mid;}}
<span style="white-space:pre"> </span>return -1;
}
int main()
{int arr[] = {1,3,5,7,9};int size = sizeof(arr)/sizeof(arr[0]);cout<<BinaryFind(arr,size,5)<<endl;return 0;
}
说起二分查找的非递归算法,我们还有另外一种实现。(要特别注意)
int BinaryFind(int arr[],int size,int data)
{int left = 0;int right = size; //区间[)while(left < right){int mid = left-(left-right)/2;if(arr[mid] > data){right = mid;}else if(arr[mid] < data){left = mid+1;}else{return mid;}}
<span style="white-space:pre"> </span>return -1;
}
int main()
{int arr[] = {1,3,5,7,9};int size = sizeof(arr)/sizeof(arr[0]);cout<<BinaryFind(arr,size,5)<<endl;return 0;
}
while循环循环的次数就是时间复杂度,即时间复杂度为O(LgN),空间复杂度为O(N)。
(2)递归算法
int BinaryFind_R(int arr[],int data,int left,int right)
{if(left <= right)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>int mid = left-(left-right)/2;
<span style="white-space:pre"> </span>if(arr[mid] > data)
<span style="white-space:pre"> </span>BinaryFind_R(arr,data,left,mid-1);
<span style="white-space:pre"> </span>else if(arr[mid] < data)
<span style="white-space:pre"> </span>BinaryFind_R(arr,data,mid+1,right);
<span style="white-space:pre"> </span>else
<span style="white-space:pre"> </span>return mid;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else
<span style="white-space:pre"> </span>return -1;
}
int main()
{int arr[] = {1,3,5,7,9};int size = sizeof(arr)/sizeof(arr[0]);int left = 0;int right = size - 1;cout<<BinaryFind_R(arr,6,left,right)<<endl;return 0;
}
递归时间复杂度为O(LgN)。