数据结构与应用算法
㈠ 如何将数据结构和算法应用到实际之中
写一些程序,尤其是比较底层的程序。就明白它们的用处了。
列举下我们当初的作业(其实是老师从UC Santa Barbara\UC Berkley CS作业直接来题目)
(1)实现一个简单的 TCP 传输层的协议机制
自己去设计协议,不用照搬 RFC 的标准,其实就是数据结构的用场。
需要考虑到数据包丢失(Loss)、损坏(Corruption)、乱序(Disorder)这样的情况。
(2)实现操作系统的虚拟内存机制(基于Nachos系统)
如何去设计页表。如何使用置换算法。以及应用程序请求页的时候,发生缺页,从而导致的中断如何处理。
(3)实现一个简单的编译器(MiniJava)
词法:字符串匹配,表达式求值 等算法;
语法:生成抽象语法树;
语义:采用适当的设计模式(Visitor)来生成语义表、字典、然后转化为目标代码(可以是汇编、或者是类似的 Three-Address Code)
如果以上三个任务都完成并搞懂了,那么恭喜:你不仅掌握了数据结构、算法,而且也学习了计算机网络、操作系统、编译原理中大部分的知识。
㈡ 什么是数据结构和算法
本人乃一个数据痴迷者,在计算机的道路上,也是一个数据结构的痴迷者,现在大学里面和同学搞开发也痴迷于数据库,我就我个人的理解给你谈一谈:
首先,数据结构是一门计算机语言学的基础学科,它不属于任何一门语言,其体现的是几乎所有标准语言的算法的思想。
上面的概念有一些模糊,我们现在来具体说一说,相信你门的数据结构使用的是一门具体的语言比如C/C++语言来说明,那是为了辅助的学习数据结构,而数据结构本身不属于任何语言(相信你把书上的程序敲到电脑里面是不能通过的吧,其只是描述了过程,要调试程序,还需要修改和增加一些东西)。你们的书上开始应该在讲究数据的物理存储结构/逻辑存储结构等概念,说明数据结构首先就是“数据的结构”,在内存上的存储方式,就是物理的存储结构,在程序使用人员的思想上它是逻辑的,比如:
你们在C/C++中学习到链表,那么链表是什么一个概念,你们使用指针制向下一个结点的首地址,让他们串联起来,形成一个接一个的结点,就像显示生活中的火车一样。而这只是对于程序员的概念,但是在内存中存储的方式是怎样的那?对于你程序员来说这是“透明”的,其内部分配空间在那里,都是随机的,而内存中也没有一个又一根的线将他们串联起来,所以,这是一个物理与逻辑的概念,对于我们程序员只需要知道这些就可以了,而我们主要要研究的是“逻辑结构”。
我可以给你一个我自己总结的一个概念:所有的算法必须基于数据结构生存。也就是说,我们对于任何算法的编写,必须依赖一个已经存在的数据结构来对它进行操作,数据结构成为算法的操作对象,这也是为什么算法和数据结构两门分类不分家的概念,算法在没有数据结构的情况下,没有任何存在的意义;而数据结构没有算法就等于是一个尸体而没有灵魂。估计这个对于算法的初学者可能有点晕,我们在具体的说一些东西吧:
我们在数据结构中最简单的是什么:我个人把书籍中线性表更加细化一层(这里是为了便于理解在这样说的):单个元素,比如:int i;这个i就是一个数据结构,它是一个什么样的数据结构,就是一个类型为int的变量,我们可以对它进行加法/减法/乘法/除法/自加等等一系列操作,当然对于单个元素我们对它的数据结构和算法的研究没有什么意义,因为它本来就是原子的,某些具体运算上可能算法存在比较小的差异;而提升一个层次:就是我们的线性表(一般包含有:顺序表/链表)那么我们研究这样两种数据结构主要就是要研究它的什么东西那?一般我们主要研究他们以结构为单位(就是结点)的增加/删除/修改/检索(查询)四个操作(为什么有这样的操作,我在下面说到),我们一般把“增加/删除/修改”都把它称为更新,对于一个结点,若要进行更新一类的操作比如:删除,对于顺序表来说是使用下标访问方式,那么我们在删除了一个元素后需要将这个元素后的所有元素后的所有元素全部向前移动,这个时间是对于越长的顺序表,时间越长的,而对于链表,没有顺序的概念,其删除元素只需要将前一个结点的指针指向被删除点的下一个结点,将空间使用free()函数进行释放,还原给操作系统。当执行检索操作的时候,由于顺序表直接使用下标进行随机访问,而链表需要从头开始访问一一匹配才可以得到使用的元素,这个时间也是和链表的结点个数成正比的。所以我们每一种数据结构对于不同的算法会产生不同的效果,各自没有绝对的好,也没有绝对的不好,他们都有自己的应用价值和方式;这样我们就可以在实际的项目开发中,对于内部的算法时间和空间以及项目所能提供的硬件能力进行综合评估,以让自己的算法能够更加好。
(在这里只提到了基于数据结构的一个方面就是:速度,其实算法的要素还应该包括:稳定性、健壮性、正确性、有穷性、可理解性、有输入和输出等等)
为什么要以结点方式进行这些乱七八糟的操作那?首先明确一个概念就是:对于过程化程序设计语言所提供的都是一些基础第一信息,比如一些关键字/保留字/运算符/分界符。而我们需要用程序解决现实生活中的问题,比如我们要程序记录某公司人员的情况变化,那么人员这个数据类型,在程序设计语言中是没有的,那么我们需要对人员的内部信息定义(不可能完全,只是我们需要那些就定义那些),比如:年龄/性别/姓名/出生日期/民族/工作单位/职称/职务/工资状态等,那么就可以用一些C/C++语言描述了,如年龄我们就可以进行如下定义:
int age;/*age变量,表示人员公司人员的年龄*/
同理进行其他的定义,我们用结构体或类把他们封装成自定义数据类型或类的形式,这样用他们定义的就是一个人的对象的了,它内部包含了很多的模板数据了。
我就我个人的经历估计的代码量应该10000以内的(我个人的经理:只是建议,从你的第一行代码开始算,不论程序正确与否,不论那一门语言,作为一个标准程序员需要十万行的代码的功底(这个是我在大学二年级感觉有一定时候的大致数据,不一定适合其他人),而十万行代码功底一般需要四门基础远支撑,若老师没有教,可以自学一些语言)。
㈢ 数据结构与算法分析 —— C 语言描述:树的遍历及应用
树有很多应用,流行的用法之一是包括 UNIX、VAX/VMS 和 DOS 在内的许多常用操作系统中的目录结构。
假设我们有一个根目录 A,A 目录下有一个目录 B,B 目录下有一个目录 C,C 目录下有一个文件 D。此时,文件 D 的全路径名就为 A/B/C/D,其中,每一个 “/” 后的每一个 “/”在树中都表示一山配山条边,这个分级文件系统非常流行,因为它能够使得用户逻辑地组织数据。不仅如此,在不同目录下的两个文件还可以享有相同的名字,因为他们必然有从根开始的不同的路径从而具有不同的路径名。在 UNIX 文件系统中的目录就是含有它的所有儿子的一个文件。(在 UNIX 文件系统中的每个目录还有一项指向该目录本身以及另一项指向该目录的父目录。因此,严格说来,UNIX 文件系统不是树,而是类树(treelike)。)
假设我们想要列出目录中所文件中所有文件的名字。我们的输出格式将是:深度为 的文件的名字被 次跳格(tab) 锁进后打印出来。
算法的核心为递归程序 ListDir。为了显示根时不进行锁进,该例程需要从目录名和深度 0 开始。这里的深度是一个内部薄记变量,而不是主调例程能够期望知道的那种参数。因此,驱动例程 ListDirectory 用于将递归例程和外界连接卖塌起来。
算法的逻辑简单易懂。ListDir 的参数是到树中的某种引用。只要引用合理,则引用涉及的名字在进行适当次数的跳格锁进后被打印出来。如果是一个目录,那么我们递归地一个逗中一个地处理它所有的儿子。这些儿子出在一个深度上,因此需要锁进一段附加的空格。
这种遍历的策略叫做先序遍历(preorder traversal)。在先序遍历中,对节点的处理工作是在它的诸儿子节点被处理之前进行的。当程序运行时,每个父节点恰好最多只执行一次,因为每个名字只输出一次。不仅如此,对于每个节点的每一个儿子节点最多只能执行一次。在遍历过程中,每个 for 循环终止在 NULL 指针上,但每个节点最多有一个这样的指针。因此,每个节点总的工作量是常数。如果有 N 个文件名需要输出,则运行时间就是 O(N)。
另一种遍历树的方法是后序遍历(postorder traversal)。在后序遍历中,在一个节点处的工作是在它的诸儿子节点被计算后进行的。
由于目录本身也是文件,因此它们也有大小。设我们想要计算被该树所有文件占用的磁盘区块的总数。最自然的做法是找出含有子目录中的块的个数。于是,磁盘块的总数就是子目录中的块的总数加上该目录使用的一个块。
如果不是一个目录,那么 SizeDirectory 只返回所占用的块数。否则,将被占用的块数与其所有子节点(递归地)发现的块数相加。
㈣ 什么是数据结构什么是算法算法与程序有什么关系
在计算机编程领域,数据结构与算法的应用是无处不在。比如图像视频处理、数据压缩、数据库、游戏开发、操作系统、编译器、搜索引擎、AR、VR、人工智能、区块链等领域,都是以数据结构与算法为基石。
数据结构与算法属于开发人员的基本内功,也能训练大脑的思考能力,掌握一次,终生受益。扎实的数据结构与算法功底,能让我们站在更高的角度去思考代码、写出性能更优的程序,能让我们更快速地学习上手各种新技术(比如人工智能、区块链等),也能让我们敲开更高级编程领域的大门。
数据结构与算法更是各大名企面试题中的常客,如果不想被行业抛弃、想进入更大的名企、在IT道路上走得更远,掌握数据结构与算法是非常有必要。