文档库 最新最全的文档下载
当前位置:文档库 › 数据结构与算法大全复习资料

数据结构与算法大全复习资料

数据结构与算法大全复习资料
数据结构与算法大全复习资料

何谓数据结构

数据结构是在整个计算机科学与技术领域上广泛被使用的术语。它用来反映一个数据的内部构成,即一个数据由那些成分数据构成,以什么方式构成,呈什么结构。数据结构有逻辑上的数据结构和物理上的数据结构之分。逻辑上的数据结构反映成分数据之间的逻辑关系,而物理上的数据结构反映成分数据在计算机内部的存储安排。数据结构是数据存在的形式。

数据结构是信息的一种组织方式,其目的是为了提高算法的效率,它通常与一组算法的集合相对应,通过这组算法集合可以对数据结构中的数据进行某种操作。

数据结构主要研究什么?

数据结构作为一门学科主要研究数据的各种逻辑结构和存储结构,以及对数据的各种操作。因此,主要有三个方面的内容:数据的逻辑结构;数据的物理存储结构;对数据的操作(或算法)。通常,算法的设计取决于数据的逻辑结构,算法的实现取决于数据的物理存储结构。

什么是数据结构?什么是逻辑结构和物理结构?

数据是指由有限的符号(比如,"0"和"1",具有其自己的结构、操作、和相应的语义)组成的元素的集合。结构是元素之间的关系的集合。通常来说,一个数据结构DS可以表示为一个二元组:

DS=(D,S), //i.e., data-structure=(data-part,logic-structure-part)

这里D是数据元素的集合(或者是“结点”,可能还含有“数据项”或“数据域”),S是定义在D(或其他集合)上的关系的集合,S = { R | R : D×D×...},称之为元素的逻辑结构。

逻辑结构有四种基本类型:集合结构、线性结构、树状结构和网络结构。表和树是最常用的两种高效数据结构,许多高效的算法可以用这两种数据结构来设计实现。表是线性结构的(全序关系),树(偏序或层次关系)和图(局部有序(weak/local orders))是非线性结构。

数据结构的物理结构是指逻辑结构的存储镜像(image)。数据结构DS的物理结构P 对应于从DS 的数据元素到存储区M(维护着逻辑结构S)的一个映射:P:(D,S)--> M

存储器模型:一个存储器M是一系列固定大小的存储单元,每个单元U有一个唯一的地址A(U),该地址被连续地编码。每个单元U 有一个唯一的后继单元U'=succ(U)。

P 的四种基本映射模型:顺序(sequential)、链接(linked)、索引(indexed)和散列(hashing)映射。

(并不是所有的可能组合都合理)

数据结构DS上的操作:所有的定义在DS上的操作在改变数据元素(节点)或节点的域时必须保持DS的逻辑和物理结构。

DS上的基本操作:任何其他对DS的高级操作都可以用这些基本操作来实现。最好将DS 和他的所有基本操作看作一个整体——称之为模块。我们可以进一步将该模块抽象为数据类型(其中DS的存储结构被表示为私有成员,基本操作被表示为公共方法),称之为ADT。作为ADT,堆栈和队列都是一种特殊的表,他们拥有表的操作的子集。

对于DATs的高级操作可以被设计为(不封装的)算法,利用基本操作对DS进行处理。

好的和坏的DS:如果一个DS可以通过某种“线性规则”被转化为线性的DS(例如线性表),则称它为好的DS。好的DS通常对应于好的(高效的)算法。这是由计算机的计算能力决定的,因为计算机本质上只能存取逻辑连续的内存单元,因此如何没有线性化的结构逻辑上是不可计算的。比如对一个图进行操作,要访问图的所有结点,则必须按照某种顺序来依次访问所有节点(要形成一个偏序),必须通过某种方式将图固有的非线性结构转化为线性结构才能对图进行操作。

树是好的DS——它有非常简单而高效的线性化规则,因此可以利用树设计出许多非常高效的算法。树的实现和使用都很简单,但可以解决大量特殊的复杂问题,因此树是实际编程中最重要和最有用的一种数据结构。树的结构本质上有递归的性质——每一个叶节点可以被一棵子树所替代,反之亦然。实际上,每一种递归的结构都可以被转化为(或等价于)树形结构。

计算机中数据的描述方式

我们知道,数据可以用不同的形式进行描述或存储在计算机存储器中。最常见的数据描述方法有:公式化描述、链接描述、间接寻址和模拟指针。

?公式化描述借助数学公式来确定元素表中的每个元素分别存储在何处,也就通过公式计算元素的存储器地址。最简单的情形就是把所有元素依次连续存储在一片连续

的存储空间中,这就是通常所说的连续线性表,即数组。复杂一点的情形是利用复

杂的函数关系根据元素的某些特征来计算元素在内存中的位置,这种技术称为散列

技术(Hash,经常音译为哈希技术)。

?在链接描述中,元素表中的每个元素可以存储在存储器的不同区域中,每个元素都包含一个指向下一个元素的指针。这就是通常所说的链表。这种描述方法的好处是,知道了第一个元素的位置,就可以依次找到第n个元素的位置,而且在其中插入元

素非常方便,缺点是查找某个元素要遍历所有在该元素之前的元素,实际应用中经

常和公式化描述结合起来使用。

?在间接寻址方式中,元素表中的每个元素也可以存储在存储器的不同区域中,不同的是,此时必须保存一张表,该表的第i项指向元素表中的第i个元素,所以这张表是一个用来存储元素地址的表。指针数组(元素为指针的数组)就是这种描述法的

应用。这种描述方法是公式化描述和链接描述的一种折衷方案,同时具有两种描述

方法的优点,但是需要额外的内存开销。

?模拟指针非常类似于链接描述,区别在于它用整数代替了指针,整数所扮演的角色与指针所扮演的角色完全相同。模拟指针的描述方式是链接描述和公式化描述的结

合,元素被存储在不同的区域中,每个元素包含一个指示下一个元素位置的整数,

可以通过某种公式由该整数计算出下一个元素的存储器地址。线性表的游标实现就

是模拟指针描述法。

算法Algorithm

算法是在有限步骤内求解某一问题所使用的一组定义明确的规则。通俗点说,就是计算机解题的过程。在这个过程中,无论是形成解题思路还是编写程序,都是在实施某种算法。前者是推理实现的算法,后者是操作实现的算法。

一个算法应该具有以下五个重要的特征:

1.有穷性:一个算法必须保证执行有限步之后结束;

2.确切性:算法的每一步骤必须有确切的定义;

3.输入:一个算法有0个或多个输入,以刻画运算对象的初始情况,所谓0个输

入是指算法本身定除了初始条件;

4.输出:一个算法有一个或多个输出,以反映对输入数据加工后的结果。没有输

出的算法是毫无意义的;

5.可行性:算法原则上能够精确地运行,而且人们用笔和纸做有限次运算后即

可完成。

Did you know

Algorithm一词的由来

Algorithm(算法)一词本身就十分有趣。初看起来,这个词好像是某人打算要写“Logarithm”(对数)一词但却把头四个字母写的前后颠倒了。这个词一直到1957年之前在Webster's New World Dictionary(《韦氏新世界词典》)中还未出现,我们只能找到带有它的古代涵义的较老形式的“Algorism”(算术),指的是用阿拉伯数字进行算术运算的过程。在中世纪时,珠算家用算盘进行计算,而算术家用算术进行计算。中世纪之后,对这个词的起源已经拿不准了,早期的语言学家试图推断它的来历,认为它是从把algiros(费力

的)+arithmos(数字)组合起来派生而成的,但另一些人则不同意这种说法,认为这个词是从“喀斯迪尔国王Algor”派生而来的。最后,数学史学家发现了algorism(算术)一词的真实起源:它来源于著名的Persian Textbook(《波斯教科书》)的作者的名字Abu Ja'far Mohammed ibn M?sa al-Khowarizm (约公元前825年)——从字面上看,这个名字的意思是“Ja'far 的父亲,Mohammed 和M?sa的儿子,Khowarizm 的本地人”。Khowarizm 是前苏联XИBA(基发) 的小城镇。Al-Khowarizm 写了著名的书Kitab al jabr w'al-muqabala (《复原和化简的规则》);另一个词,“algebra”(代数),是从他的书的标题引出来的,尽管这本书实际上根本不是讲代数的。

逐渐地,“algorism”的形式和意义就变得面目全非了。如牛津英语字典所说明的,这个词是由于同arithmetic(算术)相混淆而形成的错拼词。由algorism又变成algorithm。一本早期的德文数学词典Vollstandiges Mathematisches Lexicon (《数学大全辞典》) ,给出了Algorithmus (算法)一词的如下定义:“在这个名称之下,组合了四种类型的算术计算的概念,即加法、乘法、减法、除法”。拉顶短语algorithmus infinitesimalis (无限小方法) ,在当时就用来表示Leibnitz(莱布尼兹)所发明的以无限小量进行计算的微积分方法。

1950年左右,algorithm一词经常地同欧几里德算法(Euclid's algorithm)联系在一起。这个算法就是在欧几里德的《几何原本》(Euclid's Elements ,第VII卷,命题i和ii)中所阐述的求两个数的最大公约数的过程(即辗转相除法)。

伪代码的使用Usage of Pseudocode

伪代码(Pseudocode)是一种算法描述语言。使用为代码的目的是为了使被描述的算法可以容易地以任何一种编程语言(Pascal, C, Java, etc)实现。因此,伪代码必须结构清晰,代码简单,可读性好,并且类似自然语言。

下面介绍一种类Pascal语言的伪代码的语法规则。

伪代码的语法规则

1.在伪代码中,每一条指令占一行(else if例外,),指令后不跟任何符号(Pascal

和C中语句要以分号结尾);

2.书写上的“缩进”表示程序中的分支程序结构。这种缩进风格也适用于

if-then-else语句。用缩进取代传统Pascal中的begin和end语句来表示程序的块结构可以大大提高代码的清晰性;同一模块的语句有相同的缩进量,次一级模块的语句

相对与其父级模块的语句缩进;

例如:

line 1

line 2

sub line 1

sub line 2

sub sub line 1

sub sub line 2

sub line 3

line 3

而在Pascal中这种关系用begin和end的嵌套来表示, line 1

line 2

begin

sub line 1

sub line 2

begin

sub sub line 1

sub sub line 2

end;

sub line 3

end;

line 3

在C中这种关系用{ 和} 的嵌套来表示,

line 1

line 2

{

sub line 1

sub line 2

{

sub sub line 1

sub sub line 2

}

sub line 3

}

line 3

3.在伪代码中,通常用连续的数字或字母来标示同一即模块中的连续语句,有时也可省略标号。

例如:

1. line 1

2. line 2

a. sub line 1

b. sub line 2

1. sub sub line 1

2. sub sub line 2

c. sub line 3

3. line 3

4.符号△后的内容表示注释;

5.在伪代码中,变量名和保留字不区分大小写,这一点和Pascal相同,与C或C++不同;

6.在伪代码中,变量不需声明,但变量局部于特定过程,不能不加显示的说明就使用全局变量;

