数据结构和算法第一篇

本文探讨数据结构和算法的重要性,特别是在优化代码效率和节省内存方面。介绍了复杂度分析,包括时间复杂度和空间复杂度的概念,强调了大O复杂度表示法,并详细阐述了分析方法,如最大循环原则、加法原则和乘法原则。同时列举了常见复杂度级别,以及如何分析不同场景下的复杂度。
摘要由CSDN通过智能技术生成

常见的复杂度分析

 

No.1 什么是数据结构和算法?

数据结构就是一组数的存储结构,而算法是怎么将这组数进行存储,是进行更深层次的优化存储。.................

数据结构和算法的作用,我们平时写的代码不够完美,可能占用内存较高,运行消耗时间也很长。

 

No.2 复杂度分析

数据结构和算法是解决代码的“快”和“省”的问题,如何让代码运行的更快,更能节省程序运行时占用的内存空间等,所以代码的执行效率是一个非常重要的指标。

复杂度分析相比于性能测试,复杂度不依赖执行环境,成本较低,效率高。

 

No.3 大O复杂度表示法

复杂度分为时间复杂度和空间复杂度,时间复杂度代表了数据量的递增,代码执行后的时间也会随之递增的,用timer表示代码执行一次的使用时间,注意这里并不能正真意义上去代表代码执行一次使用的时间,而是表示着下面可以观察这组代码来分析时间复杂度。

public class Demo1{
    public int sum(int n){
        int sum = 0; // 1次
        for(int i=0;i<=n;i++){ // i=0一次,i<=n n次 ,i++ n次
            sum = sum+i; // n次
        }
        return sum; // 一次
    }
}

分析:上面整个代码从开始执行到结束后,看方法体内部的代码,循环外为代码执行了两次,内部循环体总共执行了3n+1次,所以整个代码的时间复杂度为timer*(3n+3)。时间复杂度只描述了对数据量n的处理,当数据量n逐渐增大时,处理的时间也会随之增大的一个变化趋势,这就是时间复杂度的分析。

注:当数据量n变得很大时,公式中的低阶,常量,系数三部分并不能左右其增长趋势,反之,影响变化趋势的却是公式中的高阶,当数据量足够大的时候,可以忽略公式中的低阶数据了。

一般的,可以将时间复杂度从简表示,例如上面的时间复杂度可以表示为O(n),最大系数没有高阶次。

 

No.4 复杂度的分析方法

最大循环原则:大O复杂度法只表示一种变化趋势,公式中的低阶,常量,系数三个部分都不会随着n的增长而影响整个数据的变化趋势,我们只需要记录一个最大的量级就可以了,因此分析一个算法或者一个代码执行的次数最大的那一段代码即可。

加法原则:当一段代码中出现多个循环,或者其他的代码相加起来的情况时,我们只需要考虑用系数最大的那个时间复杂度,其他系数比较小的可以不用加到里面来。例如:

public int sum(int n){

	int sum1 = 0;
	int p = 0;
	for(;p<=100;p++){
	  sum1=sum1+p;
	}  
	
	int sum2 = 0;
	int q =1 ;
	for(;q<n;q++){
		sum2 = sum2+q;
	}
	
	int sum3 = 0;
	int i = 1;
	int j = 1;
	for(;i<=n;i++){
	     j=1;
	     for(;j<=n;j++){
	     	sum3 = sum3+i*j;
	     }
	}
	return sum1+sum2+sum3;
}

分析后这段代码的时间复杂度是O(n^2)!

乘法原则:在一段代码中有循环,循环中还能调用其他的方法的时候,这个时候就可以使用乘法原则来判断时间复杂度了。

public  int sum(int n ){
	int ret = 0;
	int  i  = 1;
	for(;i<n;i++){
		ret = ret+func(i);
	}
	return ret;
	
}

public int func(int n){
	int sum = 0;
	int i = 1;
	for(;i<n;i++){
		sum = sum + i;
	}
	return sum;
}

注:方法中有方法调用,第一个复杂度是O(n),第二个也是O(n),用乘法思想就是O(n^2)

No.5 常见的复杂度

常数 O(1), 线性 O(n), 对数 O(log n), 线性对数 O(n*log n), 等。

No.6 几种复杂度的分析

对数:o(log n)

public void Demo1(int n){
		int i = 1;
		while(i<=n){
			i=i*2;
		}
}

分析:循环内是进行2倍数的扩大化,假设执行到第k次后达到n了,次复杂度就可以表示为 O(log n),也就是对数运算方法。那对于O(n*log n)呢? 我们可以分析,如下面的代码:

public void Demo2(int n ){
		int i = 1;
		for(;i<=n;i++){
			i=i+Demo3(n);
		}
}

public void Demo3(int n){
		int i = 1;
		while(i<=n){
			i=i*2;
		}
}

此方法中使用了方法调用,一个方法里面调用了另一个方法,对第一段代码来说,复杂度为O(n),对第二段代码来说,复杂度是O(log n),所以综合起来复杂度就是O(n*log n).

No.7 空间复杂度

时间复杂度表示了代码执行时间随着数据N增长的一个变化趋势,空间复杂度表示了代码执行所需要的额外空间和数据n增长的一个变化趋势,描述了他们之间的一个增长关系。

public void Demo5(int n){
		int i = 1;
		int sum = 0;
		for(;i<=n;i++){
			sum=sum+i;
		}
}

public void Demo6(int n){
     	int i = 0;
    	int [] a = new int [n];
    	for(;i<n;i++){
            a[i]=i*i;
        }
    	for(i=n-1;i>=0;i--){
            System.out.println(a[i]);
        }
}

分析:这两段代码都带有循环,第一,数据n的代入并不影响代码运行时所需要的空间,是一个常数级的空间复杂度,n的增长并不印象内存空间的开辟。第二段代码,很明显代码中定义了一个数组,而且数组初始化长度是根据数据n的大小而决定的,当n增大的时候,代码运行的空间复杂度也随之增大,这是一个相对的关系,所以Demo6的代码空间复杂度是随着n的增大而增大的,这是一个O(n)的空间复杂度。

有不对的地方还希望大家共同指正!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值