25版王道数据结构课后习题详细分析 第二章线性表 2.3线性表的链式表示 选择题部分

一、单项选择题

————————————————————

————————————————————

解析:两种存储结构适用于不同的场合,不能简单地说谁好谁坏,Ⅰ错误。链式存储用指针表示逻辑结构,而指针的设置是任意的,因此比顺序存储结构能更方便地表示各种逻辑结构,Ⅱ正确。在顺序存储中,插入和删除结点需要移动大量元素,效率较低,Ⅲ的描述刚好相反。顺序存储结构既能随机存取又能顺序存取,而链式结构只能顺序存取,Ⅳ正确。

正确答案:B

————————————————————

————————————————————

解析:首先直接排除A和D。散列存储通过散列函数映射到物理空间,不能反映数据之间的逻辑关系,排除C。链式存储能方便地表示各种逻辑关系,且插入和删除操作的时间复杂度为O(1)。

正确答案:B

————————————————————

————————————————————

解析:链式存储设计时,各个不同结点的存储空间可以不连续,但结点内的存储单元地址必须连续。

正确答案:A

————————————————————

————————————————————

解析:顺序存储方式同样适用于存储图和树,Ⅰ错误。删除表尾结点时,必须从头开始找到表尾结点的前驱,其时间与表长有关,Ⅱ错误。循环单链表中最后一个结点的指针不是 NUIL,而是指向头结点,整个链表形成一个环,因此不存在空指针,Ⅲ正确。有序单链表只能依次查找插入位置,时间复杂度为O(n),Ⅳ正确。队列需要在表头删除元素,表尾插入元素,采用带尾指针的循环链表较为方便,插入和删除的时间复杂度都为O(1)

正确答案:D

————————————————————

————————————————————

对于这个问题,我们需要考虑各种操作在单链表和顺序表上的效率对比。

A. 删除所有值为x的元素

  • 顺序表:需要遍历整个表,对每个元素检查其值是否为x,如果是,则需要将该元素之后的所有元素向前移动一位来填补空缺。这涉及到多次的元素移动,时间复杂度为O(n*m),其中n是元素总数,m是值为x的元素的数量。
  • 单链表:同样需要遍历整个表,但对每个节点检查其值是否为x,如果是,则直接修改前一个节点的指针,跳过当前节点即可。这样不需要移动其他元素,时间复杂度为O(n)。
    因此,在单链表上删除所有值为x的元素效率更高。

B. 在最后一个元素的后面插入一个新元素

  • 顺序表:由于顺序表是连续存储的,找到最后一个元素是O(1)的,但在其后插入新元素可能需要移动大量元素以腾出空间(如果顺序表已满或几乎满),平均情况下效率并不高,特别是如果顺序表需要扩容。
  • 单链表:在最后一个元素后插入新元素需要遍历到链表的末尾,这通常是O(n)的,但一旦到达末尾,插入新元素就是O(1)的。尽管有遍历成本,但在最坏情况下,其总体效率并不明显优于顺序表(特别是在顺序表有足够空间时)。
    因此,这一选项在单链表和顺序表上的效率差别不大,但通常不认为单链表更优。

C. 顺序输出前k个元素

  • 顺序表:直接访问数组的前k个元素并输出,时间复杂度为O(k)。
  • 单链表:需要从头节点开始遍历链表,直到找到第k个元素,时间复杂度也是O(k)。
    两种结构在这一操作上效率相当。

D. 交换第i个元素和第2n-i-1个元素的值(i=0,…,n-1)

  • 顺序表:直接通过索引访问并交换两个元素的值,时间复杂度为O(1)(尽管有两次访问,但仍然是常数时间)。
  • 单链表:需要分别遍历到第i个元素和第2n-i-1个元素,这通常是O(n)的复杂度,因为你需要遍历链表来找到这两个元素。
    因此,在顺序表上执行此操作效率更高。

综上所述,选项A(删除所有值为x的元素)在单链表上实现要比在顺序表上实现效率更高。

正确答案:A

————————————————————

————————————————————

解析:s插入后,q成为s 的前驱,而p成为s的后继,选C。

正确答案:C

————————————————————

————————————————————

解析:若先建立链表,然后依次插入建立有序表,则每插入一个元素就需遍历链表寻找插入位置,即直接插入排序,时间复杂度为 O(n²)。若先将数组排好序,然后建立链表,建立链表的时间复杂度为O(n),数组排序的最好时间复杂度为O(nlog2n),总时间复杂度为O(nlog2n)。故选D。

正确答案:D

————————————————————

————————————————————

解析:先遍历长度为m的单链表,找到该单链表的尾结点然后将其next域指向另一个单链表的首结点,其时间复杂度为O(m)。

正确答案:C

————————————————————

————————————————————