7.赋值语句用符号←表示,x←exp表示将exp的值赋给x,其中x是一个变量,exp是一个与x同类型的变量或表达式(该表达式的结果与x同类型);多重赋值i←j←e是将表达式e的值赋给变量i和j,这种表示与j←e和i←e等价。

例如:

x←y

x←20*(y+1)

x←y←30

以上语句用Pascal分别表示为:

x := y;

x := 20*(y+1);

x := 30; y := 30;

以上语句用C分别表示为:

x = y;

x = 20*(y+1);

x = y = 30;

8.选择语句用if-then-else来表示,并且这种if-then-else可以嵌套,与Pascal中的if-then-else没有什么区别。

例如:

if (Condition1)

then [ Block 1 ]

else if (Condition2)

then [ Block 2 ]

else [ Block 3 ]

9.循环语句有三种:while循环、repeat-until循环和for循环,其语法均与Pascal 类似,只是用缩进代替begin - end;

例如:

1. x ← 0

2. y ← 0

3. z ← 0

4. while x < N

1. do x ← x + 1

2. y ← x + y

3. for t ← 0 to 10

1. do z ← ( z + x * y ) / 100

2. repeat

1. y ← y + 1

2. z ← z - y

3. until z < 0

4. z ← x * y

5. y ← y / 2

上述语句用Pascal来描述是:

x := 0;

y := 0;

z := 0;

while x < N do

begin

x := x + 1;

y := x + y;

for t := 0 to 10 do

begin

z := ( z + x * y ) / 100;

repeat

y := y + 1;

z := z - y;

until z < 0;

end;

z := x * y;

end;

y := y / 2;

上述语句用C或C++来描述是:

x = y = z = 0;

while( z < N )

{

x ++;

y += x;

for( t = 0; t < 10; t++ )

{

z = ( z + x * y ) / 100;

do {

y ++;

z -= y;

} while( z >= 0 );

}

z = x * y;

}

y /= 2;

10.数组元素的存取有数组名后跟“[下标]”表示。例如A[j]指示数组A的第j个元素。符号“ …”用来指示数组中值的范围。

例如:

A[1…j]表示含元素A[1], A[2], … , A[j]的子数组;

11.复合数据用对象(Object)来表示,对象由属性(attribute)和域(field)构成。域的存

取是由域名后接由方括号括住的对象名表示。

例如:

数组可被看作是一个对象,其属性有length,表示其中元素的个数,则length[A]就

表示数组A中的元素的个数。在表示数组元素和对象属性时都要用方括号,一般来

说从上下文可以看出其含义。

用于表示一个数组或对象的变量被看作是指向表示数组或对象的数据的一个指针。

对于某个对象x的所有域f,赋值y←x就使f[y]=f[x],更进一步,若有f[x]←3,则

不仅有f[x]=3,同时有f[y]=3,换言之,在赋值y←x后,x和y指向同一个对象。

有时,一个指针不指向任何对象,这时我们赋给他nil。

12.函数和过程语法与Pascal类似。

函数值利用“return (函数返回值)” 语句来返回,调用方法与Pascal类似;过程用

“call 过程名”语句来调用;

例如:

1. x ← t + 10

2. y ← sin(x)

3. call CalValue(x,y)

参数用按值传递方式传给一个过程:被调用过程接受参数的一份副本,若他对某个

参数赋值,则这种变化对发出调用的过程是不可见的。当传递一个对象时,只是拷

贝指向该对象的指针,而不拷贝其各个域。

算法的复杂性

傅清祥王晓东

算法与数据结构, 电子工业出版社,1998

摘要

本文介绍了算法的复杂性的概念和衡量方法,并提供了一些计算算法的复杂性的渐近阶的方法。

目录

?简介

?比较两对算法的效率

?复杂性的计量

?复杂性的渐近性态及其阶

?复杂性渐近阶的重要性

?算法复杂性渐近阶的分析

?递归方程组的渐近阶的求法

? 1.代入法

? 2.迭代法

? 3.套用公式法

? 4.差分方程法

? 5.母函数法

简介

算法的复杂性是算法效率的度量,是评价算法优劣的重要依据。一个算法的复杂性的高低体现在运行该算法所需要的计算机资源的多少上面,所需的资源越多,我们就说该算法的复杂性越高;反之,所需的资源越低,则该算法的复杂性越低。

计算机的资源,最重要的是时间和空间(即存储器)资源。因而,算法的复杂性有时间复杂性和空间复杂性之分。

不言而喻,对于任意给定的问题,设计出复杂性尽可能地的算法是我们在设计算法是追求的一个重要目标;另一方面,当给定的问题已有多种算法时,选择其中复杂性最低者,是我们在选用算法适应遵循的一个重要准则。因此,算法的复杂性分析对算法的设计或选用有着重要的指导意义和实用价值。

关于算法的复杂性,有两个问题要弄清楚:

1.用怎样的一个量来表达一个算法的复杂性;

2.对于给定的一个算法,怎样具体计算它的复杂性。

让我们从比较两对具体算法的效率开始。

比较两对算法的效率

考虑问题1:已知不重复且已经按从小到大排好的m个整数的数组A[1..m](为简单起见。还设m=2 k,k是一个确定的非负整数)。对于给定的整数c,要求寻找一个下标i,使得A[i]=c;若找不到,则返回一个0。

问题1的一个简单的算法是:从头到尾扫描数组A。照此,或者扫到A的第i个分量,经检测满足A[i]=c;或者扫到A的最后一个分量,经检测仍不满足A[i]=c。我们用一个函数Search来表达这个算法:

Function Search (c:integer):integer;

Var J:integer;

Begin

J:=1; {初始化}

{在还没有到达A的最后一个分量且等于c的分量还没有找到时,

查找下一个分量并且进行检测}

