初学者最难理解的数据结构和算法概念有哪些?你会如何解释它们?
Posted crazy_itman
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初学者最难理解的数据结构和算法概念有哪些?你会如何解释它们?相关的知识,希望对你有一定的参考价值。
尽管计算机技术自20世纪40年代第一部电子通用计算机诞生以来以来有了令人目眩的快速发展,但是今天计算机仍然基本上采用的是存储程序结构,即冯·诺伊曼结构。这个结构实现了实用化的通用计算机。存储程序结构将一部计算机描述成四个主要部分:算术逻辑单元、控制电路、存储器及输入输出设备。这些部件通过一组一组的排线连接(特别地,当一组线被用于多种不同意图的数据传输时又被称为总线),并且由一个时钟来驱动(当然某些其他事件也可能驱动控制电路)。概念上讲,一部计算机的存储器可以被视为一组“细胞”单元。每一个“细胞”都有一个编号,称为地址;又都可以存储一个较小的定长信息。这个信息既可以是指令(告诉计算机去做什么),也可以是数据(指令的处理对象)。原则上,每一个“细胞”都是可以存储二者之任一的。算术逻辑单元(ALU)可以被称作计算机的大脑。它能做两类运算: 第一类是算术运算,比如对两个数字进行加减法。算术运算部件的功能在ALU中是十分有限的,事实上, 一些ALU根本不支持电路级的乘法和除法运算(理由是用户只能通过编程进行乘除法运算)。第二类是比较运算,即给定两个数, ALU对其进行比较以确定哪个更大一些。输入输出系统是计算机从外部世界接收信息和向外部世界反馈运算结果的手段。对于一部标准的个人电脑,输入设备主要有键盘和鼠标,输出设备则是显示器、打印机以及其他许多后文将要讨论的可连接到计算机上的I/O设备。
控制系统将以上计算机各部分联系起来。它的功能是从存储器和输入输出设备中读取指令和数据,对指令进行解码, 并向ALU交付符合指令要求的正确输入,告知ALU对这些数据做哪些运算并将结果数据返回到何处。控制系统中一个重要组件就是一个用来保持跟踪当前指令所在地址的计数器。 通常这个计数器随着指令的执行而累加,但有时如果指令指示进行跳转则不依此规则。
20世纪80年代以来ALU和控制单元(二者合称中央处理器)逐渐被集成到一块集成电路上,称作微处理器。 这类计算机的工作模式十分直观:在一个时钟周期内,计算机先从存储器中获取指令和数据,然后执行指令,存储数据,再获取下一条指令。这个过程被反复执行,直至得到一个终止指令。由控制器解释,运算器执行的指令集是一个精心定义的数目十分有限的简单指令集合。一般可以分为四类:1)、数据移动 (如:将一个数值从存储单元A拷贝到存储单元B)2)、数逻运算(如:计算存储单元A与存储单元B之和,结果返回存储单元C)3)、 条件验证(如:如果存储单元A内数值为100,则下一条指令地址为存储单元F)4)、指令串行改易(如:下一条指令地址为存储单元F)
指令如同数据一样在计算机内部是以二进制来表示的。比如说,10110000就是一条Intel x86系列微处理器的拷贝指令代码。 某一个计算机所支持的指令集就是该计算机的机器语言。因此,使用流行的机器语言将会使既成软件在一部新计算机上运行得更加容易。所以对于那些机型商业化软件开发的人来说,它们通常只会关注一种或几种不同的机器语言。更加强大的小型计算机,大型计算机和服务器可能会与上述计算机有所不同。它们通常将任务分担给不同的CPU来执行。今天, 微处理器和多核个人电脑也在朝这个方向发展。超级计算机通常有着与基本的存储程序计算机显著区别的体系结构。它们通常有着数以千计的CPU, 不过这些设计似乎只对特定任务有用。在各种计算机中,还有一些微控制器采用令程序和数据分离的哈佛架构(Harvard architecture)。
数据结构
在计算机科学中,数据结构(英语:data structure)是计算机中存储、组织数据的方式。数据结构意味着接口或封装:一个数据结构可被视为两个函数之间的接口,或者是由数据类型联合组成的存储内容的访问方法封装。大多数数据结构都由数列、记录、可辨识联合、引用等基本类型构成。举例而言,可为空的引用(nullable reference)是引用与可辨识联合的结合体,而最简单的链式结构链表则是由记录与可空引用构成。数据结构可透过编程语言所提供的数据类型、引用及其他操作加以实现。一个设计良好的数据结构,应该在尽可能使用较少的时间与空间资源的前提下,支持各种程序执行。
不同种类的数据结构适合不同种类的应用,部分数据结构甚至是为了解决特定问题而设计出来的。例如B树即为加快树状结构访问速度而设计的数据结构,常被应用在数据库和文件系统上。正确的数据结构选择可以提高算法的效率(请参考算法效率)。在计算机程序设计的过程中,选择适当的数据结构是一项重要工作。许多大型系统的编写经验显示,程序设计的困难程度与最终成果的质量与表现,取决于是否选择了最适合的数据结构。系统架构的关键因素是数据结构而非算法的见解,导致了多种形式化的设计方法与编程语言的出现。绝大多数的语言都带有某种程度上的模块化思想,透过将数据结构的具体实现封装隐藏于用户界面之后的方法,来让不同的应用程序能够安全地重用这些数据结构。C++、Java、Python等面向对象的编程语言可使用类 (计算机科学)来达到这个目的。因为数据结构概念的普及,现代编程语言及其API中都包含了多种默认的数据结构,例如 C++ 标准模板库中的容器、Java集合框架以及微软的.NET Framework。
常见的数据结构
堆栈(Stack)
队列(Queue)
数组(Array)
链表(Linked List)
树(Tree)
图(Graph)
堆(Heap)
散列表(Hash table)
算法
算法(英语:algorithm),在数学(算学)和计算机科学之中,指一个被定义好的、计算机可施行其指示的有限步骤或次序,常用于计算、数据处理(英语:Data processing)和自动推理。算法是有效方法(英语:Effective method),包含一系列定义清晰的指令,并可于有限的时间及空间内清楚的表述出来。算法中的指令描述的是一个计算,它执行(英语:Execution (computing))时从一个初始状态和初始输入(可能为空)开始,经过一系列有限而清晰定义的状态最终产生输出并停止于一个终态。一个状态到另一个状态的转移不一定是确定的。包括随机化算法在内的一些算法,都包含了一些随机输入。早在尝试解决希尔伯特提出的判定问题时,算法的不完整概念已经初步定型;在其后的正式化阶段中人们尝试去定义“有效可计算性(英语:Effective calculability)[9]”或者“有效方法(英语:Effective method)[10]”。这些尝试包括库尔特·哥德尔、雅克·埃尔布朗和斯蒂芬·科尔·克莱尼分别于1930年、1934年和1935年提出的递归函数,阿隆佐·邱奇于1936年提出的λ演算,1936年埃米尔·莱昂·珀斯特(英语:Emil Leon Post)的Formulation 1和艾伦·图灵1937年提出的图灵机。即使在当下,依然常有符合直觉的想法难以定义为形式化算法的情况。
初学者最难理解的数据结构和算法概念有哪些?你会如何解释它们?
在我看来,最难的概念本身并不是真正的概念,而是数据的整体抽象。我们从链表开始,试图获得数据组织不必在任何地方的抽象概念- 指针意味着数据桶可以只存在,我们可以通过跟随箭头和附加到桶的指针找到数据意味着我们可以找到更多的桶,无论它们在哪里。尽管有无数种尝试解释的方法,但许多学生并没有学到这一课。大多数人在 CS2 中的链表中快速上了一课,在那里他们学习了指针的工作原理,但要超越这一点就意味着要对抗:
“我已经学会了,我现在要忽略教授”和
“这不是关于真正的编码,它只是框和线”
LL 有几个应用程序,但最终,每个人都意识到动态数组几乎对所有事情都更好,因此他们坚持认为链表仅用作学术练习*(当然,它有点像,但前提是学术练习能够理解上述概念)。那么,我将如何解释呢?(即我是如何解释的)我不只是用数据和指针绘制一个框作为线。我为板上的节点编写了代码,然后画了一个包含三部分信息的框 - 一个指向数据的指针(这很重要,因为实际数据通常与桶不在同一个空间),一个那是下一个指针,一块是前一个指针。将所有这些东西作为“数据”有助于强化指针就像其他任何东西一样。然后,我会放一张内存图片,把一些(半任意的)十六进制值赋给指针,让同学们看到指针中的值不是“箭头”,而是可以指向任何地方的数据。这种方法还强调了我不仅仅是重复 CS2 中的相同课程,而是更深入。
通常,我们然后转向树。我们为什么要谈论树木?因为树是将结构与性能联系起来的介绍。这意味着将链接的概念扩展到第二个维度。大多数学生都知道决策树的概念,但这过于简单化了。此外,有些人刚刚开始连接第一课,但为时已晚,因为将这个想法应用于树木的期望是隐含的。我看到的另一个问题是,学生们相信每棵树都是二叉搜索树,并且每棵树都是平衡的(他们没有付出任何努力)。我怎么解释的?我使用三种排序算法来介绍树,而不是二叉搜索树。我从优先级队列开始,讨论使用数组列表和链表的性能。然后我说“我们可以使用树来获得更好的优先级队列吗?” 几乎总是有人试图强迫 BST 发现它没有多大帮助,然后谈论堆。我谈到了优先项目总是在最前面的“规则”,以及保持它平衡的“完整”结构(O(lg n)高度),并详细介绍了我们如何维护该结构。我们经常谈论子指针和父指针,以及向上和向下冒泡如何需要双向引用。然后我突然想到我们可以将它存储在一个数组中。这是一个真正的觉醒时刻。那指针不需要成为指针。它们可以是数组索引的“数学”函数。这强化了重要的是结构,而不是实施。然后我们深入研究分而治之的算法,以及由此产生的自然树结构(没有实际实现树)。我们使用 MergeSort 来表明树结构顺序不必与算法顺序相同,但是当我们依赖树型时,我们可以获得它的好处。最后,我使用 QuickSort 来讨论树内的平衡和随机性,以及如果没有组织,这将如何导致一些错误的路径。我不会谈论二叉搜索树(如果出现提示,我会告诉他们这是下一节的一部分):
地图(又名字典)。地图可能是目前最有用的数据结构。它们无处不在,但课程不是介绍真正有用的东西,课程是事物的抽象概念与实现之间的区别。地图不是真实的东西,它只是一组功能,它们共同工作以表示事物应该如何工作。这个想法实际上非常直观,这意味着课程可能更难理解。我怎么解释的?我很早就介绍了抽象数据类型(ADT),在链表和数组列表的Stack/Queue/Priority Queue应用中谈到它。我还将这些列表统称为序列。我并没有特别强调它们,而是本着看数据结构的心态。我花了一些时间讨论优先队列方法的时间复杂性,但是当我们谈到地图时,我更难理解了。我从地图的“最愚蠢”实现开始,即无序数组列表。一切都是 O(n) 时间,因为即使在插入时,您也必须找到一些东西来检查是否应该添加或替换它。然后我们对列表进行排序,得到二分查找的好处,但没有插入/删除的好处。我谈了一些关于使用链表的实现,这有助于强调当您必须跟随链接时,“跳来跳去”并不那么快。这也是对堆数组的一个很好的提醒。我们得到了明显的二叉搜索树,但后来我问了平衡树,有人提到了红黑,当我问它是如何工作的时,得到了震惊的沉默(我每个学期都教过它,但仍然不得不查找规则和转换每一次)。讲完AVL、B-Tree、Skiplist和Red-Black,评估每块的时间复杂度和背后的原因,最后问“但是如果我们不能对数据进行排序怎么办?” 我举了几个例子,比如网格上的点,然后提醒他们 CS2 多态性和内部数据可能不同的超/子类。在我们介绍散列之前通常会进行一些很好的讨论,它提供了一个全新的地图视角,
然后是图表,教训是您可以转换问题以找到更简单的解决方案。我怎么解释的?至此,没有上课的学生已经退学或不再出现了。我的方法是将一些问题转化为图表,然后讨论我们可以获得的解决方案。我们讨论了一点图形表示,但只是在我们试图实现的算法的上下文中。这在算法课程中涵盖的比我的多,所以我把它当作介绍性的。
以上是关于初学者最难理解的数据结构和算法概念有哪些?你会如何解释它们?的主要内容,如果未能解决你的问题,请参考以下文章