目录
1. 数据结构介绍
2.算法介绍
3.时间复杂度,(空间复杂度)
首先我们讲解一下什么是数据结构(从今天开始,博主要开始学习数据结构啦,以后再学习算法会给大家分享更多深入浅出的干货!)
这个听起来就很高大上的名字,其实是计算机存储和组成数据的方式,他是一些数据元素的组合,这些元素之间相互存在着一些一种或者多种的联系
我们学习数据结构是为了更好的了解计算机工作的原理,实现更好的人机交流
和数学公式一样,其实算法就是对于某一类计算机问题的 总结好的 特定实现思路
比如说我现在做到一个题目,需要用到排序
这时候我们就想到一些排序的方法,这些方法就相当于算法,当然算法不是这么简单的,也有很多很有技巧的,这里只是为了举例子
所以算法就是对于某一种特定问题(比如排序)的具体实现形式(堆排,快排,冒泡..)
首先解释什么是复杂度
对于两个算法(比如冒泡和堆排),应用到实际问题里谁更好呢?难道我说第一个更好就一定是对的吗
当然有一个衡量标准:复杂度
复杂度分为两种:时间,空间
但是主要说的还是时间复杂度
因为
时间复杂度:一个关于时间的函数,用来描述一个程序结束之后,某一部分被调用的次数,用俩衡量算法的效率
空间复杂度:程序运行需要额外开辟的空间的大小
而我们知道,随着时间的推移,现在的电脑内存已经很大了,空间复杂度已经不作为特别重要的参考依据,并且计算空间复杂度本身也不是特别复杂
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)