目录
首先我们讲解一下什么是数据结构(从今天开始,博主要开始学习数据结构啦,以后再学习算法会给大家分享更多深入浅出的干货!)
这个听起来就很高大上的名字,其实是计算机存储和组成数据的方式,他是一些数据元素的组合,这些元素之间相互存在着一些一种或者多种的联系
我们学习数据结构是为了更好的了解计算机工作的原理,实现更好的人机交流
和数学公式一样,其实算法就是对于某一类计算机问题的 总结好的 特定实现思路
比如说我现在做到一个题目,需要用到排序
这时候我们就想到一些排序的方法,这些方法就相当于算法,当然算法不是这么简单的,也有很多很有技巧的,这里只是为了举例子
所以算法就是对于某一种特定问题(比如排序)的具体实现形式(堆排,快排,冒泡..)
首先解释什么是复杂度
对于两个算法(比如冒泡和堆排),应用到实际问题里谁更好呢?难道我说第一个更好就一定是对的吗
当然有一个衡量标准:复杂度
复杂度分为两种:时间,空间
但是主要说的还是时间复杂度
因为
时间复杂度:一个关于时间的函数,用来描述一个程序结束之后,某一部分被调用的次数,用俩衡量算法的效率
空间复杂度:程序运行需要额外开辟的空间的大小
而我们知道,随着时间的推移,现在的电脑内存已经很大了,空间复杂度已经不作为特别重要的参考依据,并且计算空间复杂度本身也不是特别复杂
- 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);
- }
现在是这样的过程,所以总共的次数应该是加起来
但是真的有这么麻烦吗
我们来看一段代码
- #include
- #include
- int main()
- {
- int begin=clock();
- int count = 0;
- for (size_t i = 0; i < 1000; i++)
- {
- count++;
- }
- int end = clock();
- printf("%d毫秒\n", end - begin);
- return 0;
- }
这个代码调用一个
其实如果我们把数字再改的更大
5毫秒真的是很短的时间,也就是在循环中,常数次的循环其实时间上来讲和一次没很大区别
这里我们用到一个大O渐进的方法来表示时间复杂度
常数次的调用定义为O(1)
大O渐进:
常数次都当成1次
系数不影响阶 可以忽略(O(2*N)=O(N))
抓大头 O(N^2+2*N+10)=O(N^2)
需要注意的是,以后我们计算时间复杂度的题目可能都不会给出代码,因为最重要的是思想,训练的就是给一个函数我立马就能想起来他用的什么方法实现的!!!!!
来看他的时间复杂度
这个时候我们就蒙了,这个字符到底出现在哪里我是不知道的
所以我们提出
最好情况:一次找到
最坏情况:(假设字符串长度为n)n次找到
平均情况:N/2
但是我们思考一下就知道,只有最坏情况才是真正有意义的
所以定义:在这种很蒙的情况,最坏情况对应的时间复杂度就是我们要找的时间复杂度
对于上面strchr函数的时间复杂度就是O(N)
再看一个
- void Func2(int N)
- {
- int count = 0;
- for (int k = 0; k < 2 * N; ++k)
- {
- ++count;
- }
- int M = 10;
- while (M--)
- {
- ++count;
- }
- printf("%d\n", count);
- }
根据大O渐进的方法,最后的时间复杂度就是O(N)
冒泡排序的时间复杂度是多少呢
- 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;
- }
- }
所以一个数字需要的次数分别是N ,N-1,N-2,...........,2
等差数列
就是O(N^2)
递归的时间复杂度呢
- long long Fac(size_t N)
- {
- if(0 == N)
- return 1;
- return Fac(N-1)*N;
- }
注意我们在这里不能以为往下递和往上推各有N次一共就是2*N
在递归函数的时间复杂度里,我们定义每次递归调用的函数次数累加就是最后的结果
3.2 空间复杂度
其实就是在程序里 定义的变量,或者新开辟空间的大小
还是符合大O渐进的规则
常数个还是令为O(1)
递归的空间复杂度就是每次递归调用的变量个数的累加,最多有多少个栈帧
不是递归就算一个栈帧里有多少个变量
- 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)
再来看斐波那契的空间复杂度
- 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+1,我们就知道别的常数个可以都不看了
O(N)
再看一个递归
- long long Fac(size_t N)
- {
- if(N == 0)
- return 1;
- return Fac(N-1)*N;
- }
一共创建了N+1个栈帧所以空间复杂度是O(N)
本文到此结束啦,相信你一定收获满满