数据结构-前言、时间复杂度、空间复杂度

前言

1.什么是数据结构

     数据结构(Data Structure)是计算机存储、组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合。

2.什么是算法?
算法(Algorithm):就是定义良好的计算过程,他取一个或一组的值为输入,并产生出一个或一组值作为输出。简单来说算法就是一系列的计算步骤,用来将输入数据转化成输出结果。

3.作用?

    数据结构是计算机类的重要知识,是校园招聘的重要考察内容。目前校园招聘笔试一般采用Online Judge形式, 一般都是20-30道选择题+2道编程题,或者3-4道编程题。

   其中会有很多比较难的编程题,对算法的考察也是无处不在,对于算法,需要从基础打好。

  算法对工作的作用:学好算法对一个程序员来说是必须的吗?如果是,至少应该学到哪种程度? - 知乎 (zhihu.com)

 4. 如何学好数据结构

1.很简单,学到下图那样就行了。

2.多思考和画图!!!!!!!

5.学习资料建议
1.剑指offerOJ牛客网 - 找工作神器|笔试题库|面试经验|实习招聘内推,求职就业一站解决_牛客网 (nowcoder.com)

2.力扣网。

1.程序的评价

一个程序的好坏是有多方面的评价体系的,比如可读性、可维护性、时间复杂度、空间复杂度等

如下斐波那契数列的函数

long long Fib(int N)
{
if(N < 3)
return 1;
return Fib(N-1) + Fib(N-2);
}

很简洁,但是好吗?

对于一个算法,算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源 。因此衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。
时间复杂度主要衡量一个算法的运行快慢,而空间复杂度主要衡量一个算法运行所需要的额外空间。在计算机发展的早期,计算机的存储容量很小。所以对空间复杂度很是在乎。但是经过计算机行业的迅速发展,计算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度。因此现在我们更加看重时间复杂度。

2.时间复杂度


通常算法中的基本操作的执行次数表示算法的时间复杂度。但实际使用时算法的时间复杂度是一个函数,用大O的渐进表示法表示

大O符号(Big O notation):是用于描述函数渐进行为的数学符号。
推导大O阶方法:
1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数函数中,只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。
有些算法会出现最好情况、最坏情况、期望情况等三类,通常用其时间复杂度用最坏情况表示。
example1

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);
}
执行了2n+10次,因此是O(N);

example2:

void Func4(int N)
{
int count = 0;
for (int k = 0; k < 100; ++ k)
{
++count;
}
printf("%d\n", count);
}

执行了100次,是一个常数,时间复杂度是O(1);

example3:

const char * strchr ( const char * str, int character );

//这个函数是从字符串第一个字符开始查找,直到找到character,然后返回其字符串中它的地址。
 

其他

冒泡排序

快速排序

                                 

3.空间复杂度

有了时间复杂度的经验,空间复杂度应该也不难掌握,先来两道练手题

// 计算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;
 }
}

 这个冒泡排序只额外开了exchange一个变量,因此是O(N)

// 计算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个元素的数组,空间使用了n个,因此是O(N)

// 计算阶乘递归Fac的空间复杂度?
long long Fac(size_t N)
{
if(N == 0)
return 1;
return Fac(N-1)*N;
}

这个是函数递归,函数的连续调用开了连续的n个空间,因此是O(N)

再来看看这个:

// 计算斐波那契递归Fib的空间复杂度?
long long Fib(size_t N)
{
if(N < 3)
return 1;
return Fib(N-1) + Fib(N-2);
}

这个就需要对于空间比较深刻的理解了

函数递归的调用会启用栈空间

我们知道,Fib(n)会调用Fib(n-1)、Fib(n-2)并且调用顺序是先n-1后n-2,由于n-1会继续递归,因此这个n-2的就被暂时搁置了,那么接下来每一个都会先调自己下面的第一个,直到调到3。(此时空间已经调用了O(N))那么到这里之后,调用3之后空间被销毁。但是这里空间的销毁不是把内存条给掰断之类的,而是把这片空间里存着的Fib(3)给它踢出去,然后塞进它的上一个的右下函数(类似二叉树的右孩)但是空间总数不变,这个右下掉完也被踢出去,以此类推,所以自此以后不会再开启新的空间,因此答案是O(N);这个空间用了多次,但是确实只需要这么多空间就够了

这里给两个例题:

1.消失的数字OJ链接:https://leetcode-cn.com/problems/missing-number-lcci

2 旋转数组 OJ 链接: https://leetcode-cn.com/problems/rotate-array /
  • 31
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值