解析:单链表设置头结点的目的是方便运算的实现,主要好处体现在:第一,有头结点后,插入和删除数据元素的算法就统一了,不再需要判断是否在第一个元素之前插入或删除第一个元素;第二,不论链表是否为空,其头指针是指向头结点的非空指针,链表的头指针不变,因此空表和非空表的处理也就统一了。

正确答案:C

————————————————————

————————————————————

解析:

A、删除单链表中的第一个元素

  • 这个操作需要找到并删除头结点之后的第一个节点(即实际存储数据的第一个节点)。这个操作不依赖于链表的长度,因为它总是发生在链表的开始位置。

B、删除单链表中的最后一个元素

  • 由于我们有尾指针r指向链表的最后一个节点,我们可以很容易地找到并删除这个节点。但是,在删除最后一个节点后,我们需要更新尾指针r以指向新的最后一个节点(即原最后一个节点的前一个节点)。这个操作实际上需要知道链表当前的长度(或者至少需要知道是否有除了头结点之外的节点),以确保尾指针r的正确更新。如果链表只有一个节点(不包括头结点),则删除后需要将尾指针r设置为NULL或指向头结点(取决于具体实现)。因此,这个操作与链表的长度有关。

C、在单链表第一个元素前插入一个新元素

  • 这个操作涉及到在头结点之后插入一个新节点,并使其成为新的第一个数据节点。这个操作不依赖于链表的长度,因为它总是在链表的开始位置进行。

D、在单链表最后一个元素后插入一个新元素

  • 尽管这个操作是在链表的末尾进行,但它实际上只需要尾指针r的帮助来找到最后一个节点,并在其后插入新节点。这个操作不依赖于链表的长度,因为尾指针r已经直接指向了最后一个节点。

综上所述,与链表长度有关的操作是B、删除单链表中的最后一个元素,因为它需要基于链表当前的长度(或结构)来正确地更新尾指针r。因此,正确答案是B。

正确答案:B

————————————————————

————————————————————

解析:在带头结点的单链表中,头指针head指向头结点,头结点的next域指向第一个元素结点,head->next==NULL表示该单链表为空。在不带头结点的单链表中,head直接指向第一个元素结点,head==NULL表示该单链表为空。

正确答案:B;A

————————————————————

————————————————————

解析:线性表有顺序存储和链式存储两种存储结构。若采用链式存储结构,则删除元素a50不需要移动元素;若采用顺序存储结构,则需要依次移动50个元素。

正确答案:D

————————————————————

————————————————————

解析:当采用头插法建立单链表时,数组后面的元素插入到单链表L的最前端,所以L中的元素次序与数组a的元素次序相反。

正确答案:B

————————————————————

————————————————————

解析:A显然错误。B表中第一个元素和最后一个元素不满足题设要求。双链表能很方便地访问前驱和后继,故删除和插入数据较为方便,C正确。D未考虑顺序存储的情况。

正确答案:C

————————————————————

————————————————————

解析:为了在p之前插入结点q,可以将p的前一个结点的next域指向q,将q的next域指向p,将q的prior域指向p 的前一个结点,将p的prior域指向q。仅D满足条件。

正确答案:D

————————————————————

————————————————————

解析:与上一题的分析基本类似,只不过这里是删除一个结点,注意将p的前、后两结点链接起来。关键是要保证在结点指针的修改过程中不断链。

正确答案:A

————————————————————

————————————————————

解析:结点A和B分别由指针p和q指示,但结点C仅能由p->next间接指示,因此在改变p->next和p->next->prior之前,必须先将q->next 指向结点C,即①要在③和④前面,且④要在③前面(因为若先执行③,则④相当于q->prior指向其自身,显然矛盾)。故只能选A。

正确答案:A

————————————————————

————————————————————

解析:当在双链表的两个结点(分别用第一个、第二个结点表示)之间插入一个新结点时,需要修改四个指针域,分别是:新结点的前驱指针域,指向第一个结点;新结点的后继指针域,指向第二个结点;第一个结点的后继指针域,指向新结点;第二个结点的前驱指针域,指向新结点。

正确答案:C

————————————————————

————————————————————

解析:设单链表递增有序,首先要在单链表中找到第一个大于x的结点的直接前驱p,在p之后插入该结点。查找的时间复杂度为O(n),插入的时间复杂度为O(1),总时间复杂度为O(n)。

正确答案:B

————————————————————

————————————————————

解析:在插入和删除操作上,单链表和双链表都不用移动元素,都很方便,但双链表修改指针的操作更为复杂,A错误。双链表中可以快速访问任何一个结点的前驱和后继结点,D正确。

正确答案:D

————————————————————

————————————————————

解析:

  • L 的值(或指向的值)是头结点在内存中的地址。
  • L 的地址是存储这个指针变量(即头结点地址)的内存位置。

带头结点的循环单链表L为空表时,满足L->next=L,即头结点的指针域与L的值相等,而不是头结点的指针域与L的地址相等。注意,带头结点的单循环链表中不存在空指针。

