一说到数据结构与算法,大家都会避之不及。这本来是一门专业基础课,但是大部分人都并没有学好,更不用说我这种半路出家的码农了。说实话,还是很羡慕科班出身的程序员,因为你们在日常工作或者面试中,只需要复习一下就好了,而我则是完全的从头开始学。不过,还好一切都不晚,在这里,我们就用 PHP 作为示例代码,来和大家一起真正的从头学一遍恐怖的数据结构与算法。

数据结构

什么是数据结构呢?

数据结构是带“结构”的数据元素的集合,“结构”就是指数据元素之间存在的关系

这是严蔚敏老师在《数据结构》第二版中对数据结构的定义。其实,就是关于数据的一种组合形式。就像你去一家书店,或者是图书馆,或者是你家的书柜。这些书应该怎么摆放呢?关于书的摆放形式,就是数据结构。你可以乱七八糟的摆放,也可以分门别类的摆放,也可以根据自己的兴趣爱好摆放,也可以将最常用的书放在手边,将不常看的书放在柜子的深处。这些都是数据结构。

在程序世界中,数据结构包含两种形式,一种是逻辑结构,一种是物理结构。

逻辑结构

即使你完全没有接触过数据结构,但只要你学习过编程,一定会多多少少地听说过这样一些名词:集合、线性表、树、图,它们指的就是数据结构中的逻辑结构。也就是从逻辑关系上描述数据,是具体问题抽象出来的数学模型。比如我们将书进行分类,每个分类下放着相对应的书籍,这就是一种树形结构。或者我们将书按书名拼音建立索引,然后在书架上贴上索引标签,这就是一种哈希结构。

逻辑结构将是我们整个学习中的一个重点,因为各种算法都是针对这些结构的操作实现。这个我们在下面的算法解释中再进行详细的说明。

物理结构

物理结构主要是数据的物理存储方式,也叫做存储结构。这个非常好记,它只有两种形式,顺序存储结构和链式存储结构。通常,顺序存储结构我们使用数组来表示,而链式存储结构在 C语言 中使用结构体的指针来表示,但在 PHP 中,链式结构我们将使用类来表述。

上面说的那些逻辑结构,都可以用顺序或者链式的方式来实现,不管使用哪种方式,都可以完成对应逻辑结构的算法操作,但不同的形式或者算法又有不同的效率。而效率,正是整个数据结构和算法学习核心中的核心。

算法

接下来我们看看什么是算法。

算法是一个有限指令集,它接受一些输入(有些情况下不需要输入),产生输出,并一定在有限步骤之后终止

这是陈越老师在浙大版《数据结构》第二版中对于算法的定义。其实我们简单点理解的话,针对上面的数据结构的一系列操作,就是算法。比如说我们定义了一个树,如何遍历这颗树呢?这就是一个算法,遍历一颗树有先序、中序、后序,也可以进行层序遍历,有这么多种方法,哪种好?哪种不好?用哪种物理结构?线性还是链式?这些结论都以算法的执行效率为基础。可以说,算法种类繁多,效率也千差万别,但是,不能一棒子打死说某个算法一定不好,每种算法也有它不同的应用场景。这就是我们要研究算法的原因。

关于算法,我们最关心的是它的效率,这个效率在这里我们使用的是时间复杂度和空间复杂度来定义的。

时间复杂度

时间复杂度一般使用 O(n) 来表示,它关心的是问题规模和语句频度,一般会以 n 表示问题规模 (注意,这个 n 是未知的,如果这个 n 是已知的,那么它就是常数阶)。这个 n 有可能是一个常数(n 明确等于多少),记成 O(1) 。这是最好的情况,也可以线性增长,如 O(n) 。当然也可能对数或指数级增长,O(logN) 、 O(N^2),当然最要不得的是 O(2^N) 级的增长,这种情况下可能有生之年你都看不到运算的结果了。

我们可以看看简单的一段代码来分析它的时间复杂度:


