当前位置:首页 > 数据结构习题及答案
。
1.2 试举一个数据结构的例子、叙述其逻辑结构、存储结构、运算三个方面的内容。
答:例如有一张学生体检情况登记表,记录了一个班的学生的身高、体重等各项体检信息。这张登记表中,每个学生的各项体检信息排在一行上。这个表就是一个数据结构。每个记录(有姓名,学号,身高和体重等字段)就是一个结点,对于整个表来说,只有一个开始结点(它的前面无记录)和一个终端结点(它的后面无记录),其他的结点则各有一个也只有一个直接前趋和直接后继(它的前面和后面均有且只有一个记录)。这几个关系就确定了这个表的逻辑结构是线性结构。
这个表中的数据如何存储到计算机里,并且如何表示数据元素之间的关系呢? 即用一片连续的内存单元来存放这些记录(如用数组表示)还是随机存放各结点数据再用指针进行链接呢? 这就是存储结构的问题。
在这个表的某种存储结构基础上,可实现对这张表中的记录进行查询,修改,删除等操作。对这个表可以进行哪些操作以及如何实现这些操作就是数据的运算问题了。
1.3 常用的存储表示方法有哪几种? 答:常用的存储表示方法有四种:
● 顺序存储方法:它是把逻辑上相邻的结点存储在物理位置相邻的存储单元里,结点间的逻辑关系由存储单元的邻接关系来体现。由此得到的存储表示称为顺序存储结构,通常借助程序语言的数组描述。
● 链接存储方法:它不要求逻辑上相邻的结点在物理位置上亦相邻,结点间的逻辑关系是由附加的指针字段表示。由此得到的存储表示称为链式存储结构,通常借助于程序语言的指针类型描述。
● 索引存储方法:除建立存储结点信息外,还建立附加的索引表来标识结点的地址。组成索引表的索引项由结点的关键字和地址组成。若每个结点在索引表中都有一个索引项,则该索引表称之为稠密索引(Dense Index)。若一组结点在索引表中只对应一个索引项,则该索引表称为稀疏索引。
● 散列存储方法:就是根据结点的关键字直接计算出该结点的存储地址
1.4 设三个函数f,g,h分别为 f(n)=100n3+n2+1000 , g(n)=25n3+5000n2 , h(n)=n1.5+5000nlgn 请判断下列关系是否成立:
(1) f(n)=O(g(n)) (2) g(n)=O(f(n)) (3) h(n)=O(n1.5) (4) h(n)=O(nlgn) 分析:
数学符号\的严格的数学定义:
若T(n)和f(n)是定义在正整数集合上的两个函数,则T(n)=O(f(n))表示存在正的常数C和n0,使得当n≥n0时都满足0≤T(n)≤C·f(n)。
通俗地说,就是当n→∞时,f(n)的函数值增长速度与T(n)的增长速度同阶。一般,一个函数的增长速度与该函数的最高次阶同阶。
即:
O(f(n))=n3 O(g(n))=n3 O(h(n))=n1.5 所以答案为: 答:●(1)成立。 ●(2)成立。 ●(3)成立。 ●(4)不成立。
1.5 设有两个算法在同一机器上运行,其执行时间分别为100n2和2n,要使前者快于后者,n至少要多大?
1
分析:要使前者快于后者,即前者的时间消耗低于后者,即: 100n2<2n 求解上式,可得 答: n=15
1.6 设n为正整数,利用大\记号,将下列程序段的执行时间表示为n的函数。 (1) i=1; k=0; while(i { k=k+10*i;i++; } 分析: i=1; //1 k=0; //1 while(i { k=k+10*i; //n-1 i++; //n-1 } 由以上列出的各语句的频度,可得该程序段的时间消耗: T(n)=1+1+n+(n-1)+(n-1)=3n 可表示为T(n)=O(n) (2) i=0; k=0; do{ k=k+10*i; i++; } while(i k=k+10*i; //n i++; //n } while(i 由以上列出的各语句的频度,可得该程序段的时间消耗: T(n)=1+1+n+n+n+n=4n+2 可表示为T(n)=O(n) (3) i=1; j=0; while(i+j<=n) { if (i>j) j++; else i++; } 分析: 通过分析以上程序段,可将i+j看成一个控制循环次数的变量,且每执行一次循环,i+j的值加1。该程序段的主要时间消耗是while循环,而while循环共做了n次,所以该程序段的执行时间为: T(n)=O(n) 2 (4)x=n; // n>1 while (x>=(y+1)*(y+1)) y++; 分析: 由x=n且x的值在程序中不变,又while的循环条件(x>=(y+1)*(y+1))可知:当(y+1)*(y+1)刚超过n的值时退出循环。 由(y+1)*(y+1) (5) x=91; y=100; while(y>0) if(x>100) {x=x-10;y--;} else x++; 分析: x=91; //1 y=100; //1 while(y>0) //1101 if(x>100) //1100 { x=x-10; //100 y--; //100 } else x++; //1000 以上程序段右侧列出了执行次数。该程序段的执行时间为: T(n)=O(1) 1.7 算法的时间复杂度仅与问题的规模相关吗? 答: 算法的时间复杂度不仅与问题的规模相关,还与输入实例中的初始状态有关。但在最坏的情况下,其时间复杂度就是只与求解问题的规模相关的。我们在讨论时间复杂度时,一般就是以最坏情况下的时间复杂度为准的。 1.8 按增长率由小至大的顺序排列下列各函数: 2100, (3/2)n,(2/3)n, nn ,n0.5 , n! ,2n ,lgn ,nlgn, n(3/2) 答:常见的时间复杂度按数量级递增排列,依次为:常数阶0(1)、对数阶0(log2n)、线性阶0(n)、线性对数阶0(nlog2n)、平方阶0(n2)、立方阶0(n3)、k次方阶0(nk)、指数阶0(2n)。 先将题中的函数分成如下几类: 常数阶:2100 对数阶:lgn K次方阶:n0.5、n(3/2) 指数阶 (按指数由小到大排):nlgn、(3/2)n、2n、 n!、 nn 注意:(2/3)^n由于底数小于1,所以是一个递减函数,其数量级应小于常数阶。 根据以上分析按增长率由小至大的顺序可排列如下: (2/3)n < 2100 < lgn < n0.5 < n(3/2) < nlgn < (3/2)n < 2n < n! < nn 1.9 有时为了比较两个同数量级算法的优劣,须突出主项的常数因子,而将低次项用大\记号表示。例如,设T1(n)=1.39nlgn+100n+256=1.39nlgn+O(n), T2(n)=2.0nlgn-2n=2.0lgn+O(n), 这两个式子表示,当n 3 足够大时T1(n)优于T2(n),因为前者的常数因子小于后者。请用此方法表示下列函数,并指出当n足够大时,哪一个较优,哪一个较劣? 函数 大\表示 优劣 (1) T1(n)=5n2-3n+60lgn 5n2+O(n) 较差 (2) T2(n)=3n2+1000n+3lgn 3n2+O(n) 其次 (3) T3(n)=8n2+3lgn 8n2+O(lgn) 最差 (4) T4(n)=1.5n2+6000nlgn 1.5n2+O(nlgn) 最优 2.1 试描述头指针、头结点、开始结点的区别、并说明头指针和头结点的作用。 答:开始结点是指链表中的第一个结点,也就是没有直接前趋的那个结点。 链表的头指针是一指向链表开始结点的指针(没有头结点时),单链表由头指针唯一确定,因此单链表可以用头指针的名字来命名。 头结点是在链表的开始结点之前附加的一个结点。有了头结点之后,头指针指向头结点,不论链表否为空,头指针总是非空。而且头指针的设置使得对链表的第一个位置上的操作与在表其他位置上的操作一致(都是在某一结点之后)。 2.2 何时选用顺序表、何时选用链表作为线性表的存储结构为宜? 答:在实际应用中,应根据具体问题的要求和性质来选择顺序表或链表作为线性表的存储结构,通常有以下几方面的考虑: 1.基于空间的考虑。当要求存储的线性表长度变化不大,易于事先确定其大小时,为了节约存储空间,宜采用顺序表;反之,当线性表长度变化大,难以估计其存储规模时,采用动态链表作为存储结构为好。2.基于时间的考虑。若线性表的操作主要是进行查找,很少做插入和删除操作时,采用顺序表做存储结构为宜;反之, 若需要对线性表进行频繁地插入或删除等的操作时,宜采用链表做存储结构。并且,若链表的插入和删除主要发生在表的首尾两端,则采用尾指针表示的单循环链表为宜。 2.3 在顺序表中插入和删除一个结点需平均移动多少个结点?具体的移动次数取决于哪两个因素? 答:在等概率情况下,顺序表中插入一个结点需平均移动n/2个结点。删除一个结点需平均移动(n-1)/2个结点。具体的移动次数取决于顺序表的长度n以及需插入或删除的位置i。i越接近n则所需移动的结点数越少。 2.4 为什么在单循环链表中设置尾指针比设置头指针更好? 答:尾指针是指向终端结点的指针,用它来表示单循环链表可以使得查找链表的开始结点和终端结点都很方便,设一带头结点的单循环链表,其尾指针为rear,则开始结点和终端结点的位置分别是rear->next->next 和 rear, 查找时间都是O(1)。 若用头指针来表示该链表,则查找终端结点的时间为O(n)。 2.5 在单链表、双链表和单循环链表中,若仅知道指针p指向某结点,不知道头指针,能否将结点*p从相应的链表中删去?若可以,其时间复杂度各为多少? 答:下面分别讨论三种链表的情况。 1. 单链表。若指针p指向某结点时,能够根据该指针找到其直接后继,能够顺后继指针链找到*p结点后的结点。但是由于不知道其头指针,所以无法访问到p指针指向的结点的直接前趋。因此无法删去该结点。 2. 双链表。由于这样的链表提供双向指针,根据*p结点的前趋指针和后继指针可以查找到其直接前趋和直接后继,从而可以删除该结点。其时间复杂度为O(1)。 3. 单循环链表。根据已知结点位置,可以直接得到其后相邻的结点位置(直接后继),又因为是循环链表,所以我们可以通过查找,得到p结点的直接前趋。因此可以删去p所指结点。其时间复杂度应为O(n)。 2.6 下述算法的功能是什么? LinkList Demo(LinkList L){ // L 是无头结点单链表 ListNode *Q,*P; 4
共分享92篇相关文档