【思特奇杯·云上蓝桥-算法集训营】第1周——了解算法与数据结构

一、算法的基础概念

1、什么是算法?

        算法就是任何良定义的计算过程,该过程取某个值或者值的集合作为输入并产生某个值的集合作为输出。算法描述了一个特定的计算过程来实现该输入输出关系。

注:良定义是指给出的定义到底是不是清晰的,是不是有意义的。

        我们也可以把算法看成是用于求解良说明的计算问题的工具。

2、为什么学习算法?

        计算时间和存储空间是一种有限资源.我们把算法看作一种技术,整个系统的性能不但依赖于选择快速的硬件,也在于选择快速有效的算法。

3、如何评判算法的优劣

运算的速度和所需要的存储空间。 评判算法的常用方法——大O记法

4、什么是大O记法

        影响算法性能的主要因素是这个算法对应操作的所需步数,但是我们无法把一个算法记录成确切步数的算法,因为同一个算法对应不同对象的步数并不是固定的,比如线性查找,一个有20个元素的数组,最多需要20步;但一个400元素的数组,最多就是400步了。

        这样的话,我们量化线性查找步数的最好方法就是:对于具有 个元素的数组,该算法最多需要 步;不过这种说法太繁琐,一大堆字不是么,所以计算机科学家就从数学界借鉴了一种简洁又通用的方式——大O记法,并将记录方式规范化,从而使得学术交流变得简单。

        同样对于编程人员来说,掌握了大O记法,就掌握了算法分析的专业工具。

1、 数步数

        大O记法不关注算法所用的时间,只关注所用的步数;譬如一个数组不管多大,读取操作都只需要 1 步,用大O记法来表示,就是:

                 O(1)

        回过头来看看之前提及的线性查找,我们已经知道,对于具有 个元素的数组,该算法最多需要 步,那么我们用大O记法来表示,就是:

                O(N)

2、常数时间与线性时间

        从上面的内容就可以看出来,大O记法不仅仅用固定的数字来表示算法步数的,而是基于要处理的数据量来表述算法所需的步数;或者说,随着数据量的增长,所需步数如何增长。

         这里可以看出两者的区别,O(N) 是一条持续上斜上方的对角线,也被称为线性时间;而 O(1) 是恒定的水平线,也被称为常数时间

        通过上面的图例和解释,我们也可以明白,当一个算法是恒定步数的时候,即使不是固定的 步,而是比如 步,它的图形也是类似的:

        此时因为步数恒定,所以在大O记法当中,我们都认为这种算法属于常数时间,故此同样表示为 O(1);简单来说,O(1) 就是表示数据增长但是步数不变的所有算法。

        即使步数是恒定的 100 步,它也依然表示为 O(1),因为它最终还是会比 O(N) 更高效。

 3、同一算法,不同场景

        其实我们也知道,线性查找的步数并不总是 O(N),如果要查找的元素恰好在数组开头,那么仅仅需要 步,那么技术上来说应该是 O(1);而最坏的情况是要查找的元素在数据末尾,那么就需要 步了,也就是 O(N);概括来说,线性查找的最好情况是 O(1),最坏情况才是 O(N)

        不过一般情况下,如果没有特别标明,大O记法通常都是指算法的最坏情况,所以我们说线性查找的算法应该归类为 O(N)

        因为我们需要知道一个算法会差到什么程度,才可能做好最坏的打算,选出最适合的算法。

 4 对数时间

这里学过大O记法了,我们就可以来看看之前了解的有序数组里,二分查找应该怎么分类:

  • 它不能写成 O(1),因为步数会随着数据量增长而增长,即非常数时间
  • 同样不能写成 O(N),因为该算法步数要比元素数量少得多(100 个元素只需要 步);

那么,二分查找的时间按复杂度就是介于 O(1) 和 O(N) 之间了,这样我们可以记为:

                O(log N)

这一类的算法,我们也叫做对数时间——数据量翻倍时,步数加 1