echo $a++, PHP_EOL; // O(1) $n = 10; // 假设一个数量用于测试,实际这个 n 是未知的,如果面试题代码中真的出现了这种已知 n 的情况,那么这个算法就是 O(1)
for($i = 0;$i<$n;$i++){
echo $i, PHP_EOL;
}
// O(n) for($i = 0;$i<$n;$i*=2){
echo $i, PHP_EOL;
}
// O(logN) for($i = 0;$i<$n;$i++){
for($j = 0;$j<$n;$j++){
echo $i, $j, PHP_EOL;
}
}
// O(N^2)

从上面代码中可以看出,循环嵌套次数与 n 的增长有很大的关系,另外就是看在循环内部的操作也会影响到增长的情况。比如如果我们是这样一段代码:

$n = 10; // 假设一个数量,实际这个 n 是未知的
$m = 3; // 假设一个数量,实际这个 m 是未知的
for($i = 0;$i<$n;$i++){
for($j = 0;$j<$m;$j++){
echo $i, $j, PHP_EOL;
}
}

那么它的时间复杂度就不是 O(N^2) 而是,O(NM) ,因为我们这两层循环并不是都是对最大的 N 的操作,而是 N * M 的操作。但是,如果当 M 很大甚至等于 N 的时候,那么这个算法也就成为了 N^2 。

对于时间复杂度的分析其实是需要一些数学功底的,但是对于我这种半吊子出身的码农来说,把握住循环层次以及循环内的操作情况就可以大致地分析出一段算法的时间复杂度了。当然,对于某些大厂比较刁钻的面试题来说,还是需要用数学方法进行分解求得正确的时间复杂度。

另外,在一段算法或者说一个函数中,时间复杂度以最大的那个为准,同时,也要考虑最好和最差时间复杂度,因为基于数据规模有可能在数据量大的时候时间复杂度会越来越惨。这个时候我们就会以最差时间复杂度来作为这一段算法的最终时间复杂度。

关于时间复杂度的问题,可以参考各类算法书籍,当然最好是以大学教材及练习题为主,多做题就能掌握得更深入。

空间复杂度

相对时间复杂度来,空间复杂度在数据结构和算法中要关心的少一些,因为大部分情况下我们只借助一个第三方变量的话,这个空间复杂度就是 O(1) 。而如果需要借助一个数组或者链表来实现算法的话,这个算法的空间复杂度就是 O(n) 。

一般情况下我们不太会去过于的关注空间复杂度,因为大部分算法基本都会维持在 O(1) 或 O(n) 这个级别。当然,也就一些算法会出现占用非常大的空间复杂度的情况,这样分分钟就能撑爆你的内存。当在遇到这类算法的时候,我们会单独来说明空间复杂度的情况。

总结

第一篇文章都是以理论方面的东西为基础的,这也是学习数据结构与算法的实际情况,必须是理论与实际相结合的学习。让我们从此开始,迈向这个深不见底的超级大坑吧!!

参考资料:

《数据结构》第二版,严蔚敏

《数据结构》第二版,陈越

《数据结构高分笔记》2020版,天勤考研

===============

关注公众号:【硬核项目经理】获取最新文章

添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料

知乎、公众号、抖音、头条搜索【硬核项目经理】

B站ID:482780532

