何谓数据结构Word文件下载.docx
《何谓数据结构Word文件下载.docx》由会员分享,可在线阅读,更多相关《何谓数据结构Word文件下载.docx(9页珍藏版)》请在冰豆网上搜索。
![何谓数据结构Word文件下载.docx](https://file1.bdocx.com/fileroot1/2022-11/16/ecfeab92-f637-4a01-8566-cbc29423d2cc/ecfeab92-f637-4a01-8566-cbc29423d2cc1.gif)
什么是数据结构?
什么是逻辑结构和物理结构?
数据是指由有限的符号(比如,"
0"
和"
1"
,具有其自己的结构、操作、和相应的语义)组成的元素的集合。
结构是元素之间的关系的集合。
通常来说,一个数据结构DS可以表示为一个二元组:
DS=(D,S),//i.e.,data-structure=(data-part,logic-structure-part)
这里D是数据元素的集合(或者是“结点”,可能还含有“数据项”或“数据域”),S是定义在D(或其他集合)上的关系的集合,S={R|R:
D×
D×
...},称之为元素的逻辑结构。
逻辑结构有四种基本类型:
集合结构、线性结构、树状结构和网络结构。
表和树是最常用的两种高效数据结构,许多高效的算法可以用这两种数据结构来设计实现。
表是线性结构的(全序关系),树(偏序或层次关系)和图(局部有序(weak/localorders))是非线性结构。
数据结构的物理结构是指逻辑结构的存储镜像(image)。
数据结构DS的物理结构P对应于从DS的数据元素到存储区M(维护着逻辑结构S)的一个映射:
PD,S)-->
M存储器模型:
一个存储器M是一系列固定大小的存储单元,每个单元U有一个唯一的地址A(U),该地址被连续地编码。
每个单元U有一个唯一的后继单元U'
=succ(U)。
P的四种基本映射模型:
顺序(sequential)、链接(linked)、索引(indexed)和散列(hashing)映射。
因此,我们至少可以得到4×
4种可能的物理数据结构:
sequential(sets)
linkedlists
indexedtrees
hashgraphs
(并不是所有的可能组合都合理)数据结构DS上的操作:
所有的定义在DS上的操作在改变数据元素(节点)或节点的域时必须保持DS的逻辑和物理结构。
DS上的基本操作:
任何其他对DS的高级操作都可以用这些基本操作来实现。
最好将DS和他的所有基本操作看作一个整体——称之为模块。
我们可以进一步将该模块抽象为数据类型(其中DS的存储结构被表示为私有成员,基本操作被表示为公共方法),称之为ADT。
作为ADT,堆栈和队列都是一种特殊的表,他们拥有表的操作的子集。
对于DATs的高级操作可以被设计为(不封装的)算法,利用基本操作对DS进行处理。
好的和坏的DS:
如果一个DS可以通过某种“线性规则”被转化为线性的DS(例如线性表),则称它为好的DS。
好的DS通常对应于好的(高效的)算法。
这是由计算机的计算能力决定的,因为计算机本质上只能存取逻辑连续的内存单元,因此如何没有线性化的结构逻辑上是不可计算的。
比如对一个图进行操作,要访问图的所有结点,则必须按照某种顺序来依次访问所有节点(要形成一个偏序),必须通过某种方式将图固有的非线性结构转化为线性结构才能对图进行操作。
树是好的DS——它有非常简单而高效的线性化规则,因此可以利用树设计出许多非常高效的算法。
树的实现和使用都很简单,但可以解决大量特殊的复杂问题,因此树是实际编程中最重要和最有用的一种数据结构。
树的结构本质上有递归的性质——每一个叶节点可以被一棵子树所替代,反之亦然。
实际上,每一种递归的结构都可以被转化为(或等价于)树形结构。
从机器语言到高级语言的抽象
我们知道,算法被定义为一个运算序列。
这个运算序列中的所有运算定义在一类特定的数据模型上,并以解决一类特定问题为目标。
这个运算序列应该具备下列四个特征。
有限性,即序列的项数有限,且每一运算项都可在有限的时间内完成;
确定性,即序列的每一项运算都有明确的定义,无二义性;
可以没有输入运算项,但一定要有输出运算项;
可行性,即对于任意给定的合法的输入都能得到相应的正确的输出。
这些特征可以用来判别一个确定的运算序列是否称得上是一个算法。
但是,我们现在的问题不是要判别一个确定的运算序列是否称得上是一个算法,而是要对一个己经称得上是算法的运算序列,回顾我们曾经如何用程序设计语言去表达它。
算法的程序表达,归根到底是算法要素的程序表达,因为一旦算法的每一项要素都用程序清楚地表达,整个算法的程序表达也就不成问题。
作为运算序列的算法,有三个要素。
作为运算序列中各种运算的运算对象和运算结果的数据;
运算序列中的各种运算;
运算序列中的控制转移。
这三种要素依序分别简称为数据、运算和控制。
由于算法层出不穷,变化万千,其中的运算所作用的对象数据和所得到的结果数据名目繁多,不胜枚举。
最简单最基本的有布尔值数据、字符数据、整数和实数数据等;
稍复杂的有向量、矩阵、记录等数据;
更复杂的有集合、树和图,还有声音、图形、图像等数据。
同样由于算法层出不穷,变化万千,其中运算的种类五花八门、多姿多彩。
最基本最初等的有赋值运算、算术运算、逻辑运算和关系运算等;
稍复杂的有算术表达式和逻辑表达式等;
更复杂的有函数值计算、向量运算、矩阵运算、集合运算,以及表、栈、队列、树和图上的运算等:
此外,还可能有以上列举的运算的复合和嵌套。
关于控制转移,相对单纯。
在串行计算中,它只有顺序、分支、循环、递归和无条件转移等几种。
我们来回顾一下,自从计算机问世以来,算法的上述三要素的程序表达,经历过一个怎样的过程。
最早的程序设计语言是机器语言,即具体的计算机上的一个指令集。
当时,要在计算机上运行的所有算法都必须直接用机器语言来表达,计算机才能接受。
算法的运算序列包括运算对象和运算结果都必须转换为指令序列。
其中的每一条指令都以编码(指令码和地址码)的形式出现。
与算法语言表达的算法,相差十万八千里。
对于没受过程序设计专门训练的人来说,一份程序恰似一份"
天书"
,让人看了不知所云,可读性极差。
用机器语言表达算法的运算、数据和控制十分繁杂琐碎,因为机器语言所提供的指令太初等、原始。
机器语言只接受算术运算、按位逻辑运算和数的大小比较运算等。
对于稍复杂的运算,都必须一一分解,直到到达最初等的运算才能用相应的指令替代之。
机器语言能直接表达的数据只有最原始的位、字节、和字三种。
算法中即使是最简单的数据如布尔值、字符、整数、和实数,也必须一一地映射到位、字节和字中,还得一一分配它们的存储单元。
对于算法中有结构的数据的表达则要麻烦得多。
机器语言所提供的控制转移指令也只有无条件转移、条件转移、进入子程序和从子程序返回等最基本的几种。
用它们来构造循环、形成分支、调用函数和过程得事先做许多的准备,还得靠许多的技巧。
直接用机器语言表达算法有许多缺点。
大量繁杂琐碎的细节牵制着程序员,使他们不可能有更多的时间和精力去从事创造性的劳动,执行对他们来说更为重要的任务。
如确保程序的正确性、高效性。
程序员既要驾驭程序设计的全局又要深入每一个局部直到实现的细节,即使智力超群的程序员也常常会顾此失彼,屡出差错,因而所编出的程序可靠性差,且开发周期长。
由于用机器语言进行程序设计的思维和表达方式与人们的习惯大相径庭,只有经过较长时间职业训练的程序员才能胜任,使得程序设计曲高和寡。
因为它的书面形式全是"
密"
码,所以可读性差,不便于交流与合作。
因为它严重地依赖于具体的计算机,所以可移植性差,重用性差。
这些弊端造成当时的计算机应用未能迅速得到推广。
克服上述缺点的出路在于程序设计语言的抽象,让它尽可能地接近于算法语言。
为此,人们首先注意到的是可读性和可移植性,因为它们相对地容易通过抽象而得到改善。
于是,很快就出现汇编语言。
这种语言对机器语言的抽象,首先表现在将机器语言的每一条指令符号化:
指令码代之以记忆符号,地址码代之以符号地址,使得其含义显现在符号上而不再隐藏在编码中,可让人望"
文"
生义。
其次表现在这种语言摆脱了具体计算机的限制,可在不同指令集的计算机上运行,只要该计算机配上汇编语言的一个汇编程序。
这无疑是机器语言朝算法语言靠拢迈出的一步。
但是,它离算法语言还太远,以致程序员还不能从分解算法的数据、运算和控制到汇编才能直接表达的指令等繁杂琐碎的事务中解脱出来。
到了50年代中期,出现程序设计的高级语言如Fortran,Algol60,以及后来的PL/l,Pascal等,算法的程序表达才产生一次大的飞跃。
诚然,算法最终要表达为具体计算机上的机器语言才能在该计算机上运行,得到所需要的结果。
但汇编语言的实践启发人们,表达成机器语言不必一步到位,可以分两步走或者可以筑桥过河。
即先表达成一种中介语言,然后转成机器语言。
汇编语言作为一种中介语言,并没有获得很大成功,原因是它离算法语言还太远。
这便指引人们去设计一种尽量接近算法语言的规范语言,即所谓的高级语言,让程序员可以用它方便地表达算法,然后借助于规范的高级语言到规范的机器语言的"
翻译"
,最终将算法表达为机器语言。
而且,由于高级语言和机器语言都具有规范性,这里的"
完全可以机械化地由计算机来完成,就像汇编语言被翻译成机器语言一样,只要计算机配上一个编译程序。
上述两步,前一步由程序员去完成,后一步可以由编译程序去完成。
在规定清楚它们各自该做什么之后,这两步是完全独立的。
它们各自该如何做互不相干。
前一步要做的只是用高级语言正确地表达给定的算法,产生一个高级语言程序;
后一步要做的只是将第一步得到的高级语言程序翻译成机器语言程序。
至于程序员如何用高级语言表达算法和编译程序如何将高级语言表达的算法翻译成机器语言表达的算法,显然毫不相干。
处理从算法语言最终表达成机器语言这一复杂过程的上述思想方法就是一种抽象。
汇编语言和高级语言的出现都是这种抽象的范例。
与汇编语言相比,高级语言的巨大成功在于它在数据、运算和控制三方面的表达中引入许多接近算法语言的概念和工具,大大地提高抽象地表达算法的能力。
在运算方面,高级语言如Pascal,除允许原封不动地运用算法语言的四则运算、逻辑运算、关系运算、算术表达式、逻辑表达式外,还引入强有力的函数与过程的工具,并让用户自定义。
这一工具的重要性不仅在于它精简了重复的程序文本段,而且在于它反映出程序的两级抽象。
在函数与过程调用级,人们只关心它能做什么,不必关心它如何做。
只是到函数与过程的定义时,人们才给出如何做的细节。
用过高级语言的读者都知道,一旦函数与过程的名称、参数和功能被规定清楚,那么,在程序中调用它们便与在程序的头部说明它们完全分开。
你可以修改甚至更换函数体与过程体,而不影响它们的被调用。
如果把函数与过程名看成是运算名,把参数看成是运算的对象或运算的结果,那么,函数与过程的调用和初等运算的引用没有两样。
利用函数和过程以及它们的复合或嵌套可以很自然地表达算法语言中任何复杂的运算。
在数据方面,高级语言如Pascal引人了数据类型的概念,即把所有的数据加以分类。
每一个数据(包括表达式)或每一个数据变量都属于其中确定的一类。
称这一类数据为一个数据类型。
因此,数据类型是数据或数据变量类属的说明,它指示该数据或数据变量可能取的值的全体。
对于无结构的数据,高级语言如Pascal,除提供标准的基本数据类型--布尔型、字符型、整型和实型外,还提供用户可自定义的枚举类型、子界类