这里可以看看三类算法的对比图:

上图可以看出,对数时间的效率略差于常数时间,但远胜于线性时间

至于为什么是对数,我们需要了解一下对数(logarithm)的概念了:对数是指数的反函数

(对数实在打不出来了QAQ,对数时间具体内容见5.大O记法 - 知乎 (zhihu.com)

 二、数据结构

1、数据结构类型

(1)数组:

数组是可以再内存中连续存储多个元素的结构,在内存中的分配也是连续的,数组中的元素通过数组下标进行访问,数组下标从0开始。(C语言里已经见识过了)

(2)栈:

栈是一种特殊的线性表,仅能在线性表的一端操作,栈顶允许操作,栈底不允许操作。 栈的特点是:先进后出,或者说是后进先出,从栈顶放入元素的操作叫入栈,取出元素叫出栈。(大致了解,若需详细理解,请见(27条消息) 什么是栈?_程晨-CSDN博客_什么是栈

(3)队列:

队列与栈一样,也是一种线性表,不同的是,队列可以在一端添加元素,在另一端取出元素,也就是:先进先出。从一端放入元素的操作称为入队,取出元素为出队。

(4)链表:

链表是物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现,每个元素包含两个结点,一个是存储元素的数据域 (内存空间),另一个是指向下一个结点地址的指针域。根据指针的指向,链表能形成不同的结构,例如单链表,双向链表,循环链表等。

(5)树:

树是一种数据结构,它是由n(n>=1)个有限节点组成一个具有层次关系的集合。把它叫做 “树” 是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:

每个节点有零个或多个子节点;
没有父节点的节点称为根节点;
每一个非根节点有且只有一个父节点;
除了根节点外,每个子节点可以分为多个不相交的子树;
在日常的应用中,我们讨论和用的更多的是树的其中一种结构,就是二叉树。
这里写图片描述

 

二叉树是树的特殊一种,具有如下特点:

1、每个结点最多有两颗子树,结点的度最大为2。
2、左子树和右子树是有顺序的,次序不能颠倒。
3、即使某结点只有一个子树,也要区分左右子树。

二叉树是一种比较有用的折中方案,它添加,删除元素都很快,并且在查找方面也有很多的算法优化,所以,二叉树既有链表的好处,也有数组的好处,是两者的优化方案,在处理大批量的动态数据方面非常有用。

(6)堆:

堆是一种比较特殊的数据结构,可以被看做一棵树的数组对象,具有以下的性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值;

  • 堆总是一棵完全二叉树。

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

因为堆有序的特点,一般用来做数组中的排序,称为堆排序。 

(6)图:

图是由结点的有穷集合V和边的集合E组成。其中,为了与树形结构加以区别,在图结构中常常将结点称为顶点,边是顶点的有序偶对,若两个顶点之间存在一条边,就表示这两个顶点具有相邻关系。

按照顶点指向的方向可分为无向图和有向图:

这里写图片描述这里写图片描述

邻接列表:在邻接列表实现中,每一个顶点会存储一个从它这里开始的边的列表。比如,如果顶点A 有一条边到B、C和D,那么A的列表中会有3条边

 

邻接列表只描述了指向外部的边。A 有一条边到B,但是B没有边到A,所以 A没有出现在B的邻接列表中。查找两个顶点之间的边或者权重会比较费时,因为遍历邻接列表直到找到为止。

邻接矩阵:在邻接矩阵实现中,由行和列都表示顶点,由两个顶点所决定的矩阵对应元素表示这里两个顶点是否相连、如果相连这个值表示的是相连边的权重。例如,如果从顶点A到顶点B有一条权重为 5.6 的边,那么矩阵中第A行第B列的位置的元素值应该是5.6:

 往这个图中添加顶点的成本非常昂贵,因为新的矩阵结果必须重新按照新的行/列创建,然后将已有的数据复制到新的矩阵中。

        两种方法如何选用呐?

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值