王道学习
考纲内容
算法时间复杂度和空间复杂度的分析与计算
知识框架
复习提示
本章内容是数据结构概述,并不在考研大纲中。读者可通过对本章的学习,初步了解数据结构的基本内容和基本方法。分析算法的时间复杂度和空间复杂度是本章重点,需要熟练掌握,算法设计题通常都会要求分析时间复杂度、空间复杂度,同时会出现考察时间复杂度的选择题。
1.1 数据结构的基本概念
1.1.1 基本概念和术语
数据、数据元素、数据项和数据对象
数据(data)是对客观事物的符号表示,在计算机科学中是指所有能输入到计算机中并被计算机程序处理的符号的总称。它是计算机程序加工的“原料”。例如,一个利用数值分析方法解代数方程的程序,其处理对象是整数和实数;一个编译程序或文字处理程序的处理对象是字符串。因此,对计算机科学而言﹐数据的含义极为广泛,如图像、声音等都可以通过编码而归之于数据的范畴。
数据元素(data element)是数据的基本单位,在计算机程序中通常作为一个整体进行考虑和处理。例如,例1-2中的“树"中的一个棋盘格局,例1-3中的“图”中的一个圆圈都被称为一个数据元素。有时,一个数据元素可由若干个数据项(data item)组成,例如,例1-1中一本书的书目信息为一个数据元素,而书目信息中的每一项(如书名、作者名等)为-个数据项。数据项是数据的不可分割的最小单位。
数据对象(Data Object)是性质相同的数据元素的集合,是数据的一个子集。例如:整数数据对象是集合N={0,±1,±2,…},字母字符数据对象是集合C={‘A’,‘B’,…,‘Z’,‘a’,‘b’,…,‘z’}。
数据类型和抽象数据类型
数据类型(Data Type)是高级程序设计语言中的一个基本概念,前面提到过顺序存储结构可以借助程序设计语言的数组类型描述,链式存储结构可以借助指针类型描述,所以数据类型和数据结构的概念密切相关。
一方面,在程序设计语言中,每一个数据都属于某种数据类型。类型明显或隐含地规定了数据的取值范围、存储方式以及允许进行的运算,数据类型是一个值的集合和定义在这个值集上的一组操作的总称。例如,C语言中的整型变量,其值集为某个区间上的整数(区间大小依赖于不同的机器),定义在其上的操作为加、减、乘、除和取模等算术运算;而实型变量也有自己的取值范围和相应运算,比如取模运算是不能用于实型变量的。程序设计语言允许用户直接使用的数据类型由具体语言决定,数据类型反映了程序设计语言的数据描述和处理能力。C语言除了提供整型、实型、字符型等基本类型数据外,还允许用户自定义各种类型数据,例如数组、结构体和指针等。
抽象就是抽取出实际问题的本质。在计算机中使用二进制数来表示数据,在汇编语言中则可给出各种数据的十进制表示,它们是二进制数据的抽象,使用者在编程时可以直接使用,不必考虑实现细节。在高级语言中,则给出更高一级的数据抽象,出现了数据类型,如整型、实型、字符型等,可以进一步利用这些类型构造出线性表、栈、队列、树、图等复杂的抽象数据类型。
抽象数据类型(Abstract Data Type,ADT)一般指由用户定义的、表示应用问题的数学模型,以及定义在这个模型上的一组操作的总称,具体包括三部分:数据对象、数据对象上关系的集合以及对数据对象的基本操作的集合。
任何一个算法的设计取决于选定的数据(逻辑)结构,而算法的实现依赖于采用的存储结构。
1.1.2 数据结构的三要素
数据结构(Data Structure)是相互之间存在一种或多种特定关系的数据元素的集合。换句话说,数据结构是带“结构”的数据元素的集合,“结构”就是指数据元素之间存在的关系。
1.逻辑结构
数据的逻辑结构是从逻辑关系上描述数据,它与数据的存储无关,是独立于计算机的。因此.数据的逻辑结构可以看作是从具体问题抽象出来的数学模型。
数据的逻辑结构有两个要素:一是数据元素;二是关系。数据元素的含义如前所述,关系是指数据元素间的逻辑关系。根据数据元素之间关系的不同特性,通常有四类基本结构,如图1.3所示。它们的复杂程度依次递进。
线性结构包括线性表、栈和队列(具有特殊限制的线性表,数据操作只能在表的一端或两端进行)、字符串(也是特殊的线性表,其特殊性表现在它的数据元素仅由一个字符组成)、数组(是线性表的推广,它的数据元素是一个线性表)广义表(也是线性表的推广,它的数据元素是一个线性表,但不同构,即或者是单元素,或者是线性表)。非线性结构包括树(具有多个分支的层次结构)和二叉树(具有两个分支的层次结构)、有向图(一种图结构,边是顶点的有序对)和无向图(另一种图结构,边是顶点的无序对)。这几种逻辑结构可以用一个层次图描述,如图1.4所示。
2.存储结构
存储结构是指数据结构在计算机中的表示(又称映像),也称物理结构。它包括数据元素的表示和关系的表示。数据的存储结构是用计算机语言实现的逻辑结构,它依赖于计算机语言。数据的存储结构主要有顺序存储、链式存储、索引存储和散列存储。
1)顺序存储。把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来体现。其优点是可以实现随机存取,每个元素占用最少的存储空间;缺点是只能使用相邻的一整块存储单元,因此可能产生较多的外部碎片。
2)链式存储。不要求逻辑上相邻的元素在物理位置上也相邻,借助指示元素存储地址的指针来表示元素之间的逻辑关系。其优点是不会出现碎片现象,能充分利用所有存储单元;缺点是每个元素因存储指针而占用额外的存储空间,且只能实现顺序存取。
3)索引存储。在存储元素信息的同时,还建立附加的索引表。索引表中的每项称为索引项,索引项的一般形式是(关键字,地址)。其优点是检索速度快;缺点是附加的索引表额外占用存储空间。另外,增加和删除数据时也要修改索引表,因而会花费较多的时间。
4)散列存储。根据元素的关键字直接计算出该元素的存储地址,又称哈希(Hash)存储。其优点是检索、增加和删除结点的操作都很快;缺点是若散列函数不好,则可能出现元素存储单元的冲突,而解决冲突会增加时间和空间开销。
3.数据的运算
施加在数据上的运算包括运算的定义和实现。运算的定义是针对逻辑结构的,指出运算的功能;运算的实现是针对存储结构的,指出运算的具体操作步骤。
1.1.3 本节试题精选
3.以下关于数据结构的说法中,正确的是()。
A 数据的逻辑结构独立于其存储结构
B 数据的存储结构独立于其逻辑结构
C 数据的逻辑结构唯一决定了其存储结构
D 数据结构仅由其逻辑结构和存储结构决定
1.对于两种不同的数据结构,逻辑结构或物理结构一定不相同么?
2.试举一例,说明对相同的逻辑结构,同一种运算在不同的存储方式下实现时,其运算效率不同。
1.2 算法和算法分析
1.2.1 算法的基本概念
算法(algorithm)是对特定问题求解步骤的一种描述,它是指令的有限序列,其中每一条指令表示一个或多个操作;此外,一个算法还具有下列5个重要特性:
(1)有穷性 一个算法必须总是(对任何合法的输入值)在执行有穷步之后结束,且每一步都可在有穷时间内完成。
(2)确定性 算法中每一条指令必须有确切的含义,读者理解时不会产生二义性。并且,在任何条件下,算法只有惟一的一条执行路径,即对于相同的输入只能得出相同的输出。
(3)可行性 一个算法是能行的,即算法中描述的操作都是可以通过已经实现的基本运算执行有限次来实现的。
(4)输入 一个算法有零个或多个的输入,这些输入取自于某个特定的对象的集合。
(5)输出 一个算法有一个或多个的输出,这些输出是同输入有着某些特定关系的量。
通常,设计一个“好”的算法应考虑达到以下目标:
1)正确性。算法应能够正确地解决求解问题。
2)可读性。算法应具有良好的可读性,以帮助人们理解。
3)健壮性。输入非法数据时,算法能适当地做出反应或进行处理,而不会产生莫名其妙的输出结果。
4)效率与低存储量需求。效率是指算法执行的时间,存储量需求是指算法执行过程中所需要的最大存储空间,这两者都与问题的规模有关。
1.2.2 算法效率的度量
算法效率的度量是通过时间复杂度和空间复杂度来描述的。
1.时间复杂度
算法执行时间需通过依据该算法编制的程序在计算机上运行时所消耗的时间来度量。而度量一个程序的执行时间通常有两种方法。
(1)事后统计的方法 因为很多计算机内部都有计时功能,有的甚至可精确到毫秒级,不同算法的程序可通过一组或若干组相同的统计数据以分辨优劣。但这种方法有两个缺陷:一是必须先运行依据算法编制的程序;二是所得时间的统计量依赖于计算机的硬件、软件等环境因素,有时容易掩盖算法本身的优劣。因此人们常常采用另一种事前分析估算的方法。
(2)事前分析估算的方法 一个用高级程序语言编写的程序在计算机上运行时所消耗的时间取决于下列因素:
a.依据的算法选用何种策略﹔
b.问题的规模,例如求100以内还是1000以内的素数;
c.书写程序的语言,对于同一个算法,实现语言的级别越高,执行效率就越低;
d.编译程序所产生的机器代码的质量;
e.机器执行指令的速度。
常、对、幂、指、阶
T(n)=O(f(n))–n为问题规模大小,f(n)为每行代码执行次数的总数也就是执行次数,程序的执行时间T肯定与执行次数f(n)存在关系:T(n)=O(f(n))
2.空间复杂度
递归函数的调用的空间复杂度一般为递归调用的次数
1.2.3 本节试题精选
1.3 程序=数据结构+算法
1.4 归纳与总结
本章的重点是分析程序的时间复杂度。一定要掌握分析时间复杂度的方法和步骤,很多读者在做题时一眼就能看出程序的时间复杂度,但就是无法规范地表述其推导过程。为此,编者查阅众多资料,总结出了此类题型的两种形式,供大家参考。