一、时间复杂度概念
1、时间复杂度概念
提到时间复杂度,第一时间想到的是算法,简单说,算法就是你解决问题的方法,而你用这个方法解决这个问题所执行的语句次数,称为语句频度或者时间频度,记为T(n)。
什么是时间复杂度,算法中某个函数有n次基本操作重复执行,用T(n)表示。
现在有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。
记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。
通俗一点讲,其实所谓的时间复杂度,就是找了一个同样曲线类型的函数f(n)来表示这个算法的在n不断变大时的趋势 。
当输入量n逐渐加大时,时间复杂性的极限情形称为算法的“渐近时间复杂性”。
2、计算时间复杂度的方法:
推导大O阶,我们可以按照如下的规则来进行推导,得到的结果就是大O表示法:
a.用常数1来取代运行时间中所有加法常数。
b.修改后的运行次数函数中,只保留最高阶项
c.如果最高阶项存在且不是1,则去除与这个项相乘的常数。
二、理解
1、常数阶:O(1)的算法是一些运算次数为常数的算法。例如:
temp=a;
a=b;
b=temp;
上面语句共三条操作,单条操作的频度为1,即使他有成千上万条操作,也只是个较大常数,这一类的时间复杂度为O(1)。
int sum = 0,n = 100; //执行一次
sum = (1+n)*n/2; //执行一次
System.out.println (sum); //执行一次
上面算法的运行的次数的函数为f(n)=3,根据推导大O阶的规则1,我们需要将常数3改为1,则这个算法的时间复杂度为O(1)。
2、线性阶:O(n)的算法是一些线性算法。例如:
sum=0;
for(i=0;i<n;i++)
sum++;
上面代码中第一行频度1,第二行频度为n,第三行频度为n,所以f(n)=n+n+1=2n+1。所以时间复杂度O(n)。这一类算法中操作次数和n正比线性增长。
3、对数阶:O(logn) 一个算法如果能在每个步骤去掉一半数据元素,如二分检索,通常它就取 O(logn)时间。例如:
int i=1;
while (i<=n)
i=i*2;
上面代码设第三行的频度是f(n), 则:2^f(n)<=n;f(n)<=log₂n,取最大值f(n)= log₂n,所以T(n)=O(log₂n ) 。
4、平方阶:O(n²)(n的k次方的情况)最常见的就是平时的对数组进行排序的各种简单算法都是O(n²),例如直接插入排序的算法。
sum=0;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
sum++;
第一行频度1,第二行n,第三行n²,第四行n²,T(n)=2n²+n+1 =O(n²)
5、平方阶:O(n²)
for(int i = 0; i < n; i++){
for(int j = i; j < n; j++){
printf("%d ",i);
}
}
//运行次数为(1+n)*n/2
//时间复杂度O(n^2)
6、时间复杂度按n越大算法越复杂来排的话:
常数阶O(1)、对数阶O(logn)、线性阶O(n)、线性对数阶O(nlogn)、平方阶O(n²)、立方阶O(n³)、……k次方阶O(n的k次方)、指数阶O(2的n次方)。
O(1)<O(logn)<O(n)<O(nlogn)<O(n²)<O(n³)<O(2ⁿ)<O(n!)
三、其他
1、冒泡程序—平方阶
public void sort(int[] args)
{
//第一层循环从数组的最后往前遍历
for (int i = args.length - 1; i > 0 ; --i) {
for (int j = 0; j < i; j++) {
//保证在相邻的两个数中比较选出最大的并且进行交换(冒泡过程)
if (args[j] > args[j+1]) {
int temp = args[j];
args[j] = args[j+1];
args[j+1] = temp;
}
}
}
}
上面算法的运行的次数函数为f(n)= (n-1)+(n-2)+(n-3)+(n-4)+…===>等差数列求和===> (n*(n-1))/2 ===>n^2/2-n/2===> f(n)=O(n^2)
2、选择排序
public void sort(int[] args)
{
int len = args.length;
for (int i = 0,k = 0; i < len; i++,k = i) { n
// 在这一层循环中找最小
for (int j = i + 1; j < len; j++) { n-1
// 如果后面的元素比前面的小,那么就交换下标,每一趟都会选择出来一个最小值的下标
if (args[k] > args[j]) k = j;
}
if (i != k) {
int tmp = args[i];
args[i] = args[k];
args[k] = tmp;
}
}
}
上面算法的运行的次数函数为f(n)= (n-1)+(n-2)+(n-3)+(n-4)+…===>等差数列求和===> (n*(n-1))/2 ===>n^2/2-n/2===> f(n)=O(n^2)
3、插入排序
public static void insertSort(int a[]){
int fn = 0;
int n = a.length;
int temp = 0;
printfArray(a);
for(int i = 1; i < n; i++){
for(int j = i; j >0; j--){
fn++;
if(a[j] < a[j-1]){ // 交换
temp = a[j];
a[j] = a[j-1];
a[j-1] = temp;
}else{
break;
}
}
printfArray(a);
}
printfArray(a);
System.out.println("语句频度:"+fn);
}
上面算法的运行的次数函数为f(n)= (n-1)+(n-2)+(n-3)+(n-4)+…===>等差数列求和===> (n*(n-1))/2 ===>n^2/2-n/2===> f(n)=O(n^2)