正确答案:C

————————————————————

————————————————————

解析:循环双链表L判空的条件是头结点(头指针)的prior和next域都指向它自身。

正确答案:D

————————————————————

————————————————————

解析:在链表的末尾插入和删除一个结点时,需要修改其相邻结点的指针域。而寻找尾结点及尾结点的前驱结点时,带头结点的双循环链表可从第一个节点向最后一个节点开始遍历,所需要的时间最少。

正确答案:A

————————————————————

————————————————————

解析:对于A,删除尾结点*p时,需要找到*p的前一个结点,时间复杂度为O(n)。对于B,删除首结点*p时,需要找到*p结点,这里没有直接给出头结点指针,而通过尾结点的prior指针找到*p 结点的时间复杂度为O(n)。对于D,删除尾结点*p时,需要找到*p的前一个结点,时间复杂度为O(n)。对于C,执行这四种算法的时间复杂度均为O(1)。

正确答案:C

————————————————————

————————————————————

解析:要求用O(1)的时间将两个循环单链表头尾相接,并未指明哪个链表接在另一个链表之后,所以对两个链表都要在O(1)的时间找到头结点和尾结点。因此,两个指针应都指向尾结点。

正确答案:B

————————————————————

————————————————————

解析:

表头指针是指向链表第一个节点(可能是头节点,也可能是第一个数据节点,这取决于链表是否包含头节点)的指针。它是链表在内存中的起始位置的引用,通过它可以遍历整个链表。表头指针是链表结构的一个重要组成部分,它使得我们可以访问和操作链表。

在循环单链表中,删除首元结点后,要保持链表的循环性,因此需要找到首元结点的前驱。当链表带头结点时,其前驱就是头结点,因此不论是表头指针还是表尾指针,删除首元结点的时间都为O(1)。当链表不带头结点时,其前驱是尾结点,因此,若有表尾指针,就可在O(1)的时间找到尾结点;若只有表头指针,则需要遍历整个链表找到尾结点,时间为O(n)。

正确答案:A

————————————————————

————————————————————

解析:对一个空循环单链表,有head->next==head,推理head->next->next==head->next==head。对含有一个元素的循环单链表,头结点(头指针head 指示〉的next域指向这个唯一的元素结点,该元素结点的next域指向头结点,因此也有head->next->next=head。

正确答案:D

————————————————————

————————————————————

解析:对于两种双链表,删除首结点的时间复杂度都是O(1)。对于非循环双链表,删除尾结点的时间复杂度是O(n);对于循环双链表,删除尾结点的时间复杂度是O(1)。(可从头节点直接到尾结点)

正确答案:D

————————————————————

————————————————————

解析:对于A,在最后一个元素之后插入元素的情况与普通单链表相同,时间复杂度为O(n);而删除第一个元素时,为保持单循环链表的性质(尾结点指向第一个结点),要先遍历整个链表找到尾结点,再做删除操作,时间复杂度为O(n)。对于B,双链表的情况与单链表的相同,一个是O(n),一个是O(1)。对于C,在最后一个元素之后插入一个元素,要遍历整个链表才能找到插入位置,时间复杂度为O(n);删除第一个元素的时间复杂度为O(1)。对于D,与A的分析对比,有尾结点的指针,省去了遍历链表的过程,因此时间复杂度均为O(1)。

正确答案:D

————————————————————

————————————————————

解析:单链表和双链表是动态数据结构,排除;静态链表采用数组表示,因此需要预先分配较大的连续空间,静态链表同时还具有一般链表的特点,即插入和删除不需要移动元素。

正确答案:B

————————————————————

————————————————————

解析:静态链表的存储空间虽然是顺序分配的,但元素的存储不是顺序的,查找时仍然需要按链依次进行,而插入、删除都不需要移动元素。静态链表的存储空间是一次性申请的,能容纳的最大元素个数在定义时就已确定。由于并非每个空间都存储了元素,因此会造成存储空间的浪费。

正确答案:B

————————————————————

————————————————————

解析:A的第二句代码,相当于将p前驱结点的后继指针指向其自身,错误;B和C的第一句代码,相当于将p后继结点的前驱指针指向其自身,错误。只有D正确。

正确答案:D

————————————————————

————————————————————

解析:

正确答案:D

————————————————————

————————————————————

解析:如图1所示,要删除带头结点的非空单循环链表中的第一个元素,就要先用临时指针q指向待删结点,q=h->next;然后将q从链表中断开,h->next=q->next(这一步也可写成h->next=h->next->next);此时要考虑一种特殊情况,若待删结点是链表的尾结点,即循环单链表中只有一个元素(p和q指向同一个结点),如图2所示,则在删除后要将尾指针指向头结点,即if(p==-q)p=h;最后释放q结点即可,答案选D。

正确答案:D

————————————————————

————————————————————

解析:

正确答案:C

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值