While (A[i]

j:=j+1;

If A[j]=c then search:=j {在数组A中找到等于c的分量,且此分量的下标为j}

else Search:=0; {在数组中找不到等于c的分量}

End;

容易看出,在最坏的情况下,这个算法要检测A的所有m个分量才能判断在A中找不到等于c的分量。

解决问题1的另一个算法利用到已知条件中A已排好序的性质。它首先拿A的中间分量A[m/2]与c比较,如果A[m/2]=c则解已找到。如果A[m/2]>c,则c只可能在

A[1],A[2],..,A[m/2-1]之中,因而下一步只要在A[1], A[2], .. ,A[m/2-1]中继续查找;如果

A[m/2]

A[m/2+1],A[m/2+2],..,A[m]中继续查找。不管哪一种情形,都把下一步需要继续查找的范围缩小了一半。再拿这一半的子数组的中间分量与c比较,重复上述步骤。照此重复下去,总

有一个时候,或者找到一个i使得A[i]=c,或者子数组为空(即子数组下界大于上界)。前一种情况找到了等于c的分量,后一种情况则找不到。

这个新算法因为有反复把供查找的数组分成两半,然后在其中一半继续查找的特征,我们称为二分查找算法。它可以用函数B_Search来表达:

Function B_Search ( c: integer):integer;

Var

L,U,I : integer; {U和L分别是要查找的数组的下标的上界和下界}

Found: boolean;

Begin

L:=1; U:=m; {初始化数组下标的上下界}

Found:=false; {当前要查找的范围是A[L]..A[U]。}

{当等于c的分量还没有找到且U>=L时,继续查找}

While (not Found) and (U>=L) do

Begin

I:=(U+L) div 2; {找数组的中间分量}

If c=A[I] then Found:=Ture

else if c>A[I] then L:=I+1

else U:=I-1;

End;

If Found then B_Search:=1

else B_Search:=0;

End;

容易理解,在最坏的情况下最多只要测A中的

k+1(k=logm,这里的log以2为底,下同)个分量,就判

断c是否在A中。

算法Search和B_Search解决的是同一个问题,

但在最坏的情况下(所给定的c不在A中),两个算法

所需要检测的分量个数却大不相同,前者要m=2 k个,

后者只要k+1个。可见算法B_Search比算法Search

高效得多。

以上例子说明:解同一个问题,算法不同,则计算

的工作量也不同,所需的计算时间随之不同,即复杂性

不同。

上图是运行这两种算法的时间曲线。该图表明,当m适当大(m>m0)时,算法B_Search 比算法Search省时,而且当m更大时,节省的时间急剧增加。

不过,应该指出:用实例的运行时间来度量算法的时间复杂性并不合适,因为这个实例时间与运行该算法的实际计算机性能有关。换句话说,这个实例时间不单纯反映算法的效率而是反映包括运行该算法的计算机在内的综合效率。我们引入算法复杂性的概念是为了比较解决同一个问题的不同算法的效率,而不想去比较运行该算法的计算机的性能。因而,不应该取算法运行的实例时间作为算法复杂性的尺度。我们希望,尽量单纯地反映作为算法精

髓的计算方法本身的效率,而且在不实际运行该算法的情况下就能分析出它所需要的时间和空间。

复杂性的计量

算法的复杂性是算法运行所需要的计算机资源的量,需要的时间资源的量称作时间复杂性,需要的空间(即存储器)资源的量称作空间复杂性。这个量应该集中反映算法中所采用的方法的效率,而从运行该算法的实际计算机中抽象出来。换句话说,这个量应该是只依赖于算法要解的问题的规模、算法的输入和算法本身的函数。如果分别用N、I和A来表示算法要解问题的规模、算法的输入和算法本身,用C表示算法的复杂性,那么应该有:

C =F(N,I,A)

其中F(N,I,A)是N,I,A的一个确定的三元函数。如果把时间复杂性和空间复杂性分开,并分别用T和S来表示,那么应该有:

T =T(N,I,A) (2.1)

和S =S(N,I,A) (2.2)

通常,我们让A隐含在复杂性函数名当中,因而将(2.1)和(2.2)分别简写为T =T(N,I)

和S =S(N,I)

由于时间复杂性和空间复杂性概念类同,计算方法相似,且空间复杂性分析相对地简单些,所以下文将主要地讨论时间复杂性。

下面以T(N,I)为例,将复杂性函数具体化。

根据T(N,I)的概念,它应该是算法在一台抽象的计算机上运行所需的时间。设此抽象的计算机所提供的元运算有k种,他们分别记为O1,O2 ,..,O k;再设这些元运算每执行一次所需要的时间分别为t1,t2,..,t k。对于给定的算法A,设经过统计,用到元运算O i的次数为e i,i=1,2,..,k,很明显,对于每一个i,1<=i<=k,e i是N和I的函数,即e i=e i(N,I)。那么有:

(2.

其中t i,i=1,2,..,k,是与N,I无关的常数。

显然,我们不可能对规模N的每一种合法的输入I都去统计e i(N,I),i=1,2,…,k。因此T(N,I)的表达式还得进一步简化,或者说,我们只能在规模为N的某些或某类有代表性的合法输入中统计相应的e i, i=1,2,…,k,评价时间复杂性。

下面只考虑三种情况的复杂性,即最坏情况、最好情况和平均情况下的时间复杂性,并分别记为T max(N )、T min(N)和T avg(N )。在数学上有:

(2.

(2.

(2.

其中,D N是规模为N的合法输入的集合;I *是D N中一个使T(N,I *)达到T max(N)的合法输入,是D N中一个使T(N,)到T min(N)的合法输入;而P(I)是在算法的应用中出现输入I 的概率。

以上三种情况下的时间复杂性各从某一个角度来反映算法的效率,各有各的用处,也各有各的局限性。但实践表明可操作性最好的且最有实际价值的是最坏情况下的时间复杂性。下面我们将把对时间复杂性分析的主要兴趣放在这种情形上。

一般来说,最好情况和最坏情况的时间复杂性是很难计量的,原因是对于问题的任意确定的规模N达到了T max(N)的合法输入难以确定,而规模N的每一个输入的概率也难以预测或确定。我们有时也按平均情况计量时间复杂性,但那时在对P(I)做了一些人为的假设(比如等概率)之后才进行的。所做的假设是否符合实际总是缺乏根据。因此,在最好情况和平均情况下的时间复杂性分析还仅仅是停留在理论上。

现在以上一章提到的问题1的算法Search为例来说明如何利用(2.4)-(2.6)对它的T max、T min和T avg进行计量。这里问题的规模以m计算,算法重用到的元运算有赋值、测试和加法等三种,它们每执行一次所需的时间常数分别为a,t,和s 。对于这个例子,如假设c在A 中,那么容易直接看出最坏情况的输入出现在c=A[m]的情形,这时:

T max(m)=a+2mt+(m-1)s+(m-1)a+t+a=(m+1)a+(2m+1)t+(m-1)s (2.7)

而最好情况的输入出现在c=A[1]的情形。这时:

(2.

至于T avg(m),如前所述,必须对D m上的概率分布做出假设才能计量。为简单起见,我们做最简单的假设:D m上的概率分布是均等的,即P(A[i]=c)=1/m 。若记T i=T(m,I i),其中I i表示A[i]=c的合法输入,那么:

(2.

而根据与(2.7)类似的推导,有:

代入(2.9) ,则:

这里碰巧有:

T avg(m)=(T max(m)+T min(m))/2

但必须指出,上式并不具有一般性。

类似地,对于算法B_Search照样可以按(2.4)-(2.6)计算相应的T max(m)、T min(m)和

T avg(m)。不过,我们这里只计算T max(m) 。为了与Search比较,仍假设c在A中,即最坏情况的输入仍出现在c=A[m]时。这时,while循环的循环体恰好被执行了log m +1 即k+1 次。因为第一次执行时数据的规模为m,第二次执行时规模为m/2等等,最后一次执行时规模为1。另外,与Search少有不同的是这里除了用到赋值、测试和加法三种原运算外,还用到减法和除法两种元运算。补记后两种元运算每执行一次所需时间为b和d ,则可以推演出:

(2.

比较(2.7)和(2.10) ,我们看到m充分大时,在最坏情况下B_Search的时间复杂性远小于Search的时间复杂性。

复杂性的渐近性态及其阶

随着经济的发展、社会的进步、科学研究的深入,要求用计算机解决的问题越来越复杂,规模越来越大。但是,如果对这类问题的算法进行分析用的是第二段所提供的方法,把所有的元运算都考虑进去,精打细算,那么,由于问题的规模很大且结构复杂,算法分析的工作量之大、步骤之繁将令人难以承受。因此,人们提出了对于规模充分大、结构又十分复杂的问题的求解算法,其复杂性分析应如何简化的问题。

我们先要引入复杂性渐近性态的概念。设T(N)是在第二段中所定义的关于算法A的复杂性函数。一般说来,当N单调增加且趋于∞时,T(N)也将单调增加趋于∞。对于T(N),如果存在T’(N),使得当N→∞时有:

(T(N )-T’(N ))/T(N ) → 0

那么,我们就说T’(N)是T(N)当N→∞时的渐近性态,或叫T’(N)为算法A当N→∞的渐近复杂性而与T(N)相区别,因为在数学上,T’(N)是T(N)当N→∞时的渐近表达式。

直观上,T’(N)是T(N)中略去低阶项所留下的主项。所以它无疑比T(N)来得简单。比如当

T(N)=3N 2+4N log2N +7

时,T’(N)的一个答案是3N 2,因为这时有:

显然3N 2比3N 2 +4N log2N +7简单得多。

由于当N→∞时T(N)渐近于T’(N),我们有理由用T’(N)来替代T(N)作为算法A在N→∞时的复杂性的度量。而且由于于T’(N)明显地比T(N)简单,这种替代明显地是对复杂性分析的一种简化。

进一步,考虑到分析算法的复杂性的目的在于比较求解同一间题的两个不同算法的效率,而当要比较的两个算法的渐近复杂性的阶不相同时,只要能确定出各自的阶,就可以判定哪一个算法的效率高。换句话说,这时的渐近复杂性分析只要关心T’(N)的阶就够了,不必关心包含在T’(N)中的常数因子。所以,我们常常又对T’(N)的分析进--步简化,即假设算法中用到的所有不同的元运算各执行一次,所需要的时间都是一个单位时间。

综上所述,我们已经给出了简化算法复杂性分析的方法和步骤,即只要考察当问题的规模充分大时,算法复杂性在渐近意义下的阶。与此简化的复杂性分析方法相配套,需要引入五个渐近意义下的记号:Ο、Ω、θ、ο和ω。

以下设f(N)和g(N)是定义在正数集上的正函数。

如果存在正的常数C和自然数N0,使得当N≥N0时有f(N)≤Cg(N)。则称函数f(N)当N 充分大时上有界,且g(N)是它的一个上界,记为f(N)=Ο(g(N))。这时我们还说f(N)的阶不高于g(N)的阶。

举几个例子:

(1)因为对所有的N≥1有3N≤4N,我们有3N =Ο(N);

(2)因为当N≥1时有N+1024≤1025N,我们有N +1024=Ο(N);

(3)因为当N≥10时有2N 2+11N -10≤3N 2,我们有2N 2+11N -10=Ο(N 2);

(4)因为对所有N≥1有N 2≤N 3,我们有N2=Ο(N 3);

(5)作为一个反例N 3≠Ο(N 2)。因为若不然,则存在正的常数C和自然数N0,使得当N≥N0时有N3≤C N 2,即N≤C。显然当取N =max(N0,[C]+l)时这个不等式不成立,所以N3≠Ο(N 2)。按照大Ο的定义,容易证明它有如下运算规则:

1.Ο(f)+Ο(g)=Ο(max(f,g));

2.Ο(f)+Ο(g)=Ο(f +g);

3.Ο(f)·Ο(g)=Ο(f·g);

4.如果g(N)=Ο(f(N)),则Ο(f)+Ο(g)=Ο(f);

5.Ο(Cf(N))=Ο(f(N)),其中C是一个正的常数;

6.f =Ο(f);

规则1的证明:

设F(N)=Ο(f) 。根据记号Ο的定义,存在正常数C1和自然数N1,使得对所有的N≥N1,有F(N)≤C1 f(N)。类似地,设G(N)=Ο(g),则存在正的常数C2和自然数N2使得对所有的N≥N2有G(N)≤C2g(N),今令:

C3=max(C1, C2)

N3=max(N1, N2)

和对任意的非负整数N,

h(N)=max(f,g),

则对所有的N≥N3有:

F(N)≤C1f(N)≤C1h(N)≤C3h(N)

类似地,有:

G(N)≤C2g(N)≤C2h(N)≤C3h(N)

因而

Ο(f)+Ο(g) =F(N)+G(N)≤C3h(N)+ C3h(N)

=2C3h(N)

=Ο(h)

=Ο(max(f,g))

其余规则的证明类似,请读者自行证明。

应用这些规则的一个例子:对于第一章中的算法search,在第二章给出了它的最坏情况下时间复杂性T max(m)和平均情况下的时间复杂性T avg(m)的表达式。如果利用上述规则,立即有:

T max(m)=Ο(m)

和T avg(m)=Ο(m)+Ο(m)+Ο(m)=Ο(m)

另一个例子:估计下面二重循环算法段在最坏情况下的时间复杂性T(N)的阶。

for i:=l to N do

for j:=1 to i do

begin

S1;

S2;

S3;

S4;

end;

其中S k (k=1,2,3,4)是单一的赋值语句。对于内循环体,显然只需Ο(l)时间。因而内循环只需

时间。累加起来便是外循环的时间复杂性:

应该指出,根据记号Ο的定义,用它评估算法的复杂性,得到的只是当规模充分大时的一个上界。这个上界的阶越低则评估就越精确,结果就越有价值。

关于记号Ω,文献里有两种不同的定义。本文只采用其中的一种,定义如下:如果存在正的常数C和自然数N0,使得当N≥N0时有f(N)≥Cg(N),则称函数f(N)当N充分大时下有界,且g(N)是它的一个下界,记为f(N)=Ω(g(N))。这时我们还说f(N)的阶不低于g(N)的阶。

Ω的这个定义的优点是与Ο的定义对称,缺点是当f(N)对自然数的不同无穷子集有不同的表达式,且有不同的阶时,未能很好地刻画出f(N)的下界。比如当:

时,如果按上述定义,只能得到f(N)=Ω(1),这是一个平凡的下界,对算法分析没有什么价值。

然而,考虑到Ω的上述定义有与Ο的定义的对称性,又考虑到常用的算法都没出现上例中那种情况,所以本文还是选用它。

我们同样也可以列举Ω的一些运算规则。但这里从略,只提供一个应用的例子。还是考虑算法Search在最坏情况下的时间复杂性函数T max(m)。由它的表达式(2.7)及已知a,s,t 均为大于0的常数,可推得,当m≥1时有:

T max(m)≥(m+1)a+(2m+1)t>ma+2mt=(a+2t)m,

于是T max(m)=Ω(m)。

我们同样要指出,用Ω评估算法的复杂性,得到的只是该复杂性的一个下界。这个下界的阶越高,则评估就越精确,结果就越有价值。再则,这里的Ω只对问题的一个算法而言。如果它是对一个问题的所有算法或某类算法而言,即对于一个问题和任意给定的充分大的规模N,下界在该问题的所有算法或某类算法的复杂性中取,那么它将更有意义。这时得到的相应下界,我们称之为问题的下界或某类算法的下界。它常常与Ο配合以证明某问题的一个特定算法是该问题的最优算法或该问题在某算法类中的最优算法。

明白了记号Ο和Ω之后,记号θ将随之清楚,因为我们定义f(N)=θ(g(N))则f(N)=Ο(g(N)) 且f(N)=Ω(g(N))。这时,我们说f(N)与g(N)同阶。比如,对于算法Search在最坏情况下的

时间复杂性T max(m)。已有T max(m)=Ο(m)和T max(m)=Ω(m),所以有T max(m)=θ(m),这是对T max(m)的阶的精确估计。

最后,如果对于任意给定的ε≥0,都存在非负整数N0,使得当N≥N0时有f(N)≤εg(N),则称函数f(N)当N充分大时比g(N)低阶,记为f(N)= o(g(N)),例如:

4N log N +7=o(3N 2+4N log N+7);而f(N)=ω(g(N))定义为g(N)=o(f(N))。

即当N充分大时f(N)的阶比g(N)高。我们看到o对于Ο有如ω对于Ω。

复杂性渐近阶的重要性

计算机的设计和制造技术在突飞猛进,一代又一代的计算机的计算速度和存储容量在直线增长。有的人因此认为不必要再去苦苦地追求高效率的算法,从而不必要再去无谓地进行复杂性的分析。他们以为低效的算法可以由高速的计算机来弥补,以为在可接受的一定时间内用低效的算法完不成的任务,只要移植到高速的计算机上就能完成。这是一种错觉。造成这种错觉的原因是他们没看到:随着经济的发展、社会的进步、科学研究的深入,要求计算机解决的问题越来越复杂、规模越来越大,也呈线性增长之势;而问题复杂程度和规模的线性增长导致的时耗的增长和空间需求的增长,对低效算法来说,都是超线性的,决非计算机速度和容量的线性增长带来的时耗减少和存储空间的扩大所能抵销。事实上,我们只要对效率上有代表性的几个档次的算法作些简单的分析对比就能明白这一点。

我们还是以时间效率为例。设A1,A2,...和A6。是求解同一间题的6个不同的算法,它们的渐近时间复杂性分别为N,N log N,N 2,N 3,2N,N!。让这六种算法各在C1和C2两台计算机上运行,并设计算机C2的计算速度是计算机C1的10倍。在可接受的一段时间内,设在C1上算法A i可能求解的问题的规模为N1i,而在C2上可能求解的问题的规模为N2i,那么,我们就应该有T i(N2i)=10T i(N1i),其中T i(N)是算法A i渐近的时间复杂性,i=1,2, (6)

分别解出N2i和N1i的关系,可列成下表:

1

倍,可求解的规模同步增长10倍;对于A2,可求解的问题的规模的增长与计算机的计算速度的增长接近同步;但对于低效的算法A3,情况就大不相同,计算机的计算速度增长10倍只换取可求解的问题的规模增加log10。当问题的规模充分大时,这个增加的数字是微不足道的。换句话说,对于低效的算法,计算机的计算速度成倍乃至数10倍地增长基本上不带来求解规模的增益。因此,对于低效算法要扩大解题规模,不能寄希望于移植算法到高速的计算机上,而应该把着眼点放在算法的改进上。

从表4-l的最后一列我们还看到,限制求解问题规模的关键因素是算法渐近复杂性的阶,对于表中的前四种算法,其渐近的时间复杂性与规模N的一个确定的幂同阶,相应地,计算机的计算速度的乘法增长带来的是求解问题的规模的乘法增长,只是随着幂次的提高,规模增长的倍数在降低。我们把渐近复杂性与规模N的幂同阶的这类算法称为多项式算法。对于表中的后两种算法,其渐近的时间复杂性与规模N的一个指数函数同阶,相应地计算

机的计算速度的乘法增长只带来求解问题规模的加法增长。我们把渐近复杂性与规模N的指数同阶的这类算法称为指数型算法。多项式算法和指数型算法是在效率上有质的区别的两类算法。这两类算法的区别的内在原因是算法渐近复杂性的阶的区别。可见,算法的渐近复杂性的阶对于算法的效率有着决定性的意义。所以在讨论算法的复杂性时基本上都只关心它的渐近阶。

多项式算法是有效的算法。绝大多数的问题都有多项式算法。但也有一些问题还未找到多项式算法,只找到指数型算法。

我们在讨论算法复杂性的渐近阶的重要性的同时,有两条要记住:

1.“复杂性的渐近阶比较低的算法比复杂性的渐近阶比较高的算法有效”这个结

论,只是在问题的求解规模充分大时才成立。比如算法A4比A5有效只是在N 3<2N,即N≥c 时才成立。其中c是方程N 3=2N的解。当N

所说,复杂性阶比较低的算法在规模小时不一定比复杂性阶比较高的算法更有效;

另方面,在规模小时,决定工作效率的可能不是算法的效率而是算法的简单性,哪

一种算法简单,实现起来快,就选用那一种算法。

2.当要比较的两个算法的渐近复杂性的阶相同时,必须进一步考察渐近复杂性表

达式中常数因子才能判别它们谁好谁差。显然常数因子小的优于常数因子大的算法。

比如渐近复杂性为N1og N/l00的算法显然比渐近复杂性为l00N log N的算法来得有

效。

算法复杂性渐近阶的分析

前两段讲的是算法复杂性渐近阶的概念和对它进行分析的重要性。本段要讲如何具体地分析一个算法的复杂性的渐近阶,给出一套可操作的规则。算法最终要落实到用某种程序设计语言(如Pascal)编写成的程序。因此算法复杂性渐近阶的分析可代之以对表达该算法的程序的复杂性渐近阶的分析。

如前所提出,对于算法的复杂性,我们只考虑最坏、最好和平均三种情况,而通常又着重于最坏情况。为了明确起见,本段限于针对最坏情况。

仍然以时间复杂性为例。这里给出分析时间复杂性渐近阶的八条规则。这八条规则已覆盖了用Pascal语言程序所能表达的各种算法在最坏情况下的时间复杂性渐近阶的分析。

在逐条地列出并解释这入条规则之前,应该指出,当我们分析程序的某一局部(如一个语句,一个分程序,一个程序段,一个过程或函数)时,可以用具体程序的输入的规模N作为复杂性函数的自变量,也可以用局部的规模参数作为自变量。但是,作为最终结果的整体程序的复杂性函数只能以整体程序的输入规模为自变量。

对于串行的算法,相应的Pascal程序是一个串行的Pascal语句序列,因此,很明显,该算法的时间复杂性(即所需要的时间)等于相应的Pascal程序的每一个语句的时间复杂性(即所需要的时间)之和。所以,如果执行Pascal语句中的每一种语句所需要的时间都有计量的规则,那么,执行一个程序,即执行一个算法所需要的时间的计量便只是一个代数问题。接着,应用本节第三段所提供的Ο、Ω和θ等运算规则就可以分析出算法时间复杂性的渐近阶。

因此,我们的时间计量规则只需要针对Pascal有限的几种基本运算和几种基本语句。下面是这些规则的罗列和必要的说明。

规则(1)

赋值、比较、算术运算、逻辑运算、读写单个常量或单个变量等,只需要1个单位时间。

规则(2)

条件语句"if C then S1 else S2"只需要T c+max(T s1,T s2)的时间,其中T c是计算条件表达式C需要的时间,而T s1和T s2分别是执行语句S1和S2需要的时间。

规则(3)

选择语句"Case A of a1:S1; a2:S2; … ;am:Sm;end",需要max(Ts1, Ts2,…,Tsm)的时间,其中Tsii是执行语句Si所需要的时间,i=l,2,…,m。

规则(4)

访问一个数组的单个分量或一个记录的单个域,只需要1个单位时间。

规则(5)

执行一个for循环语句需要的时间等于执行该循环体所需要的时间乘上循环的次数。

规则(6)

执行一个while循环语句"while C do S"或一个repeat循环语句" repeat S until C",需要的时间等于计算条件表达式C需要的时间与执行循环S体需要的时间之和乘以循环的次数。与规则5不同,这里的循环次数是隐含的。

例如,b_search函数中的while循环语句。按规则(1)-(4),计算条件表达式" (not found)and(U≥=L)"与执行循环体

I:=(U+L)div 2;

if c=A[I] then found:=true

else if c>A[I] then L:=I+1

else U:=I-1;

只需要θ(1)时间,而循环次数为log m,所以,执行此while语句只需要θ(log m)时间。

在许多情况下,运用规则(5)和(6)常常须要借助具体算法的内涵来确定循环的次数,才不致使时间的估计过于保守。这里举一个例子。

考察程序段:

Size:=m; 1

i:=1; 1

while i

begin

i:=i+1;

S1;θ(n)

if Size>0 then 1

begin

在1到Size的范围内任选一个数赋值给t;θ(1)

Size:=Size-t; 2

for j:=l to t do

S2θ(n)

end;

end;

程序在各行右端顶格处标注着执行相应各行所需要的时间。如果不对算法的内涵作较深入的考察,只看到1≤t≤Size≤m,就草率地估计while的内循环for的循环次数为Ο(m),那么,程序在最坏情况下的时间复杂性将被估计为Ο(n 2+m·n 2)。反之,如果对算法的内涵认真地分析,结果将两样。事实上,在while的循环体内t是动态的,size也是动态的,它们都取决while的循环参数i,即t=t(i)记为t i;size=size(i)记为size i ,i=l,2,…,n-1。对于各个i,1≤i≤n-1,t i与m的关系是隐含的,这给准确地计算for循环的循环体S2被执行的次数带来困难。上面的估计比较保守的原因在于我们把S2的执行次数的统计过于局部化。如果不

局限于for循环,而是在整个程序段上统计S2被执行的总次数,那么,这个总次数等于,又根据算法中t i的取法及size i+1=size i-t i,i=1,2,…,n-1 有size n=size1-。

size1=m和size n=0得到=m 。于是在整个程序段上,S2被执行的总次数为m,所需要的时间为θ(mn)。执行其他语句所需要的时间直接运用规则(l)-(6)容易计算。累加起来,整个程序段在最坏情况下时间复杂性渐近阶为θ(n 2+mn)。这个结果显然比前面粗糙的估计准确。

规则(7)

对于goto语句。在Pascal中为了便于表达从循环体的中途跳转到循环体的结束或跳转到循环语句的后面语句,引入goto语句。如果我们的程序按照这一初衷使用goto语句,那么,在时间复杂性分析时可以假设它不需要任何额外的时间。因为这样做既不会低估也不会高估程序在最坏情况下的运行时间的阶。如果有的程序滥用了goto语句,即控制转移到前面的语句,那么情况将变得复杂起来。当这种转移造成某种循环时,只要与别的循环不交叉,保持循环的内外嵌套,则可以比照规则(1)-(6)进行分析。当由于使用goto语句而使程序结构混乱时,建议改写程序然后再做分析。

规则(8)

对于过程调用和函数调用语句,它们需要的时间包括两部分,一部分用于实现控制转移,另一部分用于执行过程(或函数)本身,这时可以根据过程(或函数)调用的层次,由里向外运用规则(l)-(7)进行分析,一层一层地剥,直到计算出最外层的运行时间便是所求。如果过程(或函数)出现直接或间接的递归调用,则上述由里向外逐层剥的分析行不通。这时我们可以对其中的各个递归过程(或函数),所需要的时间假设为一个相应规模的待定函数。然后一一根据过程(或函数)的内涵建立起这些待定函数之间的递归关系得到递归方程。最后用求递归方程解的渐进阶的方法确定最坏情况下的复杂性的渐进阶。

递归方程的种类很多,求它们的解的渐近阶的方法也很多,我们将在下一段比较系统地给予介绍。本段只举一个简单递归过程(或函数)的例子来说明如何建立相应的递归方程,同时不加推导地给出它们在最坏情况下的时间复杂性的渐近阶。

例:再次考察函数b_search,这里将它改写成一个递归函数。为了简明,我们已经运用前面的规则(l)-(6),统计出执行各行语句所需要的时间,并标注在相应行的右端:

Function b_search(C,L,U:integer):integer;单位时间数

var index,element:integer;

begin

if (U

b_search:=0;1 else

begin

index:=(L+U) div 2;3

element:=A[index];2

if element=C then1

b_search:=index1 else if element>C then

b_search:=b_search(C,L,index-1)3+T(m/2)

else

b_search:=b_search(C,index+1,U);3+T(m/2) end;

end;

其中T(m)是当问题的规模U-L+1=m时b_search在最坏情况下(这时,数组A[L..U]中没有给定的C)的时间复杂性。根据规则(l)-(8),我们有:

或化简为

这是一个关于T(m)的递归方程。用下一段将介绍的迭代法,容易解得:

T(m)=11log m +l3=θ(log m)

在结束这一段之前,我们要提一下关于算法在最坏情况下的空间复杂性分析。我们照样可以给出与分析时间复杂性类似的规则。这里不赘述。然而应该指出,在出现过程(或函数)递归调用时要考虑到其中隐含的存储空间的额外开销。因为现有的实现过程(或函数)递归调用的编程技术需要一个隐含的、额外(即不出现在程序的说明中)的栈来支持。过程(或函数)的递归调用每深人一层就把本层的现场局部信息及调用的返回地址存放在栈顶备用,直到调用的最里层。因此递归调用一个过程(或函数)所需要的额外存储空间的大小即栈的规模与递归调用的深度成正比,其比例因子等于每深入一层需要保存的数据量。比如本段前面所举的递归函数b_search,在最坏情况下,递归调用的深度为log m,因而在最坏情况下调用它所需要的额外存储空间为θ(log m)。

递归方程解的渐近阶的求法

上一章所介绍的递归算法在最坏情况下的时间复杂性渐近阶的分析,都转化为求相应的一个递归方程的解的渐近阶。因此,求递归方程的解的渐近阶是对递归算法进行分析的关键步骤。

递归方程的形式多种多样,求其解的渐近阶的方法也多种多样。这里只介绍比较实用的五种方法。

1.代入法这个方法的基本步骤是先推测递归方程的显式解,然后用数学归纳法

证明这一推测的正确性。那么,显式解的渐近阶即为所求。

2.迭代法这个方法的基本步骤是通过反复迭代,将递归方程的右端变换成一个

级数,然后求级数的和,再估计和的渐近阶;或者,不求级数的和而直接估计级数

的渐近阶,从而达到对递归方程解的渐近阶的估计。

3.套用公式法这个方法针对形如:T (n)=aT (n / b)+f (n) 的递归方程,给出三种

情况下方程解的渐近阶的三个相应估计公式供套用。

4.差分方程法有些递归方程可以看成一个差分方程,因而可以用解差分方程

(初值问题)的方法来解递归方程。然后对得到的解作渐近阶的估计。

5.母函数法这是一个有广泛适用性的方法。它不仅可以用来求解线性常系数高

阶齐次和非齐次的递归方程,而且可以用来求解线性变系数高阶齐次和非齐次的递

归方程,甚至可以用来求解非线性递归方程。方法的基本思想是设定递归方程解的

母函数,努力建立一个关于母函数的可解方程,将其解出,然后返回递归方程的解。本章将逐一地介绍上述五种井法,并分别举例加以说明。

本来,递归方程都带有初始条件,为了简明起见,我们在下面的讨论中略去这些初始条件。

递归方程组解的渐进阶的求法——代入法

用这个办法既可估计上界也可估计下界。如前面所指出,方法的关键步骤在于预先对解答作出推测,然后用数学归纳法证明推测的正确性。

数据结构与算法模拟试题

一、选择题 1.在逻辑上可以把数据结构分成() A.线性结构和非线性结构 B.动态结构和静态结构 C.紧凑结构和非紧凑结构 D.内部结构和外部结构 2.单链表中各结点之间的地址() A.必须连续 B.部分必须连续 C.不一定连续 D.以上均不对 3.在一个长度为n的顺序表中向第i个元素(0front==L C.P==NULL D.P->rear==L 12. 已知P为单链表中的非首尾结点,删除P结点的后继结点Q的语句为()。 A.P->NEXT=Q->NEXT;FREE(Q); B.Q->NEXT=P; FREE(Q); C.Q->NEXT=P->NEXT;FREE(Q); D.P->NEXT=S;S->NEXT=P; 13.循环队列SQ队满的条件是()。 A.SQ->rear==SQ->front B. (SQ->rear+1)%MAXLEN==SQ->front C.SQ->rear==0 D. SQ->front==0 14.一组记录的排序码为(46,79,56,38,40,84),则利用堆排序的方法建立的初始堆为()。 A、79,46,56,38,40,80 B、84,79,56,38,40,46 C、84,79,56,46,40,38 D、84,56,79,40,46,38 15.排序趟数与序列原始状态(原始排列)有关的排序方法是()方法。 A、插入排序 B、选择排序 C、冒泡排序 D、快速排序 16.下列排序方法中,()是稳定的排序方法。 A、直接选择排序 B、二分法插入排序

考研数据结构必须掌握的知识点与算法-打印版

《数据结构》必须掌握的知识点与算法 第一章绪论 1、算法的五个重要特性(有穷性、确定性、可行性、输入、输出) 2、算法设计的要求(正确性、可读性、健壮性、效率与低存储量需求) 3、算法与程序的关系: (1)一个程序不一定满足有穷性。例操作系统,只要整个系统不遭破坏,它将永远不会停止,即使没有作业需要处理,它仍处于动态等待中。因此,操作系统不是一个算法。 (2)程序中的指令必须是机器可执行的,而算法中的指令则无此限制。算法代表了对问题的解,而程序则是算法在计算机上的特定的实现。 (3)一个算法若用程序设计语言来描述,则它就是一个程序。 4、算法的时间复杂度的表示与计算(这个比较复杂,具体看算法本身,一般关心其循环的次数与N的关系、函数递归的计算) 第二章线性表 1、线性表的特点: (1)存在唯一的第一个元素;(这一点决定了图不是线性表) (2)存在唯一的最后一个元素; (3)除第一个元素外,其它均只有一个前驱(这一点决定了树不是线性表) (4)除最后一个元素外,其它均只有一个后继。 2、线性表有两种表示:顺序表示(数组)、链式表示(链表),栈、队列都是线性表,他们都可以用数组、链表来实现。 3、顺序表示的线性表(数组)地址计算方法: (1)一维数组,设DataType a[N]的首地址为A0,每一个数据(DataType类型)占m个字节,则a[k]的地址为:A a[k]=A0+m*k(其直接意义就是求在数据a[k]的前面有多少个元素,每个元素占m个字节) (2)多维数组,以三维数组为例,设DataType a[M][N][P]的首地址为A000,每一个数据(DataType 类型)占m个字节,则在元素a[i][j][k]的前面共有元素个数为:M*N*i+N*j+k,其其地址为: A a[i][j][k]=A000+m*(M*N*i+N*j+k); 4、线性表的归并排序: 设两个线性表均已经按非递减顺序排好序,现要将两者合并为一个线性表,并仍然接非递减顺序。可见算法2.2 5、掌握线性表的顺序表示法定义代码,各元素的含义; 6、顺序线性表的初始化过程,可见算法2.3 7、顺序线性表的元素的查找。 8、顺序线性表的元素的插入算法,注意其对于当原来的存储空间满了后,追加存储空间(就是每次增加若干个空间,一般为10个)的处理过程,可见算法2.4 9、顺序线性表的删除元素过程,可见算法2.5 10、顺序线性表的归并算法,可见算法2.7 11、链表的定义代码,各元素的含义,并能用图形象地表示出来,以利分析; 12、链表中元素的查找 13、链表的元素插入,算法与图解,可见算法2.9 14、链表的元素的删除,算法与图解,可见算法2.10 15、链表的创建过程,算法与图解,注意,链表有两种(向表头生长、向表尾生长,分别用在栈、队列中),但他们的区别就是在创建时就产生了,可见算法2.11 16、链表的归并算法,可见算法2.12 17、建议了解所谓的静态单链表(即用数组的形式来实现链表的操作),可见算法2.13 18、循环链表的定义,意义 19、循环链表的构造算法(其与单链表的区别是在创建时确定的)、图解

力 扣 数 据 结 构 与 算 法

前端如何搞定数据结构与算法(先导篇) 「观感度:?」 「口味:锅包肉」 「烹饪时间:20min」 本文已收录在Github? 为什么要学习数据结构与算法? 在0202年的今天,由于每天被无数的信息轰炸,大多数人已经变得越来越浮躁了,并且丧失了独立思考的能力。 你可能会经常听到这样的感慨: 技术人究竟能走多远?我遇到了天花板 35岁的程序员要如何面对中年危机? 技术更新太快,好累,学不动了 然后,你也变得焦虑起来。那你有没有静下心来想过,如何才能抵御年龄增长并且使自己增值呢? 无非是终身学习,持续修炼自己的内功。内功也就是基础知识和核心概念,这些轰轰烈烈发展的技术本质,其实都是基础知识,也就是我们在大学里学过的基础课-程。 操作系统 计算机组成原理 计算机网络 编译原理

设计模式 数据结构与算法 这也就是为什么越靠谱的面试官越注重你基础知识的掌握程度,为什么越牛的的企业越重视你的算法能力。因为当你拥有了这些,你已经比大多数人优秀了。你的天花板由你自己来决定,大家口中的中年危机可能并不会成为你的危机。新技术来临时,你对它的本质会看得更加透彻,学起来会一通百通。这样的人才,公司培养你也会花费更少的成本。 (不过,一辈子做个开开心心的 CRUD Boy 也是一种选择。) 数据结构与算法之间的关系 Rob Pikes 5 Rules of Programming中的第五条是这样说的: Data dominates. If youve chosen the right data structures and organized things well, the algorithms will almost always be self-evident. Data structures, not algorithms, are central to programming. 数据占主导。如果您选择了正确的数据结构并组织得当,那么这些算法几乎总是不言而喻的。数据结构而非算法是编程的核心。 瑞士计算机科学家,Algol W,Modula,Oberon 和 Pascal 语言的设计师 Niklaus Emil Wirth 写过一本非常经典的书《Algorithms + Data Structures = Programs》,即算法 + 数据结构 = 程序。 我们可以得出结论,数据结构与算法之间是相辅相成的关系。数据结构服务于算法,算法作用于特定的数据结构之上。 数据结构与算法好难,怎么学?

数据结构与算法复习题10(C语言版)

习 9解答 判断题: 1.用向量和单链表表示的有序表均可使用折半查找方法来提高查找速度。 答:FALSE (错。链表表示的有序表不能用折半查找法。) 2.有n 个数据放在一维数组A[1..n]中,在进行顺序查找时,这n 个数的排列有序或无序其平均查找长度不同。 答:FALSE (错。因顺序查找既适合于有序表也适合于无序表;对这两种表,若对于每个元素的查找概率相等,则顺序查找的ASL 相同,并且都是(n+1)/2;对于查找概率不同的情况,则按查找概率由大到小排序的无序表其ASL 要比有序表的ASL 小。) 3.折半查找是先确定待查有序表记录的范围,然后逐步缩小范围,直到找到或找不到该记录为止。( ) 答:TRUE 4.哈希表的查找效率主要取决于哈希表哈希表造表时选取的哈希函数和处理冲突的方法。 答:TRUE 5.查找表是由同一类型的数据元素(或记录)构成的集合。 答:TRUE 单选题: 6.对于18个元素的有序表采用二分(折半)查找,则查找A[3]的比较序列的下标为( )。 A. 1、2、3 B. 9、5、2、3 C. 9、5、3 D.9、4、2、3 答:D (第一次??2/)181(+ = 9,第二次??2/)81(+ = 4,第三次??2/)31(+ = 2, (第四次??2/)33(+ = 3,故选D. 7. 顺序查找法适合于存储结构为____________的线性表。 A.散列存储 B.顺序存储或链式存储 C.压缩存储 D.索引存储 答:B 8.对线性表进行二分查找时,要求线性表必须( )。 A .以顺序方式存储 B. 以链接方式存储 C .以顺序方式存储,且结点按关键字有序排序 D. 以链接方式存储,且结点按关键字有序排序 答:C 9.设哈希表长m=14,哈希函数为H(k) = k MOD 11。表中已有4个记录(如下图

数据结构与算法基础知识总结

数据结构与算法基础知识总结 1 算法 算法:是指解题方案的准确而完整的描述。 算法不等于程序,也不等计算机方法,程序的编制不可能优于算法的设计。 算法的基本特征:是一组严谨地定义运算顺序的规则,每一个规则都是有效的,是明确的,此顺序将在有限的次数下终止。特征包括: (1)可行性; (2)确定性,算法中每一步骤都必须有明确定义,不充许有模棱两可的解释,不允许有多义性; (3)有穷性,算法必须能在有限的时间内做完,即能在执行有限个步骤后终止,包括合理的执行时间的含义; (4)拥有足够的情报。 算法的基本要素:一是对数据对象的运算和操作;二是算法的控制结构。 指令系统:一个计算机系统能执行的所有指令的集合。 基本运算和操作包括:算术运算、逻辑运算、关系运算、数据传输。 算法的控制结构:顺序结构、选择结构、循环结构。 算法基本设计方法:列举法、归纳法、递推、递归、减斗递推技术、回溯法。 算法复杂度:算法时间复杂度和算法空间复杂度。 算法时间复杂度是指执行算法所需要的计算工作量。 算法空间复杂度是指执行这个算法所需要的内存空间。 2 数据结构的基本基本概念 数据结构研究的三个方面: (1)数据集合中各数据元素之间所固有的逻辑关系,即数据的逻辑结构; (2)在对数据进行处理时,各数据元素在计算机中的存储关系,即数据的存储结构;(3)对各种数据结构进行的运算。 数据结构是指相互有关联的数据元素的集合。 数据的逻辑结构包含: (1)表示数据元素的信息; (2)表示各数据元素之间的前后件关系。 数据的存储结构有顺序、链接、索引等。 线性结构条件:

(1)有且只有一个根结点; (2)每一个结点最多有一个前件,也最多有一个后件。 非线性结构:不满足线性结构条件的数据结构。 3 线性表及其顺序存储结构 线性表由一组数据元素构成,数据元素的位置只取决于自己的序号,元素之间的相对位置是线性的。 在复杂线性表中,由若干项数据元素组成的数据元素称为记录,而由多个记录构成的线性表又称为文件。 非空线性表的结构特征: (1)且只有一个根结点a1,它无前件; (2)有且只有一个终端结点an,它无后件; (3)除根结点与终端结点外,其他所有结点有且只有一个前件,也有且只有一个后件。结点个数n称为线性表的长度,当n=0时,称为空表。 线性表的顺序存储结构具有以下两个基本特点: (1)线性表中所有元素的所占的存储空间是连续的; (2)线性表中各数据元素在存储空间中是按逻辑顺序依次存放的。 ai的存储地址为:adr(ai)=adr(a1)+(i-1)k,,adr(a1)为第一个元素的地址,k代表每个元素占的字节数。 顺序表的运算:插入、删除。(详见14--16页) 4 栈和队列 栈是限定在一端进行插入与删除的线性表,允许插入与删除的一端称为栈顶,不允许插入与删除的另一端称为栈底。 栈按照“先进后出”(filo)或“后进先出”(lifo)组织数据,栈具有记忆作用。用top表示栈顶位置,用bottom表示栈底。 栈的基本运算:(1)插入元素称为入栈运算;(2)删除元素称为退栈运算;(3)读栈顶元素是将栈顶元素赋给一个指定的变量,此时指针无变化。 队列是指允许在一端(队尾)进入插入,而在另一端(队头)进行删除的线性表。rear指针指向队尾,front指针指向队头。 队列是“先进行出”(fifo)或“后进后出”(lilo)的线性表。 队列运算包括(1)入队运算:从队尾插入一个元素;(2)退队运算:从队头删除一个元素。循环队列:s=0表示队列空,s=1且front=rear表示队列满

[第1题-60题汇总]微软数据结构+算法面试100题

精选微软等公司数据结构 精选微软等公司数据结构++算法面试100题 -----[第1题-60题总] 资源说明: 此份,是为微软等公司数据结构+算法面试100题,之前60题的汇总。 总结整理了前第1题-第60题。特此并作此一份上传。以飨各位。:)。 -------------------------------- 相关资源,包括答案,下载地址: [答案V0.2版]精选微软数据结构+算法面试100题[前20题]--答案修正 https://www.wendangku.net/doc/d49917101.html,/source/2813890 //此份答案是针对最初的V0.1版本,进行的校正与修正。 [答案V0.1版]精选微软数据结构+算法面试100题[前25题] https://www.wendangku.net/doc/d49917101.html,/source/2796735 [第二部分]精选微软等公司结构+算法面试100题[前41-60题]: https://www.wendangku.net/doc/d49917101.html,/source/2811703 [第一部分]精选微软等公司数据结构+算法经典面试100题[1-40题] https://www.wendangku.net/doc/d49917101.html,/source/2778852 更多资源,下载地址: http://v_july_https://www.wendangku.net/doc/d49917101.html,/ 很快,我将公布第21-40题的答案,敬请期待。:).. 如果你对以下的前第1-60题,有好的思路,和算法,欢迎跟帖回复, 或者,联系我,发至我的邮箱, zhoulei0907@https://www.wendangku.net/doc/d49917101.html,。 My CSDN Blog:https://www.wendangku.net/doc/d49917101.html,/v_JULY_v My sina Blog:https://www.wendangku.net/doc/d49917101.html,/shitou009 帖子维护地址: [整理]算法面试:精选微软经典的算法面试100题[前1-60题] https://www.wendangku.net/doc/d49917101.html,/u/20101023/20/5652ccd7-d510-4c10-9671-307a56006e6d.html -------------------------------------- July、2010、/11.12.请享用。:)。 1

北京交通大学数据结构与算法期末测验考试参考答案

北京交通大学考试试题(A卷) 课程名称:数据结构与算法2011-2012学年第一学期出题教师:张勇 (请考生注意:(1)本试卷共有六道大题,(2)答案一律写在答题纸上,(3)试卷不得带出考场) 1. 在顺序表中访问任意一个元素的时间复杂度均为,因此顺序表也称为 的数据结构。 2.三维数组a[4][3][2](下标从0开始),假设a[0][0][0]的地址为50,数据以行序优先方式存储,每个元素的长度为2字节,则a[2][1][1]的地址是。 3. 直接插入排序用监视哨的作用是。 4. 已知广义表Ls=(a, (b, c), (d, e)), 运用head和tail函数取出Ls中的原子d的运算 是。 5.对有14个元素的有序表A[1..14]进行折半查找,当比较到A[4]时算法结束。被比较元素除A[4]外,还有。 6. 在AOV网中,顶点表示,边表示。 7. 有向图G可进行拓扑排序的判别条件是。 8. 若串S1=‘ABCDEFGHIJK’,S2=‘451223’,S3=‘####’,则执行 Substring(S1,Strlength(S3),Index(S2,‘12’,1))的结果是。 二、选择题(每空2分,共20分) 1.在下列存储形式中,哪一个不是树的存储形式?() A.双亲表示法B.孩子链表表示法 C.孩子兄弟表示法D.顺序存储表示法 2.查找n个元素的有序表时,最有效的查找方法是()。 A.顺序查找B.分块查找 C.折半查找D.二叉查找 3.将所示的s所指结点加到p所指结点之后,其语句应为()。 p (A) s->next=p+1 ; p->next=s;

(B) (*p).next=s; (*s).next=(*p).next; (C) s->next=p->next ; p->next=s->next; (D) s->next=p->next ; p->next=s; 4. 在有向图的邻接表存储结构中,顶点v 在链表中出现的次数是( )。 A. 顶点v 的度 B. 顶点v 的出度 C. 顶点v 的入度 D. 依附于顶点v 的边数 5. 算法的时间复杂度为O (nlog 2n )、空间复杂度为O(1)的排序算法是( )。 A. 堆排序 B. 快速排序 C. 归并排序 D.直接选择 6. 设矩阵A 是一个对称矩阵,为了节省存储,将其 下三角部分(如右图所示)按行序存放在一维数组B[ 1, n(n-1)/2 ]中,对下三角部分中任一元素ai,j(i ≤j), 在一维数组B 中下标k 的值是( ): A.i(i-1)/2+j-1 B.i(i-1)/2+j C.i(i+1)/2+j-1 D.i(i+1)/2+j 7. 由一个长度为11的有序表,按二分查找法对该表进行查找,在表内各元素等概率情 况下,查找成功的平均查找长度是( )。 A .29/11 B. 31/11 C. 33/11 D.35/11 8. AVL 树是一种平衡的二叉排序树,树中任一结点的( )。 A. 左、右子树的高度均相同 B. 左、右子树高度差的绝对值不超过1 C. 左子树的高度均大于右子树的高度 D. 左子树的高度均小于右子树的高度 9. 下列四种排序方法中,不稳定的方法是( )。 A. 直接插入排序 B. 冒泡排序 C. 归并排序 D. 堆排序 10. 设树的度为4,其中度为1,2,3,4的结点个数分别为4, 2, ,1, 1, 则T 中的叶子数为 ( )。 A .5 B .6 C .7 D .8 三、 判断题(10分,每小题1分) 1. 顺序存储方式的优点是存储密度大,且插入、删除运算效率高。( ) 2. 数组不适合作任何二叉树的存储结构。( ) 3. 广义表的取表尾运算,其结果通常是个表,但有时也可是个原子。( ) 4. 在含有n 个结点的树中,边数只能是n-1条。( ) 5. 所谓一个排序算法是否稳定,是指该算法在各种情况下的效率是否相差不大。( ) 6. 简单选择排序在最好情况下的时间复杂度为O(n)。( ) 7. 在二叉排序树中插入一个新结点,总是插入到叶结点下面。( ) 8. 采用线性探测处理冲突,当从哈希表中删除一个记录时,不应将该记录所在位置置 空,因为这会影响以后的查找。( ) 9. 有n 个数存放在一维数组A[1..n]中,在进行顺序查找时,这n 个数的排列有序或无 ?????? ? ???? ? ??=n n n n a a a a a a A ,2,1,2 ,21,21 ,1Λ Λ

知识点大纲全国计算机等级考试数据结构和算法

全国计算机等级考试二级office 二级公共基础知识部分(10分*10题) 第一章. 算法与数据结构 考点1:算法概念 ● 算法 算法:指解题方案准确而完整的描述。 算法不等于程序,也不是计算方法。程序编制通常不优于算法设计。 考点2:算法的四个基本特征 可行性、确定性(算法步骤有明确定义)、有穷性、拥有足够情报 考点3:算法的时间复杂度和空间复杂度 1. 时间复杂度:执行算法所需的工作量。 算法执行的基本次数是问题规模的函数,固定规模下还与输入有关。 2. 空间复杂度:算法执行需要的存储空间(算法程序、输入初始数据、某种数据结构所需空间) ● 数据结构 (反映数据元素之间关系的数据元素集合,即带有结构的数据元素的集合,结构指数据元素之间 的前后件(前驱、后继)关系)。目的是提高数据处理的效率(速度/空间) 数据的逻辑结构:是反映数据元素之间逻辑关系的数据结构。 可以表示成:B=(D ,R ) B 表示数据结构;D 表示数据元素集合;R 表示数据元素之间的前后件关系 【例:一年四季的数据结构可以表示成B=(D ,R );D=(春,夏,秋,冬);B={(春,夏), (夏,秋),(秋,冬)}】 数据结构的图形表示: 数据元素:用中间标有元素值的方框表示,称为结点。 逻辑关系:用有向线段从前件指向后件。没有前件的结点称为根结点;没有后件的结点称为 终端结点(叶子结点) B=(D ,R ) D={di|1≤i ≤7} ={d1,d2,d3,d4,(d1,d3),(d1,d7),(d2,d4),(d3,d6),(d4,d5)} 考点4:数据的存储结构 数据的存储结构:指数据的逻辑结构在计算机 储存空间的存放形式。既储存数据元素的信息,还有元素的前后件关系信息。 数据的逻辑关系与数据的存储结构不一定相同。数据结构一般可以表示成多种存储结构,常

阿里校园招聘历年经典面试题汇总:算法工程师

阿里校园招聘历年经典面试题汇总:算法工程师 (1)、jvm 原理 (2)、minor GC 与 Full GC (3)、HashMap 实现原理 (4)、java.util.concurrent 包下使用过哪些 (5)、concurrentMap 和 HashMap 区别 (6)、信号量是什么,怎么使用? (7)、阻塞队列了解吗?怎么使用? (8)、JAVA NIO 是什么? (9)、类加载机制是怎样的 (10)、什么是幂等性 (11)、有哪些 JVM 调优经验 (12)、分布式 CAP 了解吗? (13)、hdfs怎么添加Datanode,添加后hdfs会有什么操作? (14)、Hbase 跟关系数据库对比优缺点?为什么 Hbase 索引速度快 (15)、Hbase 大压缩与小压缩区别 (16)、Hive 与 Hbase 的使用场景 (17)、简单说说Spark功能,spark 与hive有无依赖关系? (18)、zookeeper 有什么应用场景,怎么选举的?3 个节点挂掉一个能正常工作吗? (19)、Hbase 中 zookeaper 作用 (20)、Hbase 写操作什么时候返回 (21)、mysql 有哪些存储引擎?各自特点 (22)、用过哪些设计模式?怎样实现线程安全单例模式? (23)、用过哪些RPC框架? (24)、什么是AOP? (25)、决策树算法怎么实现的? (26)、java垃圾回收会出现不可回收的对象吗?怎么解决内存泄露问题?怎么

定位问题源? (27)、终止线程有几种方式?终止线程标记变量为什么是 valotile 类型?(28)、用过哪些并发的数据结构? cyclicBarrier 什么功能?信号量作用?数据库读写阻塞怎么解决? (29)、乐观锁与悲观锁,怎么实现乐观锁? (30)、开发过分布式框架?怎么实现分布式事务? (31)、spark streaming与storm区别? (32)、找到最大子数组的 start,和end下标 (33)、用过 CDH中什么任务调度? (34)、spark streaming时间间隔设置很小会出现什么状况? (35)、搜索引擎了解多少?你认为搜索引擎的难点在哪里? (36)、RPC 了解吗?怎么监控 RPC 状态,找出出现问题的 RPC 连接?(37)、spring 框架了解多少? (38)、flume应用场景 (39)、找出一串字符中第一个不重复字符的下标。 点击查看详细面经〉〉〉〉〉〉〉〉〉〉〉〉 更多精品干货>>>>>>>>>>> 更多阿里机器学习/数据挖掘经典面试题 其他名企机器学习/数据挖掘经典面试题

数据结构与算法复习题及参考答案

复习题集─参考答案 一判断题 (√)1. 在决定选取何种存储结构时,一般不考虑各结点的值如何。 (√)2. 抽象数据类型与计算机部表示和实现无关。 (×)3. 线性表采用链式存储结构时,结点和结点部的存储空间可以是不连续的。 (×)4. 链表的每个结点中都恰好包含一个指针。 (×)5.链表的删除算法很简单,因为当删除链中某个结点后,计算机会自动地将后续的各个单元向前移动。(×)6. 线性表的每个结点只能是一个简单类型,而链表的每个结点可以是一个复杂类型。 (×)7. 顺序表结构适宜于进行顺序存取,而链表适宜于进行随机存取。 (×)8. 线性表在物理存储空间中也一定是连续的。 (×)9. 顺序存储方式只能用于存储线性结构。 (√)10.栈是一种对所有插入、删除操作限于在表的一端进行的线性表,是一种后进先出型结构。 (√)11.对于不同的使用者,一个表结构既可以是栈,也可以是队列,也可以是线性表。 (√)12.栈是一种对所有插入、删除操作限于在表的一端进行的线性表,是一种后进先出型结构。 (√)13.两个栈共享一片连续存空间时,为提高存利用率,减少溢出机会,应把两个栈的栈底分别设在这片存空间的两端。 (×)14.二叉树的度为2。 (√)15.若二叉树用二叉链表作存贮结构,则在n个结点的二叉树链表中只有n—1个非空指针域。 (×)16.二叉树中每个结点的两棵子树的高度差等于1。 (√)17.用二叉链表法存储包含n个结点的二叉树,结点的2n个指针区域中有n+1个为空指针。 (√)18.具有12个结点的完全二叉树有5个度为2的结点。 (√)19.二叉树的前序遍历序列中,任意一个结点均处在其孩子结点的前面。 (×)20.在冒泡法排序中,关键值较小的元素总是向前移动,关键值较大的元素总是向后移动。 (×)21.计算机处理的对象可以分为数据和非数据两大类。[计算机处理的对象都是数据] (×)22.数据的逻辑结构与各数据元素在计算机中如何存储有关。 (×)23.算法必须用程序语言来书写。 (×)24.判断某个算法是否容易阅读是算法分析的任务之一。 (×)25.顺序表是一种有序的线性表。[任何数据结构才用顺序存储都叫顺序表] (√)26.分配给顺序表的存单元地址必须是连续的。 (√)27.栈和队列具有相同的逻辑特性。[它们的逻辑结构都是线性表] (√)28.树形结构中每个结点至多有一个前驱。 (×)29.在树形结构中,处于同一层上的各结点之间都存在兄弟关系。 (×)30.如果表示图的邻接矩阵是对称矩阵,则该图一定是无向图。 (×)31.如果表示图的邻接矩阵是对称矩阵,则该图一定是有向图。 (×)32.顺序查找方法只能在顺序存储结构上进行。 (×)33.折半查找可以在有序的双向链表上进行。

数据结构与算法分析习题与参考答案

大学 《数据结构与算法分析》课程 习题及参考答案 模拟试卷一 一、单选题(每题 2 分,共20分) 1.以下数据结构中哪一个是线性结构?( ) A. 有向图 B. 队列 C. 线索二叉树 D. B树 2.在一个单链表HL中,若要在当前由指针p指向的结点后面插入一个由q指向的结点, 则执行如下( )语句序列。 A. p=q; p->next=q; B. p->next=q; q->next=p; C. p->next=q->next; p=q; D. q->next=p->next; p->next=q; 3.以下哪一个不是队列的基本运算?() A. 在队列第i个元素之后插入一个元素 B. 从队头删除一个元素 C. 判断一个队列是否为空 D.读取队头元素的值 4.字符A、B、C依次进入一个栈,按出栈的先后顺序组成不同的字符串,至多可以组成( ) 个不同的字符串? A.14 B.5 C.6 D.8 5.由权值分别为3,8,6,2的叶子生成一棵哈夫曼树,它的带权路径长度为( )。 以下6-8题基于图1。 6.该二叉树结点的前序遍历的序列为( )。 A.E、G、F、A、C、D、B B.E、A、G、C、F、B、D C.E、A、C、B、D、G、F D.E、G、A、C、D、F、B 7.该二叉树结点的中序遍历的序列为( )。 A. A、B、C、D、E、G、F B. E、A、G、C、F、B、D C. E、A、C、B、D、G、F E.B、D、C、A、F、G、E 8.该二叉树的按层遍历的序列为( )。

A.E、G、F、A、C、D、B B. E、A、C、B、D、G、F C. E、A、G、C、F、B、D D. E、G、A、C、D、F、B 9.下面关于图的存储的叙述中正确的是( )。 A.用邻接表法存储图,占用的存储空间大小只与图中边数有关,而与结点个数无关 B.用邻接表法存储图,占用的存储空间大小与图中边数和结点个数都有关 C. 用邻接矩阵法存储图,占用的存储空间大小与图中结点个数和边数都有关 D.用邻接矩阵法存储图,占用的存储空间大小只与图中边数有关,而与结点个数无关 10.设有关键码序列(q,g,m,z,a,n,p,x,h),下面哪一个序列是从上述序列出发建 堆的结果?( ) A. a,g,h,m,n,p,q,x,z B. a,g,m,h,q,n,p,x,z C. g,m,q,a,n,p,x,h,z D. h,g,m,p,a,n,q,x,z 二、填空题(每空1分,共26分) 1.数据的物理结构被分为_________、________、__________和___________四种。 2.对于一个长度为n的顺序存储的线性表,在表头插入元素的时间复杂度为_________, 在表尾插入元素的时间复杂度为____________。 3.向一个由HS指向的链栈中插入一个结点时p时,需要执行的操作是________________; 删除一个结点时,需要执行的操作是______________________________(假设栈不空而 且无需回收被删除结点)。 4.对于一棵具有n个结点的二叉树,一个结点的编号为i(1≤i≤n),若它有左孩子则左 孩子结点的编号为________,若它有右孩子,则右孩子结点的编号为________,若它有 双亲,则双亲结点的编号为________。 5.当向一个大根堆插入一个具有最大值的元素时,需要逐层_________调整,直到被调整 到____________位置为止。 6.以二分查找方法从长度为10的有序表中查找一个元素时,平均查找长度为________。 7.表示图的三种常用的存储结构为_____________、____________和_______________。 8.对于线性表(70,34,55,23,65,41,20)进行散列存储时,若选用H(K)=K %7 作为散列函数,则散列地址为0的元素有________个,散列地址为6的有_______个。 9.在归并排序中,进行每趟归并的时间复杂度为______,整个排序过程的时间复杂度为 ____________,空间复杂度为___________。 10.在一棵m阶B_树上,每个非树根结点的关键字数目最少为________个,最多为________ 个,其子树数目最少为________,最多为________。 三、运算题(每题 6 分,共24分) 1.写出下列中缀表达式的后缀形式: (1)3X/(Y-2)+1 (2)2+X*(Y+3) 2.试对图2中的二叉树画出其: (1)顺序存储表示的示意图; (2)二叉链表存储表示的示意图。 3.判断以下序列是否是小根堆? 如果不是, 将它调 图2 整为小根堆。 (1){ 12, 70, 33, 65, 24, 56, 48, 92, 86, 33 } (2){ 05, 23, 20, 28, 40, 38, 29, 61, 35, 76, 47, 100 } 4.已知一个图的顶点集V和边集E分别为: V={1,2,3,4,5,6,7};

(完整版)非常实用的数据结构知识点总结

数据结构知识点概括 第一章概论 数据就是指能够被计算机识别、存储和加工处理的信息的载体。 数据元素是数据的基本单位,可以由若干个数据项组成。数据项是具有独立含义的最小标识单位。 数据结构的定义: ·逻辑结构:从逻辑结构上描述数据,独立于计算机。·线性结构:一对一关系。 ·线性结构:多对多关系。 ·存储结构:是逻辑结构用计算机语言的实现。·顺序存储结构:如数组。 ·链式存储结构:如链表。 ·索引存储结构:·稠密索引:每个结点都有索引项。 ·稀疏索引:每组结点都有索引项。 ·散列存储结构:如散列表。 ·数据运算。 ·对数据的操作。定义在逻辑结构上,每种逻辑结构都有一个运算集合。 ·常用的有:检索、插入、删除、更新、排序。 数据类型:是一个值的集合以及在这些值上定义的一组操作的总称。 ·结构类型:由用户借助于描述机制定义,是导出类型。 抽象数据类型ADT:·是抽象数据的组织和与之的操作。相当于在概念层上描述问题。 ·优点是将数据和操作封装在一起实现了信息隐藏。 程序设计的实质是对实际问题选择一种好的数据结构,设计一个好的算法。算法取决于数据结构。 算法是一个良定义的计算过程,以一个或多个值输入,并以一个或多个值输出。 评价算法的好坏的因素:·算法是正确的; ·执行算法的时间; ·执行算法的存储空间(主要是辅助存储空间); ·算法易于理解、编码、调试。 时间复杂度:是某个算法的时间耗费,它是该算法所求解问题规模n的函数。 渐近时间复杂度:是指当问题规模趋向无穷大时,该算法时间复杂度的数量级。 评价一个算法的时间性能时,主要标准就是算法的渐近时间复杂度。 算法中语句的频度不仅与问题规模有关,还与输入实例中各元素的取值相关。 时间复杂度按数量级递增排列依次为:常数阶O(1)、对数阶O(log2n)、线性阶O(n)、线性对数阶O(nlog2n)、平方阶O (n^2)、立方阶O(n^3)、……k次方阶O(n^k)、指数阶O(2^n)。

数据结构算法面试100题

数据结构+算法面试100题~~~摘自CSDN,作者July 1.把二元查找树转变成排序的双向链表(树) 题目: 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。 要求不能创建任何新的结点,只调整指针的指向。 10 / / 6 14 / / / / 4 8 12 16 转换成双向链表 4=6=8=10=12=14=16。 首先我们定义的二元查找树节点的数据结构如下: struct BSTreeNode { int m_nValue; // value of node BSTreeNode *m_pLeft; // left child of node BSTreeNode *m_pRight; // right child of node }; 2.设计包含min函数的栈(栈) 定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。 要求函数min、push以及pop的时间复杂度都是O(1)。 参见C:\Users\Administrator\Desktop\demo\Stack 分析:min时间复杂度要达到O(1),需要我们在栈中存储最小元素 3.求子数组的最大和(数组) 题目: 输入一个整形数组,数组里有正数也有负数。 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。求所有子数组的和的最大值。要求时间复杂度为O(n)。 例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,因此输出为该子数组的和18。 分析:根据dp思想 #include #define N 8 int main() { int i, a[N] = {1, -2, 3, 10, -4, 7, 2, -5}; int from[N], result[N], max;

数据结构与算法试题

数据结构与算法试题 一、单选题 1、在数据结构的讨论中把数据结构从逻辑上分为 (C ) A 内部结构与外部结构 B 静态结构与动态结构 C 线性结构与非线性结构 D 紧凑结构与非紧凑结构。 2、采用线性链表表示一个向量时,要求占用的存储空间地址(D ) A 必须就是连续的 B 部分地址必须就是连续的 C 一定就是不连续的 D 可连续可不连续 3、采用顺序搜索方法查找长度为n的顺序表时,搜索成功的平均搜索长度为( D )。 A n B n/2 C (n-1)/2 D (n+1)/2 4、在一个单链表中,若q结点就是p结点的前驱结点,若在q与p之间插入结点s,则执行( D )。 A s→link = p→link;p→link = s; B p→link = s; s→link = q; C p→link = s→link;s→link = p; D q→link = s;s→link = p; 5、如果想在4092个数据中只需要选择其中最小的5个,采用( C )方法最好。 A 起泡排序 B 堆排序 C 锦标赛排序 D 快速排序 6、设有两个串t与p,求p在t中首次出现的位置的运算叫做( B )。 A 求子串 B 模式匹配 C 串替换 D 串连接 7、在数组A中,每一个数组元素A[i][j]占用3个存储字,行下标i从1到8,列下标j从1到10。所有数组元素相继存放于一个连续的存储空间中,则存放该数

组至少需要的存储字数就是( C )。 A 80 B 100 C 240 D 270 8、将一个递归算法改为对应的非递归算法时,通常需要使用( A )。 A 栈 B 队列 C 循环队列 D 优先队列 9、一个队列的进队列顺序就是1, 2, 3, 4,则出队列顺序为( C )。 10、在循环队列中用数组A[0、、m-1] 存放队列元素,其队头与队尾指针分别为front与rear,则当前队列中的元素个数就是( D )。 A ( front - rear + 1) % m B ( rear - front + 1) % m C ( front - rear + m) % m D ( rear - front + m) % m 11、一个数组元素a[i]与( A )的表示等价。 A *(a+i) B a+i C *a+i D &a+i 12、若需要利用形参直接访问实参,则应把形参变量说明为( B )参数。 A 指针 B 引用 C 值 D 变量 13、下面程序段的时间复杂度为( C ) for (int i=0;i

数据结构与算法设计知识点

数据结构与算法设计知识点 试题类型: 本课程为考试科目(闭卷笔试),试题类型包括:概念填空题(10 %),是非判断题(10 %),单项选择题(40 %),算法填空题(10%),算法应用题(20 %),算法设计题(10 %)。 第一章绪论 重点内容及要求: 1、了解与数据结构相关的概念(集合、数据、数据元素、数据项、关键字、元 素之间的关系等)。 数据:所有能被输入到计算机中,且能被计算机处理的符号的 集合。是计算机操作的对象的总称。是计算机处理的信息的某种特定 的符号表示形式。 数据元素:是数据(集合)中的一个“个体”,数据结构中的基本 单位,在计算机程序中通常作为一个整体来考虑和处理。 数据项:是数据结构中讨论的最小单位,数据元素可以是一个或 多个数据项的组合 关键码:也叫关键字(Key),是数据元素中能起标识作用的数 据项。 其中能起到唯一标识作用的关键码称为主关键码(简称主码); 否则称为次关键码。通常,一个数据元素只有一个主码,但可以有多 个次码。 关系:指一个数据集合中数据元素之间的某种相关性。 数据结构:带“结构”的数据元素的集合。这里的结构指元素之 间存在的关系。 数据类型:是一个值的集合和定义在此集合上的一组操作的总

称。 2、掌握数据结构的基本概念、数据的逻辑结构(四种)和物理结构(数据元素 的表示与关系的表示、两类存储结构:顺序存储结构和链式存储结构)。 数据结构包括逻辑结构和物理结构两个层次。 数据的逻辑结构:是对数据元素之间存在的逻辑关系的一种抽象的描述,可以用一个数据元素的集合和定义在此集合上的若干关系来表示 逻辑结构有四种:线性结构、树形结构、图状结构、集合结构数据的物理结构:是其逻辑结构在计算机中的表示或实现,因此又称其为存储结构。 存储结构:顺序存储结构和链式存储结构 顺序存储结构:利用数据元素在存储器中相对位置之间的某种特定的关系来表示数据元素之间的逻辑关系; 链式存储结构:除数据元素本身外,采用附加的“指针”表示数据元素之间的逻辑关系。 3、了解算法分析的基本方法,掌握算法时间复杂度相关的概念。 算法:是为了解决某类问题而规定的一个有限长的操作序列 或处理问题的策略 一个算法必须满足以下五个重要特性:1.有穷性2.确定性3.可行性4.有输入5.有输出 设计算法时,通常还应考虑满足以下目标: 1.正确性, 2.可读性, 3.健壮性 4.高效率与低存储量需求

典型数据结构面试题

数据结构 1?在一个单链表中p所指结点之前插入一个s (值为e)所指结点时,可执行如下操作: q=head; while (q->next!=p)q=q->next; s= newNode;s->data=e; q->next=;// 填空 s->next=;// 填空 2.线性表的顺序存储结构是一种的存储结构,而链式存储结构是一种___的 存储结构。 A.随机存取 B.索引存取 C.顺序存取 D.散列存取 3.线性表若采用链式存储结构时,要求内存中可用存储单元的地址___。 A.必须是连续的 B.部分地址必须是连续的 C.一定是不连续的 D.连续或不连续都可以 4?在一个单链表中,已知q所指结点是p所指结点的前驱结点,若在q和p 之间插入s结点,则执行_。 A.s->next=p->next;p->next=s; B.p->next=s->next;s->next=p;

C.q->next=s;s->next=p; D.p->next=s;s->next=q; 5.在一个单链表中,若p 所指结点不是最后结点,在p 之后插入s 所指结点,则执行__。 A.s->next=p;p->next=s; B.s->next=p->next;p->next=s; C.s->next=p->next;p=s; C. p->next=s;s->next=p; 6.在一个单链表中,若删除p 所指结点的后续结点,则执行__。 A.p->next= p->next->next; B.p= p->next;p->next= p->next->nex;t C.p->next= p->next; D.p= p->next->next; 7.链表不具备的特点是__。 A 可随机访问任何一个元素 B 插入、删除操作不需要移动元素 C无需事先估计存储空间大小D所需存储空间与线性表长度成正比 8.以下关于线性表的说法不正确的是。 A 线性表中的数据元素可以是数字、字符、记录等不同类型。 B 线性表中包含的数据元素个数不是任意的。 C 线性表中的每个结点都有且只有一个直接前趋和直接后继。 D 存在这样的线性表:表中各结点都没有直接前趋和直接后继。 9?在一个长度为n的顺序表中删除第i个元素,要移动个元素。如果要在第 i 个元素前插入一个元素,要后移()个元素。N-I N-I+1

相关文档
相关文档 最新文档