初学数据结构


在本文中,我们开始介绍数据结构的内容,那么就开始吧。
在这里插入图片描述

首先,为了了解数据结构,我们要知道什么是数据

什么是数据?

数据,是描述客观事物的符号,是计算机可以操作的对象,能够被计算机识别和处理的符号集合

数据不仅仅指数值类型,还有声音、图像、视频等非数值类型。

在知道数据后,我们开始介绍数据结构

什么是数据结构?

数据结构,是计算机内部存储和处理数据的方式,指相互之间存在一种或多种关系的数据的集合。

什么是算法?

算法,简单说就是计算步骤。它将输入转化为输出。

要注意的是,数据结构和算法可不是分开的,而是紧密联系一起的
尤其是在校园招聘中,算法编程题越来越常见,而此时如果你没有掌握好数据结构,那么在做类似编程题的时候会非常吃力,所以学好它们非常重要。

算法效率

在谈算法效率前,我们先看一个代码

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

上述代码其实是描述的斐波那契数列,它很有规律,代码看起来也很简洁,看到这里,我们就认为这个代码的算法效率很高。但是真实情况是这样吗?
答案当然是不对的

算法效率的好坏,我们都是从时间空间两个维度来描述的。

时间:算法执行的时间越快越好。
空间:算法运行占用的内存空间越小越好。

根据这两个标准我们再来看斐波那契数列,当n很大的时候,这个代码运行所占的内存空间是非常大的,时间可能也不是很快,这时我们就不能认为这个代码很简洁。
在这里插入图片描述

复杂度

从上文知道了,算法有时间和空间两个维度,所以顺其自然的将复杂度分为时间复杂度时间复杂度

时间复杂度

时间复杂度,是程序执行的快慢程度。但是我们计算多个程序时间复杂度的时候,难道都要我们一个一个去运行程序吗?
在这里插入图片描述

而且在执行代码的时候,会受到多种方面的因素,比如计算机的处理器好坏。你想啊一个最新的计算机和一个五年前甚至十年前的计算机,跑程序用的时间肯定是不一样的呀

后来呀,我们想到算法执行的时间和算法的执行次数成正比,因此我们把代码执行次数定为了时间复杂度。这样我们评价多个程序时间复杂度时就不用一个一个跑了。在这里插入图片描述
现在有个代码,我们来计算一下的时间复杂度

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;
    }

Fun1它的复杂度为N2+2N+10

当N=10, 复杂度为130.

当N=100, 复杂度为10210.

当N=1000, 复杂度为1002010.

我们看到当N增加时,复杂度增加的越来越快,这其中其主要作用的时N2,此时,2N和10对复杂度的影像越来越小,可以忽略不计了。所以我们可以不需要计算精确的复杂度。

来到这里,学过高等数学的小伙伴就有种熟悉的感觉了,是不是类似求无穷大时候的极限。

求时间复杂度时,有一个专门的方法

大O阶方法

大O符号(Big O notation):是用于描述函数渐进行为的数学符号。
推导大O阶方法:
1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数函数中,只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果
就是大O阶。
使用大O的渐进表示法以后,Func1的时间复杂度为:O(N2)
N = 10 F(N) = 100
N = 100 F(N) = 10000
N = 1000 F(N) = 1000000
通过上面我们会发现大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。
另外有些算法的时间复杂度存在最好、平均和最坏情况
最坏情况:任意输入规模的最大运行次数(上界)
平均情况:任意输入规模的期望运行次数
最好情况:任意输入规模的最小运行次数(下界)

下面我们在看一些例子
例1

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);
}

Fun2的复杂度为M+N,此时有两个未知数,当M远大于N时,复杂度为O(M);反之为O(N);当M与N相等时,复杂度O(M)和O(N)都可以。

例2

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

Fun4的复杂度为O(1),因为代码中并没有未知数,且循环执行100次,当复杂度为常数时都将其变成1.

例3

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;
   }
}

BubbleSort的复杂度为O(N2),怎么算的呢?
在这里插入图片描述
程序执行的次数为从1加到N-1,想当与初项为1,公差d=1的等差数列求和。再根据大O阶算法求出复杂度。

空间复杂度

早期空间复杂度是代码运行临时占用的内存空间。那时候的计算机内存还很小,所以它的每个空间在当时看来都很珍贵。但是现在随着技术不断更新,如今的计算机内存空间已经很大了,完全能满足我们的需求。所以现在把内存被占用的大小作为评判标准没有太大的意义了,因此我们将空间复杂度定为变量的个数。

具体内容我们下一节在讲。

本次我们讲了

什么是数据?
什么是数据结构?
什么是算法?
算法效率
复杂度
时间复杂度
大O阶方法
空间复杂度

—————————————————————————————————

结语

数据结构很重要,希望我们一起努力把它掌握。
在这里插入图片描述
好了,今天就这样了,我们下次见。别忘了评论互关呦
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值