1. 数据结构的认识:
初级:c语言(指针、结构、库函数、内存管理)
中级:c++语言+STL+高阶数据结构
高级:linux环境+系统编程+网络编程+数据库
2.什么是数据结构?
数据结构(Data Structure)是计算机存储、组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合。
tip:实现一些项目,需要在内存中将数据存储起来通讯录,每个信息存储起来。例如方法:数组、链表、树...
什么是算法?
算法(Algorithm):就是定义良好的计算过程,他取一个或一组的值为输入,并产生出一个或一组值作为输出。简单来说算法就是一系列的计算步骤,用来将输入数据转化成输出结果。
3.算法效率
3.1 如何衡量一个算法的好坏
- 时间复杂度:主要衡量一个算法的运行快慢
- 空间复杂度:主要衡量一个算法运行所需要的额外空间
3.1.1 时间复杂度
即:找到某条基本语句与问题规模N之间的数学表达式,就是算出了该算法的时间复杂度。
tip:环境不同,具体运行时间不同,所以不进行计算。
//计算FUNC1中++count语句中总共执行多少次?
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;
}
print("%d\n",count);
}
1.嵌套循环时间复杂度:O(N*N)
tip:嵌套循环时间复杂度的函数式子:F(N)=N*N+2N+10
- N=10 F(N)= 130
- N=100 F(N)= 10210
- N=1000 F(N)= 1002010
N越大,后两项对结果的影响是越小的
实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这里我们使用大O的渐进表示法。(估算)
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;
}
print("%d\n",count);
}
(没有说明M和N的大小关系)2. 双重循环时间复杂度:O(M+N)
tip:一般情况下,时间复杂度计算时未知数都是用的N但是也可以时M、K等等其他的。
- M远大于N-> O(M)
- N远大于M->O(N)
- M和N差不多大-> O(M) 或者O(N)
//计算FUnC4的时间复杂度?
void FUNC3(int N,int M)
{
int count=0;
for (int k=0;k<100;++k)
{
++count;
}
print("%d\n",count);
}
3. 常数循环时间复杂度:O(1)
O(1)不是代表算法运行一次,是常数次
//计算strchr的时间复杂度?
const char*strchr(const char*str,int character);
4. strchar时间复杂度:
- 最好情况:任意输入规模的最小运行次数(下界) 1
- 平均情况:任意输入规模的期望运行次数 N/2
- 最坏情况:任意输入规模的最大运行次数(上界) N
- 当一个算法随着输入不同,时间复杂度不同,时间复杂度做悲观预期,看最坏的情况
//计算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(exchnge==0)
break;
}
}
5. 冒泡排序时间复杂度:
精确:F(N) =(N*(N-1))/2
时间复杂度:O(N^2)
//计算BinarySearch的时间复杂度?
void BinarySearch(int *a,int n,int x)
{
assert(a);
for (size_t end=n;end>0;--end)
{
int begin=0;
int end=n;
while (begin<end)
{
int mid=begin+((end-begin)>>1);
if(a[mid]<x)
begin=mid+1;
else if(a[mid]>x)
end=mid;
else
return mid;
}
return -1;
}
6. 二分查找的时间复杂度: O(log2N)
tip:算时间复杂度,不能只是去看几层循环,而是去看它的思想
最好情况:O(1)
最坏情况:O(log2N)
二分查找算法很厉害!!!
N个数中查找 大概查找次数 1000 10 100W 20 10亿 30
//计算阶乘递归Fac的时间复杂度?
long long Fac(size_t N)
{
if(0==N)
return -1;
return Fac(N-1)*N;
}
7. 递归时间复杂度:O(N)
递归算法:递归次数*每次递归调用的次数
//计算斐波那契递归Fib的时间复杂度?
long long Fib(size_t N)
{
if(N<3)
return 1;
return Fib(N-1)+Fib(N-2);
}
8. 斐波那契递归时间复杂度:O(2^N)
式子:Fib(N)=2^0+2^1+2^2+...+2^(N-1)-x
其中:x远小于2^N
tip:斐波那契递归算法完全是一个没用的算法,太慢了!
3.1.2 空间复杂度
- 空间复杂度也是一个数学函数表达式,是对一个算法在运行过程中临时额外占用存储空间大小的量度。
- 注意:函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好了,因此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定。
1. 冒泡排序的空间复杂度?
空间复杂度:O(1)
2. 斐波那契的空间复杂度?
空间复杂度:O(N)
3.阶乘递归的空间复杂度?
空间复杂度:O(N)
看递归的深度
tip:空间是可以重复利用,不累计的,时间是一去不复返。