
日升时奋斗,日落时自省
目录
一、首先就是什么数据结构
从字面上理解就是 数据+结构
简单讲:组织数据,计算机储存,所有数据的集合
数据结构的开始我们要了解什么呢,数据结构不就是为了我们能够让我们的代码更快,更节省内存,那如何衡量一个算法的好坏呢
2、算法效率
我们注意的是时间和空间上,时间效率被称为时间复杂度,空间效率被称为空间复杂度
时间复杂度是衡量算法的运行速度,空间复杂度是衡量算法所需的额外空间
3、时间复杂度
3.1时间复杂度的基本概念
算法的时间复杂度是一个数学函数,算法中的基本操作的执行次数,为算法的时间复杂度。
3.2大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--) > 0) { count++; } System.out.println(count); }计算一下当前的代码的时间复杂度
详细计算下来的次数=N^2+2N+M(温馨提示^这个符号是次幂)
这里大概执行次数,那么这里我们使用大O的渐进表示法
那当N^2接近无穷大时,数学极限的思想就可以看出2N+M就可以忽略不计了
3.3大O的渐进表示方法
(1)、所有的常数次数都可以替换成1。 O(1)
例如
void func4(int N) { int count = 0; for (int k = 0; k < 100; k++) { count++; } System.out.println(count); }
该代码执行次数为100次,但是这里时间复杂度千万不能写成O(100) ,这里就是常数次数了应该写为O(1)
(2)、在修改后的运行次数函数中,只保留最高阶项。
这个就比较好理解了,就是上面提及的代码运行了N^2+2N+M次数,只保留最高阶项,时间复杂度就是O(N^2)
(3)、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶
void bubbleSort(int[] array) { for (int end = array.length; end > 0; end--) { boolean sorted = true; for (int i = 1; i < end; i++) { if (array[i - 1] > array[i]) { Swap(array, i - 1, i); sorted = false; } } if (sorted == true) { break; } } }这是我们很常见到的冒泡方法代码块,计算当前的时间复杂度
当先看见就是两个for循环执行的东西,运行次数就是
(n-1)+(n-2)+(n-3)+....+0=n*(n-1)/2
=1/2*(n^2)-1/2
这是精确地计算结果,但是我们需要的是当前的以大O渐进表示去掉当前的常数项,和最高次幂前的常数:时间复杂度是O(N^2)
这里我们多加一点
最坏时间复杂度:拿排序来说,最坏的结果就是每次都行换位置,那O(N^2)
最好时间复杂度:本来就是排好的情况下,时间复杂度为O(N),第一个for循环只跑了一次
平均时间复杂度:将每一种遍历情况加起来除其个数
我们一般说的复杂度都是:最坏时间复杂度
3.4添加的使用例
(1)、我们来看一下该代码判断,运行多少次?
是一个递归代码
假设它N=3我们需要的是递推两次,可以推出该代码运行了N-1次
时间复杂度:O(N)
(2)、
int fibonacci(int N) { return N < 2 ? N : fibonacci(N-1)+fibonacci(N-2); }该代码是斐波那契函数的代码块
当前可以进行向下分很多次,直到最左侧等于1的时候就分完了
时间复杂度也就随着分的次数增加,当前递推了多少次
前三行基本可以看出是2^0、2^1、2^2、2^3
等比数列求和
运算次数的精确计算=2^N-1
时间复杂度:O(2^N)
4、空间复杂度
4.1空间复杂度的概念
临时占用存储空间大小的量度
空间复杂度也是通过大O渐进法表示的
用例题来解释空间复杂度如何计算
例题一
void bubbleSort(int[] array) { for (int end = array.length; end > 0; end--) { boolean sorted = true; for (int i = 1; i < end; i++) { if (array[i - 1] > array[i]) { Swap(array, i - 1, i); sorted = false; } } if (sorted == true) { break; } }我们还是拿冒泡方法的代码来说空间复杂度
作为形参传进来的数组可不算到空间复杂度里
当前的没有新创建空间所以空间复杂度O(1)
这里解释一下 :sorted为什么不算新创建的空间,因为他只创建了一次,就存在了,系统不会一直创建
例题二
public int[] fibonacci(int n) { long[] fibArray = new long[n + 1]; fibArray[0] = 0; fibArray[1] = 1; for (int i = 2; i <= n ; i++) { fibArray[i] = fibArray[i - 1] + fibArray [i - 2]; } return fibArray; }该代码是斐波那契非递归的形势
该代码的空间复杂度:O(N)
为什么这里是O(N)因为这个地方
这行代码new了空间,所以所需空间就是N
例题三
long factorial(int N) { return N < 2 ? N : factorial(N-1)*N; }刚刚我们求过这个代码的时间复杂度
那空间复杂度呢,这个空间复杂度采用的是压栈
简单来看就是这样,递归了几次就开辟了多少空间
我们再接触一个特例
int fibonacci(int N) { return N < 2 ? N : fibonacci(N-1)+fibonacci(N-2); }如果是斐波那契的递归方法,空间复杂度又是多少
空间复杂度为O(N)
前面说到递推几次就可以就会开辟几个空间,这里会先开辟最大次数递归的空间数量,其他的递归都可以存放在该空间下(公用一块能支撑最大递归次数的空间)
例如斐波那契方法的递归最大次数是最左侧这一条递归链,n-1次
本文深入探讨了数据结构的基础概念,强调其在优化代码效率中的作用。文章详细阐述了算法效率的两个关键指标——时间复杂度和空间复杂度,并通过实例解释了如何使用大O渐进表示法进行计算。举例说明了冒泡排序、斐波那契数列等常见算法的时间和空间复杂度,并解释了如何考虑最好、最坏和平均时间复杂度。此外,还介绍了空间复杂度的计算,包括递归和数组分配空间的情况。








1038

被折叠的 条评论
为什么被折叠?



