衡量一个算法的复杂度:
-
时间复杂度
-
空间复杂度
-
算法的时间复杂度和空间复杂度合称为算法的复杂度
时间复杂度
一般来说,一个算法执行所消耗的时间从理论上是算不出来的,只有通过上机运行才能测试出来。当然,我们也没
必要知道一个算法它具体执行的时间是多少,而我们又知道,一个算法花费的时间与算法中语句的执行次数是成正
比的。哪个算法语句执行的次数多,它花费的时间就多。
void Test(int n)
{
int count = 0;
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
count++;
}
}
for(int k = 0; k < 2*n; k++)
{
count++;
}
int icount = 10;
while(icount--)
{
count++;
}
}
语句的总执行次数:f(n)=n^2 + 2*n + 10
时间复杂度实际上就是一个函数,该函数计算的是执行基本操作的次数
大O渐进表示法
一个算法语句总的执行次数是关于问题规模N的某个函数,记为分f(N),N称为问题的规模。语句总的执行次数
记为T[N],当N不断变化时,T[N]也在变化,算法的执行次数的增长速率和f(N)的增长速率相同。
则T[N]=O(f(N)),称O(f(N))为时间复杂度的O渐进表示法。
空间复杂度
一个程序的空间复杂度是指运行完一个程序所需内存的大小。利用程序的空间复杂度,可以对程序的运行所需要
的内存多少有个预先估计。一个程序执行时除了需要存储空间和存储本身所使用的指令、常数、变量和输入数据
外,还需要一些对数据进行操作的工作单元和存储一些为现实计算所需信息的辅助空间。程序执行时所需存储空
间包括以下两部分。
(1)固定部分。这部分空间的大小与输入/输出的数据的个数多少、数值无关。主要包括指令空间(即代码空间
)、数据空间(常量、简单变量)等所占的空间。这部分属于静态空间。
(2)可变空间,这部分空间的主要包括动态分配的空间,以及递归栈所需的空间等。这部分的空间大小与算法
有关。
一个算法所需的存储空间用f(n)表示。S(n)=O(f(n)) 其中n为问题的规模,S(n)表示空间复杂度。
空间复杂度:函数中创建对象的个数关于问题规模函数表达式,一般情况用O的渐进表示法表示。
int Bin_search(int arr[], int len, int x)
{
//二分法查找,返回数据在数组中对应的下标值,若不存在,返回-1
//以循环方式实现
int left = 0;
int right = len - 1;
int mid = 0;
while (left <= right)
{
mid = left + (right - left) / 2;
if (arr[mid] == x){
return mid;
}
else if (arr[mid] < x){
left = mid + 1;
}
else{
right = mid - 1;
}
}
return -1;
}
int main(void)
{
int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int len = sizeof(arr) / sizeof(arr[0]);
printf("%d\n", Bin_search(arr, len, 5));
return 0;
}
int Binary_search(int arr[], int left, int right, int x)
{
//二分法查找,递归方式实现
int mid = left + ((right-left)>>1);
while (arr[mid] != x)
{
if (arr[mid] < x){
left = mid + 1;
mid = left + (right - left) / 2;
Binary_search(arr, left, right,x);
}
else{
right = mid - 1;
mid = left + (right - left) / 2;
Binary_search(arr, left, right,x);
}
}
return mid;
}
int main()
{
int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int len = sizeof(arr) / sizeof(arr[0]);
int left = 0;
int right = len - 1;
printf("%d\n", Binary_search(arr,left, right, 3));
printf("%d\n", Binary_search(arr, left, right,10));
system("pause");
return 0;
}
- 非递归方式:时间复杂度O(log2(n))空间复杂度O(3)
- 递归方式:时间复杂度O(log2(n))空间复杂度O(1)
下面是斐波那契数列的递归方式与非递归方式的实现:
#define N 20
int main(void)
{
int f0=1,f1=1,fn,i;
printf("%4d%4d",f0,f1);
for(i=0;i<N;i++)
{
fn=f0+f1;
printf("%9d",fn);
f0=f1;
f1=fn;
}
return 0;
}
int fib(int n)
{
if(n <= 2)
return 1;
else
return fib(n-1)+fib(n-2);
}
- 非递归方式:时间复杂度O(n)空间复杂度O(4)
- 递归方式:时间复杂度O(2^n) 空间复杂度O(1)
递归方式的优化算法(尾递归)
http://www.nowamagic.net/librarys/veda/detail/2325
long Fib(long first,long second,long n)
{
if(N < 3)
return 1;
if(n == 3)
return first + second;
return Fib(second,first+second,n-1);
}
这样,时间复杂度便降到了O(n).
生活允许我们撒娇,但不可以任性,因为。。。任性往往要付出足够的代价。