【PHP数据结构】在学数据结构和算法的时候我们究竟学的是啥?的更多相关文章

  1. 前端要不要学数据结构&算法

    我们都知道前端开发工程师更多偏向 DOM 渲染和 DOM 交互操作,随之 Node 的推广前端工程师也可以完成服务端开发.对于服务端开发而言大家都觉得数据结构和算法是基础,非学不可.所以正在进行 No ...

  2. 数据结构C语言版 弗洛伊德算法实现

    /* 数据结构C语言版 弗洛伊德算法  P191 编译环境:Dev-C++ 4.9.9.2 */ #include <stdio.h>#include <limits.h> # ...

  3. 简学Python第二章__巧学数据结构文件操作

    #cnblogs_post_body h2 { background: linear-gradient(to bottom, #18c0ff 0%,#0c7eff 100%); color: #fff ...

  4. hdu 3336:Count the string(数据结构,串,KMP算法)

    Count the string Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  5. 每周一道数据结构(四)A*算法&博弈树α-β剪枝

    A*算法/博弈树 前阵子考试学了A*算法.博弈树和回溯,自己真是愚蠢至极,根本没就搞明白这些,所以对于这些算法问道的话就不能说清楚,也记不住,所以才有了这篇笔记.在这里感谢面试我的那位工程师~~ A* ...

  6. 你真的懂redis的数据结构了吗?redis内部数据结构和外部数据结构揭秘

    Redis有哪些数据结构? 字符串String.字典Hash.列表List.集合Set.有序集合SortedSet. 很多人面试时都遇到过这种场景吧? 其实除了上面的几种常见数据结构,还需要加上数据结 ...

  7. 一步步教你轻松学支持向量机SVM算法之案例篇2

    一步步教你轻松学支持向量机SVM算法之案例篇2 (白宁超 2018年10月22日10:09:07) 摘要:支持向量机即SVM(Support Vector Machine) ,是一种监督学习算法,属于 ...

  8. 一步步教你轻松学支持向量机SVM算法之理论篇1

    一步步教你轻松学支持向量机SVM算法之理论篇1 (白宁超 2018年10月22日10:03:35) 摘要:支持向量机即SVM(Support Vector Machine) ,是一种监督学习算法,属于 ...

  9. 一步步教你轻松学关联规则Apriori算法

    一步步教你轻松学关联规则Apriori算法 (白宁超 2018年10月22日09:51:05) 摘要:先验算法(Apriori Algorithm)是关联规则学习的经典算法之一,常常应用在商业等诸多领 ...

随机推荐

  1. 不懂Ribbon原理的可以进来看看哦,分析RibbonClientConfiguration完成了哪些核心初始操作

      本文在前一篇文章的基础上来继续分析Ribbon的核心内容. 不懂Ribbon原理的可以进来看看哦,分析SpringBoot自动装配完成了Ribbon哪些核心操作 RibbonClientConfi ...

  2. Java TreeMap 和 LinkedHashMap【笔记】

    Java TreeMap 和 LinkedHashMap[笔记] TreeMap TreeMap基本结构 TreeMap 底层的数据结构就是红黑树,和 HashMap 的红黑树结构一样 与HashMa ...

  3. MATLAB—M函数文件

    文章目录 一.M文件 1.脚本文件和函数文件的区别 二.M函数文件 1.创建方法 2.文件形式 2.函数形参及注释 3.函数的调用 4.函数变量 5.主函数.子函数 三.函数句柄 一.M文件 首先,要 ...

  4. FileUtils 文件工具类

    FileUtils 下载jar中的文件 package com.meeno.chemical.common.utils; import lombok.extern.slf4j.Slf4j; impor ...

  5. 消除不受信任的HTML (来防止XSS攻击)

    问题 在做网站的时候,经常会提供用户评论的功能.有些不怀好意的用户,会搞一些脚本到评论内容中,而这些脚本可能会破坏整个页面的行为,更严重的是获取一些机要信息,此时需要清理该HTML,以避免跨站脚本cr ...

  6. 【springcloud】API Gateway 的路由和过滤(Zuul--1)

    转自:https://blog.csdn.net/pengjunlee/article/details/87084646 Zuul是什么? API Gateway 是随着微服务(Microservic ...

  7. tar.gz 文件解压

    tar.gz 文件解压 解压缩 file.tar.gz 的过程中出现如下所示问题: tar: 它似乎不像是一个 tar 归档文件 tar: 跳转到下一个头 tar: 由于前次错误,将以上次的错误状态退 ...

  8. MAC下Jetbrains编译器无法打开问题解决

    这段时间不知道怎么回事,每次打开Rider必定闪退,毫无头绪,只好暂时放弃使用Rider,试用了一段时间Visual Studio. 可惜...虽然大学时候觉得VS天下第一,但是用惯了JB的编译器,再 ...

  9. iptables开启后造成本地套接字阻塞的问题

    前段时间,我使用iptables实现了针对IP地址与MAC地址的白名单功能,即将INPUT链的默认规则设为DROP: iptables -P INPUT DROP 这样就能拒绝一切外来报文.随后只需要 ...

  10. k8s笔记0528-基于KUBERNETES构建企业容器云手动部署集群记录-4

    部署kubelet 1.二进制包准备 将软件包从linux-node1复制到linux-node2中去. [root@linux-node1 ~]# cd /usr/local/src/kuberne ...