数据结构前言:
1. 什么是数据结构
打个比方来说不同的数据就相当于不同的书籍,我们经常在图书馆可以看到不同类别的书籍会被整理放在书架上方便查看存放,数据结构就是一种计算机存储管理数据的方式。
2. 什么是算法
算法就是一系列的计算步骤,将我们输入的需要计算的数据转化成输出的结果
算法的时间复杂度和空间复杂度:
1. 为什么要计算算法的时间复杂度和空间复杂度
时间复杂度和空间复杂度可以反应一个算法的好坏,好的算法执行能力强,快;差的算法执行能力弱,慢。比如我们打开一个应用的界面,你一打开就进入了首页,还有种情况你打开等了半天还是在封面广告界面,我相信大多数用户都喜欢前者,算法也是如此,好算法计算机1ms就执行出结果,坏的算法往往执行半天,程序一直在跑,甚至于可能失败。
所以我们需要一些理论来衡量算法的优劣,时间复杂度和空间复杂度由此诞生。选择好的算法,往往在思考算法的过程中也可以锻炼我们的思维能力。
时间复杂度:
时间复杂度表面看起来好像跟时间有关,但其实不是计算算法跑了多少时间的,因为我们知道不同的电脑计算能力,跑程序有强弱之分,一个好的算法在老古董电脑上跑也需要很长的时间,所以为了防止这样的情况误差发生,我们的时间复杂度计算的是一个算法执行了多少次命令操作!
如:
int main()
{
int a =0;
printf("%d", a);
return 0;
}
从进入主函数内部我们总共执行了3次指令,我们称这样的时间复杂度为 O(1); -> 后面会解释为啥不是 O(3)
为了方便我们判断,我们只选取最大的执行项数,N^2, 以阶级区分,为什么怎么做呢?,首先我们先了解有多少种时间复杂度:
因为目前计算机的计算速度基本上都是以亿为单位的,当计算的数量上去之后,一些细枝末节就不予考虑了
拿 F(N) = N^2 + 2*N + 10 举例
当N=10时, F(N) =100+30
当N=100时, F(N) =10000+210
当N=1000时, F(N) =1000000+2010
我们称这种取舍的表示符号O() 为大O的渐进表示法
时间复杂度计算的是最坏的情况,这样可以保证我们的效率最坏也就是那样,知道预期的结果。
// 大家可以根据以下代码测试cpu性能
// 计算出自己计算机的计算能力
int main()
{
long long int x = 0;
int begin1 = clock();
int n = 10000;
for (int i = 0; i < n; ++i)
{
for (int i = 0; i < n; ++i)
{
++x;
}
}
int end1 = clock();
printf("%lld\n", x);
printf("%d\n", end1 - begin1);
return 0;
}
下面我们来个题目分析:
题目一:
题目二:
答案:O(N) -> 2*N+10
题目三:
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(N^2) -> N^2+2*N+10
题目四:
// 计算Func3的时间复杂度?
void Func3(int N, int M)
{
int count = 0;
for (int k = 0; k < M; ++k)
{
++count;
}
for (int k = 0; k < N; ++k)
{
++count;
}
printf("%d\n", count);
}
答案:O(M+N)
题目五:
// 计算Func4的时间复杂度?
void Func4(int N)
{
int count = 0;
for (int k = 0; k < 100; ++k)
{
++count;
}
printf("%d\n", count);
}
答案: O(1) ->100
题目六:
// 计算BubbleSort的时间复杂度?
void BubbleSort(int* a, int n)
{
assert(a);
for (size_t end = n; end > 0; --end)
{
int exchange = 0;
for (size_t i = 1; i < end; ++i)
{
if (a[i - 1] > a[i])
{
Swap(&a[i - 1], &a[i]);
exchange = 1;
}
}
if (exchange == 0)
break;
}
}
答案:O(N^2) -> N*(N+1)/2
空间复杂度:
同理空间复杂度也不是去真的算空间的大小,而是计算创建了的变量个数。其他方面同理于时间复杂度。
题目一:
// 计算BubbleSort的空间复杂度?
void BubbleSort(int* a, int n)
{
assert(a);
for (size_t end = n; end > 0; --end)
{
int exchange = 0;
for (size_t i = 1; i < end; ++i)
{
if (a[i - 1] > a[i])
{
Swap(&a[i - 1], &a[i]);
exchange = 1;
}
}
if (exchange == 0)
break;
}
}
答案:题目一使用了常数个额外空间,所以空间复杂度为 O(1)
题目二:
// 计算Fibonacci的空间复杂度?
// 返回斐波那契数列的前n项
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;
}
答案:题目二动态开辟了N个空间,空间复杂度为 O(N)
题目三:
// 计算阶乘递归Fac的空间复杂度?
long long Fac(size_t N)
{
if (N == 0)
return 1;
return Fac(N - 1) * N;
}
答案:题目三递归调用了N次,开辟了N个栈帧,每个栈帧使用了常数个空间。空间复杂度为O(N)
其他关于数据结构的题目分析:
以下的图片内容我小编平时写一些算法题目的思考,大家可以选取看取: