【数据结构】(一)数据结构入门:数据结构、算法,时间复杂度和空间复杂度

1.什么是数据结构?

数据结构(Data Structure) 是计算机存储、组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合。

提到数据结构,就不得不提到算法,不论是在学习还是工作过程中,数据结构与算法可以说占据了半壁江山,可谓是重中之重,因此学好是很有必要的。

算法(Algorithm): 就是定义良好的计算过程,其取一个或一组的值为输入,并产生出一个或一组值作为输出。简单来说算法就是一系列的计算步骤,用来将输入数据转化成输出结果。

对于数据结构的学习而言,要多注重代码方面的练习,遇到抽象难懂的问题时注意画图和思考。

2.时间复杂度和空间复杂度

如何评价一段代码或一个程序的好坏?我们通常以算法效率为指标;算法效率分析分为两种:第一种是时间效率,第二种是空间效率。时间效率被称为时间复杂度,而空间效率被称作空间复杂度

2.1 时间复杂度

2.1.1定义

时间复杂度主要衡量的是一个算法的运行速度。在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。但一个算法执行所耗费的时间是不能够准确计算的,它与运行时的环境有关,换句话说同一个程序在不同机器上运行的时间是有差别的;因此引入了时间复杂度的概念:一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法的时间复杂度。

2.1.2 大O的渐进表示法

我们来看一段代码,在Func1运行过程中,其基本语句++count的执行次数F(N)=N^2+2*N+10

  • 当N = 10,F(N) = 130;
  • N = 100 ,F(N) = 10210;
  • N = 1000, F(N) = 1002010;
    在实际计算时间复杂度时,我们并不一定要精确地计算实际的执行次数,则只需要计算大概的执行的次数,因此时间复杂度一般用大O渐进表示法来表示。
void Func1(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 M = 10;
	while (M--)
	{
		++count;
	}
	printf("%d\n", count);
}

大O符号(Big O notation):是用于描述函数渐进行为的数学符号。
推导大O阶方法:
先推导出基本语句执行次数的函数表达式(如果可以),然后应用下面的方法进行推导;不过很多情况下某一算法基本语句的执行次数的函数表达式并没有像例子中那么容易得到,那么你必须对算法的原理足够熟悉,知道算法进行的是怎样的操作,然后根据操作的次数推导得到一个较为接近的表达式,再应用以下法则:
1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数函数中,只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。
使用大O的渐进表示法以后,Func1的时间复杂度为O(N^2)

  • N = 10, F(N) = 100;
  • N = 100, F(N) = 10000;
  • N = 1000 ,F(N) = 1000000;

通过上面我们发现大O渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。
另外有些算法的时间复杂度存在最好、平均和最坏情况:
最坏情况:任意输入规模的最大运行次数(上界)
平均情况:任意输入规模的期望运行次数
最好情况:任意输入规模的最小运行次数(下界)
例如:在一个长度为N数组中搜索一个数据x
最好情况:1次找到
最坏情况:N次找到
平均情况:N/2次找到
在实际中一般关注的是算法运行时最坏的情况,因此在数组中搜索指定元素的时间复杂度是O(N)

2.1.3 注意

大O表示法只是复杂度的一种渐进表示法,因此在决定使用哪些算法的时候,不是时间复杂越低的越好(因为简化后的时间复杂度忽略了常数项等等);而是要考虑数据规模,如果数据规模很小有时甚至用O(n^2)的算法比O(n)的更合适(在有常数项的时候)。

这里就又涉及到大O的定义,因为大O就是数据量级突破一个点且数据量级非常大的情况下所表现出的时间复杂度,这个数据量也就是常数项系数已经不起决定性作用的数据量。所以我们说的时间复杂度都是省略常数项系数的,是因为一般情况下都是默认数据规模足够的大.

2.2 空间复杂度

2.2.1 定义

而空间复杂度主要衡量一个算法所需要的额外空间。
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度 。空间复杂度不是程序占用了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。空间复杂度计算规则基本跟实践复杂度类似,也使用大O渐进表示法。

2.2.2 几个计算实例

实例1 计算BubbleSort的空间复杂度?(内部排序)

void BubbleSort(int* a, int n)
{
	assert(a);
	for (int i = 0; i < n-1 ; i++)
	{
		int flag=0;
		for (int  j = 0; j < n-1-i; j++)
		{
			if (a[j] > a[j+1])
			{
				Swap(&a[j], &a[j+1]);
				flag = 1;
			}
		}
		if (!flag)
			break;
	}
}

实例2 计算Fibonacc(求斐波那契数列的第n项)的空间复杂度?(malloc)

long long* Fibonacci(size_t n)
{
	if(n==0)
		return NULL;
	long long * fibArray =(long long *)malloc((n+1) * sizeof(long long));
	fibArray[0] = 0;
	fibArray[1] = 1;for (int i = 2; i <= n ; ++i)
	{
		fibArray[i ] = fibArray[ i - 1] + fibArray [i - 2];
	}
	return fibArray ;
}

示例3 计算递归求阶乘Factorial的空间复杂度?

long long Factorial(size_t N)
{
	if(N <= 2)
		return 1;
	return N*Factorial(N-1);
}

实例答案及分析:
1.实例1使用了常数个额外空间,所以空间复杂度为 O(1),一般没有额外开辟空间的空间复杂度都是O(1),如果需要动态开辟,则开辟空间的大小往往是不确定的,因此其值通常都不是O(1)。
2. 实例2动态开辟了N个空间,空间复杂度为 O(N)。
3. 实例3递归调用了N次,开辟了N个栈帧,每个栈帧使用了常数个空间。空间复杂度为O(N)。对于出现递归的情形,时间/空间复杂度=每次递归的时间/空间复杂度*递归深度

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第一章 绪论作业答案(共50分) 一、分析如下程序中 (1)~ (10)各语句的频度。(每个1分,共10分) Ex( ) { int i , j , t ; (1) for( i=1 ; i<10 ; i++) //n = (2) printf(“\n %d” , i ); //n = (3) for(i=1; i<=2; i++) //n = (4) printf(“\n”); //n = (5) for(i=1; i<=9; i++) //n = { (6) for(j=1; j <= i ; j++) //n = { (7) t = i * j ; //n = (8) printf(“]”,t); //n = } (9) for(j=1; j 0) { if(x > 100) {x -= 10 ; y -- ;} else x ++ ; } 问if 语句执行了多少次?(2分) y--执行了多少次?(2分) x ++执行了多少次?(2分) 三、回答问题(共25分) 书中16页的起泡排序如下: void bubble_sort(int a[],int n){ //将a中整数序列重新排列成自小至大有序的整数序列。 for(i=n-1,change=TRUE;i>=1&&change;--i){ change=FALSE; for(j=0;ja[j+1]{a[j]<-->a[j+1];change=TRUE; } } }//bubble_sort 1.(共15分)分析该算法的最佳情况 ,最坏情况和平均情况下各自的时间复杂度(给出分析思路与过程)。 (1) 最佳情况的时间复杂度分析(5分): (2) 最坏情况的时间复杂度分析(5分): (3) 平均情况的时间复杂度分析(5分): 2.(共10分)比较与C语言书中的起泡排序异同,并从时空效率角度说明谁更优。 四、完成如下选择题(每3分,共9分)。 1. 设f为原操作,则如下算法时间复杂度是( )。 for (i = 1; i*i=1;i--) for(j=1;jA[j+1]) A[j]与A[j+1]对换; 其中n为正整数,则算法在最坏情况下的时间复杂度为( )。 A.O(n) B.O(nlog2n) C. O(n3) D. O(n2)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值