中南大学数据结构与算法第10章内部排序课后作业答案要点.docx

上传人:罗晋 文档编号:11662530 上传时间:2021-08-29 格式:DOCX 页数:25 大小:33.87KB
返回 下载 相关 举报
中南大学数据结构与算法第10章内部排序课后作业答案要点.docx_第1页
第1页 / 共25页
中南大学数据结构与算法第10章内部排序课后作业答案要点.docx_第2页
第2页 / 共25页
中南大学数据结构与算法第10章内部排序课后作业答案要点.docx_第3页
第3页 / 共25页
中南大学数据结构与算法第10章内部排序课后作业答案要点.docx_第4页
第4页 / 共25页
中南大学数据结构与算法第10章内部排序课后作业答案要点.docx_第5页
第5页 / 共25页
点击查看更多>>
资源描述

《中南大学数据结构与算法第10章内部排序课后作业答案要点.docx》由会员分享,可在线阅读,更多相关《中南大学数据结构与算法第10章内部排序课后作业答案要点.docx(25页珍藏版)》请在三一文库上搜索。

1、第 10章内部排序 习题练习答案1 .以关键字序列(265, 301, 751 , 129, 937, 863, 742, 694, 076, 438)为例,分别写出执行以下排序算法的各趟排序结束时,关键字序列的状态。(1) 直接插入排序(2)希尔排序(3) 冒泡排序 (4)快速排序(5) 直接选择排序(6) 堆排序 (7) 归并排序 (8)基数排序上述方法中,哪些是稳定的排序?哪些是非稳定的排序?对不稳定的排序试举出一个不稳定的实例。答:(1)直接插入排序:(方括号表示无序区)初始态 : 265301 751 129 937 863 742 694 076 438第一趟:2653017511

2、29 937863 742694 076438第二趟:265301 751129 937863 742694 076438第三趟:129265 301751937863 742694 076438第四趟:129265 301751 937863 742694 076438第五趟:129265 301751 863937742694 076438第六趟:129265 301742 751863 937694 076438第七趟:129265 301694 742751 863937076438第八趟:076129 265301 694742 751863 937438第九趟: 076 129 2

3、65 301 438 694 742 751 863 937(2)希尔排序(增量为5, 3, 1)初始态 : 265 301 751 129 937 863 742 694 076 438第一趟: 265 301 694 076 438 863 742 751 129 937第二趟: 076 301 129 265 438 694 742 751 863 937第三趟: 076 129 265 301 438 694 742 751 863 937(3) 冒泡排序(方括号为无序区)初始态 265 301 751 129 937 863 742 694 076 438第一趟: 076 265 3

4、01 751 129 937 863 742 694 438第二趟: 076 129 265 301 751 438 937 863 742 694第三趟: 076 129 265 301 438 694 751 937 863 742第四趟: 076 129 265 301 438 694 742 751 937 863第五趟: 076 129 265 301 438 694 742 751 863 937第六趟: 076 129 265 301 438 694 742 751 863 937(4)快速排序:(方括号表示无序区,层表示对应的递归树的层数)初始态: 265 301 751 12

5、9 937 863 742 694 076 438第二层: 076 129 265 751 937 863 742 694 301 438第三层: 076 129 265 438 301 694 742 751 863 937第四层: 076 129 265 301 438 694 742 751 863 937第五层: 076 129 265 301 438 694 742 751 863 937第六层: 076 129 265 301 438 694 742 751 863 937(5)直接选择排序: (方括号为无序区 )初始态 265 301 751 129 937 863 742 69

6、4 076 438第一趟: 076 301 751 129 937 863 742 694 265 438第二趟: 076 129 751 301 937 863 742 694 265 438第三趟: 076 129 265 301 937 863 742 694 751 438第四趟: 076 129 265 301 937 863 742 694 751 438第五趟: 076 129 265 301 438 863 742 694 751 937第六趟: 076 129 265 301 438 694 742 751 863 937第七趟: 076 129 265 301 438 69

7、4 742 751 863 937第八趟: 076 129 265 301 438 694 742 751 937 863第九趟: 076 129 265 301 438 694 742 751 863 937(6)堆排序:(通过画二叉树可以一步步得出排序结果)初始态265 301 751 129 937 863 742 694 076 438建立初始堆: 937 694 863 265 438 751 742 129 075 301第一次排序重建堆: 863 694 751 765 438 301 742 129 075 937第二次排序重建堆: 751 694 742 265 438 30

8、1 075 129 863 937第三次排序重建堆: 742 694 301 265 438 129 075 751 863 937第四次排序重建堆: 694 438 301 265 075 129 742 751 863 937第五次排序重建堆: 438 265 301 129 075 694 742 751 863 937第六次排序重建堆: 301 265 075 129 438 694 742 751 863 937第七次排序重建堆: 265 129 075 301 438 694 742 751 863 937第八次排序重建堆: 129 075265 301 438 694 742 7

9、51 863 937第九次排序重建堆: 075 129 265 301 438 694 742 751 863 937(7)归并排序(为了表示方便,采用自底向上的归并,方括号为有序区)初始态: 265 301 751 129 937 863 742 694 076 438第一趟: 265 301 129 751 863 937 694 742 076 438第二趟: 129 265 301 751 694 742 863 937 076 438第三趟:129 265 301 694 742 751 863 937 076 438第四趟:076 129 265 301 438 694 742 7

10、51 863 937(8)基数排序(方括号内表示一个箱子共有10 个箱子,箱号从0 到 9)初始态: 265 301 751 129 937 863 742 694 076 438第一趟: 301 751 742 863 694 265 076 937 438 129第二趟: 301 129 937 438 742 751 863 265 076 694第三趟: 075 129 265 301 438 694 742 751 863 937在上面的排序方法中,直接插入排序、冒泡排序、归并排序和基数排序是稳定的,其他排序算法均是不稳定的,现举实例如下:以带*号的表示区别。希尔排序:8,1,10,

11、5,6,*8快速排序:2,*2,1直接选择排序: 2,*2,1堆排序: 2,*2,12 .上题的排序方法中,哪些易于在链表(包括各种单、双、循环链表)上实现 ?答:上题的排序方法中,直接插入排序、冒泡排序、直接选择排序、基数排序和归并排序等方法易于在链表上实现。3 .当 Rlow.high 中的关键字均相同时, Partion 返回值是什么?此时快速排序的的运行时间是多少?能否修改Partion,使得划分结果是平衡的(即划分后左右区间的长度大致相等)?答:此时 Partion 返回值是 low. 此时快速排序的运行时间是(high-low)(high-low-1)/2=O(high-low)A

12、2),可以修改 Partion ,将其中 RecType pivot=Ri;句改为:RecTypepivot=R(j+i)/2 ;也就是取中间的关键字为基准,这样就能使划分的结果是平衡的。4 .若文件初态是反序的,则直接插入,直接选择和冒泡排序哪一个更好 ?答:应选直接选择排序为更好。分析如下:(1)在直接插入排序算法中,反序输入时是最坏情况,此时:关键字的比较次数: Cmax=(n+2)(n-2)/2;记录移动次数为: Mmax=(n-1)(n+4)/2;Tmax=nA2-4n-3 (以上二者相加)(2)在冒泡排序算法中,反序也是最坏情况,此时:Cmax=n(n-1)/2; Mmax=3n(

13、n-1)/2Tmax=2nA2-2n(3)在选择排序算法中,Cmax=n(n-1)/2 Mmax=3(n-1)Tmax=nA2/2-5n/2-3由此可见,虽然它们的时间复杂度都是。6八2),但是选择排序的常数因子为1/2,因此选择排序最省时间。5 .若文件初态是反序的,且要求输入稳定,则在直接插入、直接选择、冒泡和快速排序中就选选哪种方法为宜 ?答:这四种排序算法中,直接选择、快速排序均是不稳定的,因此先予以排除,剩下两种算法中,由于直接插入算法所费时间比冒泡法更少(见上题分析) ,因此选择直接排序算法为宜。6 .有序数组是堆吗 ?答:有序数组是堆。因为有序数组中的关键字序列满足堆的性质。若数

14、组为降序,则此堆为大根堆,反之为小根堆。7 .高度为h 的堆中, 最多有多少个元素?最少有多少个元素?在大根堆中,关键字最小的元素可能存放在堆的哪些地方?答:高度为 h 的堆实际上为一棵高度为 h 的完全二叉树, 因此根据二叉树的性质可以算出, 它最少应有2h-1个元素;最多可有2h-1 个元素(注意一个有括号,一个没有) 。在大根堆中,关键字最小的元素可能存放在堆的任一叶子结点上。8 .判别下列序列是否为堆(小根堆或大根堆),若不是,则将其调整为堆:(1) (100,86,73,35,39,42,57,66,21);(2) (12,70,33,65,24,56,48,92,86,33);(3

15、) (103,97,56,38,66,23,42,12,30,52,06,20);(4) (05,56,20,23,40,38,29,61,35,76,28,100).答:堆的性质是:任一非叶结点上的关键字均不大于 (或不小于 )其孩子结点上的关键字。据此我们可以通过画二叉树来进行判断和调整:(1) 此序列是大根堆。(2) 此序列不是堆,经调整后成为小根堆:(12 , 24, 33, 65, 33, 56, 48, 92, 86, 70)(3) 此序列是一大根堆。(4) 此序列不是堆,经调整后成为小根堆:(01 , 05, 20, 23, 28, 38, 29, 56, 35, 76, 40,

16、 100)9 .将两个长度为n 的有序表归并为一个长度为2n 的有序表, 最小需要比较n 次, 最多需要比较 2n-1 次, 请说明这两种情况发生时,两个被归并的表有何特征?答:前一种情况下,这两个被归并的表中其中一个表的最大关键字不大于另一表中最小的关键字,也就是说,两个有序表是直接可以连接为有序的,因此,只需比较n 次就可将一个表中元素转移完毕,另一个表全部照搬就行了。另一种情况下,是两个被归并的有序表中关键字序列完全一样,这时就要按次序轮流取其元素归并,因此比较次数达到 2n-1.10 .设关键字序列为(0.79, 0.13, 0.16, 0.64, 0.39, 0.20, 0.89,

17、0.53, 0.71, 0.42),给出桶排序的结果。答:桶排序的结果如图:B0.9I I0 I AI1 - 0.13 0.16- AI2 -0.20 - AI3 -0.39 -AI4 -0.42 -AI5 -0.53 -AI6 -0.64 -AI7 -0.710.79-AI8 -0.89 -AI9 I A1 1结果为:0.13 0.16 0.20 0.39 0.42 0.53 0.64 0.71 0.79 0.8911.若关键字是非负整数、快速排序、归并、堆和基数排序啊一个最快布要求辅助空间为 0(1),则应选择谁?若要求排序是稳定的,且关键字是实数,则应选择谁 ?答:若关键字是非负整数,则

18、基数排序最快;若要求辅助空间为0(1),则应选堆排序;若要求排序是稳定的, 且关键字是实数,则应选归并排序,因为基数排序不适用于实数,虽然它也是稳定的12.对于 8.7节的表 8.2,解释下述问题:(1) 当待排序的关键字序列的初始态分别为正序和反序时, 为什么直接选择排序的时间基本相同 ?若采用本书 8.4.1 节的算法,这两种情况下的排序时间是否基本相同 ?(2) 为什么数组的初态为正序时,冒泡和直接插入排序的执行时间最少?(3)若采用 8.3.2 节的快速排序,则数组初态为正序和反序时,能得到与表8.2 类似的结果吗?答:(1) 由于在直接选择排序中,主要的操作是比较操作和移动操作。无论

19、文件的初始状态如何,若文件有n个记录,则都要进行n-1 趟直接选择排序,第i 趟直接选择排序中都要做 n-i 次比较才能选出最小关键字的记录。所以总的比较次数都为O(n2)。至于记录的移动次数,初始文件为正序时,移动次数为 0,当文件初始时为反序,总的移动次数为3(n-1) 。因此当待排序的关键字序列的初始态分别为正序和反序时,直接选择排序的时间基本相同,为O(n2) 。若采用本书8.4.1 节的算法,这两种情况下的排序时间基本相同。(2) 当冒泡排序是正序时,只需做一趟冒泡排序就可完成,共做 n-1 次比较,移动次数为0,所以执行时间最少。而直接插入排序时,若初始为正序,则做了 n-1 趟直

20、接插入排序,但每趟排序只做了一次比较,共做 n-1 次比较。移动次数为0 。所以当数组初态为正序,直接插入排序时间也最少。(3)不能,其中辅助空间不同13 . 将哨兵放在Rn 中,被排序的记录放在 R0.n-1 中,重写直接插入排序算法。解:重写的算法如下:void InsertSort(SeqList R)/对顺序表中记录R0.n-1 按递增序进行插入排序int i,j;for(i=n-2;i=0;i-) / 在有序区中依次插入 Rn-2.R0if(Ri.keyRi+1.key) / 若不是这样则 Ri 原位不动Rn=Ri;j=i+1; /Rn 是哨兵do / 从左向右在有序区中查找插入位置

21、Rj-1=Rj; / 将关键字小于Ri.key 的记录向右移j+;while(Rj.keynext)&(head-next-next)/ 当表中含有结点数大于1p=head-next-next;/p 指向第二个节点head-next=NULL;q=head;/指向插入位置的前驱节点while(p)&(q-next)&(p-keynext-key)q=q-next;if (p)s=p;p=p-next;/ 将要插入结点摘下s-next=q-next;/ 插入合适位置: q 结点后q-next=s;15 .设计一算法,使得在尽可能少的时间内重排数组, 将所有取负值的关键字放在所有取非负值的关键字之

22、前。请分析算法的时间复杂度。解:因为只需将负数关键字排在前面而无需进行精确排列顺序,因此本算法采用两端扫描的方法,就象快速排序采用的方法一样,左边扫描到正数时停止,开始扫描右边,遇到负数时与左边的当前记录交换,如此交替进行,一趟下来就可以完成排序。void ReSort(SeqList R)/ 重排数组,使负值关键字在前int i=1,j=n; / 数组存放在 R1.n中while (ij) /ij 表示尚未扫描完毕 while(ij&Ri.key0) / 遇到负数则继续扫描i+;R0=Ri; /R0 为辅助空间while(i=0)/ 遇到正数则继续向左扫描j-;Ri+=Rj;Rj-=R0;/

23、交换当前两个元素并移动指针/endwhile/ReSort本算法在任何情况下的比较次数均为n(每个元素和0)相比,交换次数少于n/2,总的来说,时间复杂度为 O(n).*16. 写一个双向冒泡排序的算法,即在排序过程中交替改变扫描方向。解:算法如下:void BubbleSort(SeqList R)/R1.n 是待排序文件,双向扫描冒泡排序int i,j,k;Boolean exchange; /交换标记i=n;j=1;exchange=TRUE;while (ij)&(exchange)k=i-1;exchange=FALSE;while (k=j)/ 由下往上扫描if (rkrk+1)r

24、0=rk;rk=rk+1;rk+1=rk;exchange=TRUE;/ 交换/endifk-;/endwhileif (exchange)exchange=FALSE;j+;k=j+1;while(k=i)/ 由上往下扫描if (rk0)lastExchange=0;for(j=0;ji;j+)/ 从上往下扫描A0.iif(Aj+1Aj)交换 Aj 和 Aj+1;lastExchange=j;i=lastExchange;/将i置为最后交换的位置/endwhile/BubbleSort解:算法如下:void BubbleSort(int A,int n)/不妨设 A0.n-1 是整型向量in

25、t lastExchange,j,i=0;while (ii;j-)/ 从下往上扫描A0.iif(Aj-1Aj)交换 Aj 和 Aj-1;lastExchange=j;i=lastExchange;/将i置为最后交换的位置/endwhile/BubbleSort18.改写快速排序算法,要求采用三者取中的方式选择划分的基准记录; 若当前被排序的区间长度小于等于3 时,无须划分而是直接采用直接插入方式对其排序。解:改写后的算法如下:void QuickSort(SeqList R,int low ,int high)/对 Rlow.high 快速排序int pivotpos;if(high-low

26、Ri.key) 交换R(i+j)/2 和 Ri;if(Ri.keyRj.key) 交换Ri 和 Rj;if(Ri.key)R(i+j)/2.key) 交换 Ri 和 R(i+j)/2;/ 以上三个if 语句就使区间的第一个记录的 key 值为三个 key 的中间值return Partion(R,i,j);/ 这样我们就可以仍使用原来的划分算法了 19 .对给定的j(1 wjn求在无序的记录区R1.n中找到按关键字自小到大排在第j个位置上的记录(即在无序集合中找到第j 个最小元),试利用快速排序的划分思想编写算法实现上述的查找操作。答:int QuickSort(SeqList R,int j

27、,int low,int high) / 对Rlow.high 快速排序int pivotpos ; /划分后的基准记录的位置if(lowj) return(R,j,low,pivotpos-1);else return quicksort(R,j,pivotpos+1,high); /QuickSort20 .以单链表为存储结构,写一个直接选择排序算法。 答:#define int KeyType / 定义 KeyType 为 int 型typedef struct nodeKeyType key; / 关键字域OtherInfoType info; / 其它信息域,struct node

28、* next; / 链表中指针域RecNode; / 记录结点类型typedef RecNode * LinkList ; / 单链表用 LinkList 表示void selectsort(linklist head)RecNode *p,*q,*s;if(head-next)&(head-next-next)p=head-next;/p 指向当前已排好序最大元素的前趋while (p-next)q=p-next;s=p;while(q)if (q-keykey) s=q;q=q-next;/endwhile交换 s 结点和 p 结点的数据; p=p-next;/endwhile/endif

29、/endsort21 .写一个heapInsert(R,key)算法,将关键字插入到堆 R中去,并保证插入 R后仍是堆。提示:应为堆 R 增加一个长度属性描述(即改写本章定义的SeqList类型描述,使其含有长度域);将key先插入R中已有 元素的尾部( 即原堆的长度加1 的位置, 插入后堆的长度加1) , 然后从下往上调整, 使插入的关算字满足性质。请分析算法的时间。答:#define n 100/假设文件的最长可能长度typedef int KeyType; / 定义 KeyType 为 int 型typedef struct nodeKeyType key; / 关算字域OtherInf

30、oType info; / 其它信息域,Rectype; / 记录结点类型typedef structRectype datan ; / 存放记录的空间int length;/ 文件长度seqlist;void heapInsert(seqlist *R,KeyType key)/ 原有堆元素在R-data1R-dataR-length,/将新的关键字key 插入到 R-dataR-length+1 位置后,/ 以 R-data0 为辅助空间,调整为堆(此处设为大根堆)int large;/large 指向调整结点的左右孩子中关键字较大者int low,high;/low 和 high 分别指

31、向待调整堆的第一个和最后一个记录int i;R-length+ ; R-dataR-length.key=key;/ 插入新的记录for(i=R-length/2;i0;i-)/ 建堆low=i;high=R-length;R-data0.key=R-datalow.key;/R-datalow 是当前调整的结点for(large=2*low;largehigh ,则表示R-datalow 是叶子,调整结束;/ 否则令large 指向 R-datalow 的左孩子if(largedatalarge.keydatalarge+1.key)large+;/ 若 R-datalow 的右孩子存在/

32、且关键字大于左兄弟,则令 large 指向它if (R-data0.keydatalarge.key) R-datalow.key= R-datalarge.key;low=large;令low指向新的调整结点else break;/当前调整结点不小于其孩子结点的关键字,结束调整/endforR-datalow.key=R-data0.key;/ 将被调整结点放入最终的位置上/end of forend of heapinsert算法分析:设文件长度为n,则该算法需进行n/2趟调整,总的时间复杂度与初建堆类似,最坏时间复杂度为O(nlgn) ,辅助空间为O(1).22 .写一个建堆算法:从空堆

33、开始,依次读入元素调用上题中堆插入算法将其插入堆中。答:void BuildHeap(seqlist *R)KeyType key;R-length=0;/ 建一个空堆scanf(%d,&key);/ 设 MAXINT 为不可能的关键字while(key!=MAXINT)heapInsert(R,key);scanf(%d,&key); 23 .写一个堆删除算法:HeapDelete(R,i),将Ri从堆中删去,并分析算法时间,提示:先将 Ri和堆中最后 一个元素交换,并将堆长度减1 ,然后从位置i 开始向下调整,使其满足堆性质。答:void HeapDelete(seqlist *R,int

34、 i)/ 原有堆元素在R-data1R-dataR-length,/ 将 R-datai 删除,即将R-dataR-length 放入 R-datai 中后,/将 R-length 减 1,再进行堆的调整,/ 以 R-data0 为辅助空间,调整为堆(此处设为大根堆)int large;/large 指向调整结点的左右孩子中关键字较大者int low,high;/low 和 high 分别指向待调整堆的第一个和最后一个记录int j;if (iR-length)Error(have no such node);R-datai.key=R-dataR-length.key;R-length- ;

35、 R-dataR-length.key=key;/ 插入新的记录for(j=i/2;j0;j-)/ 建堆low=j;high=R-length;R-data0.key=R-datalow.key;/R-datalow 是当前调整的结点for(large=2*low;largehigh ,则表示 R-datalow 是叶子,调整结束;/ 否则令 large 指向 R-datalow 的左孩子if(largedatalarge.keydatalarge+1.key)large+;/ 若 R-datalow 的右孩子存在/ 且关键字大于左兄弟,则令 large 指向它if (R-data0.keyd

36、atalarge.key) R-datalow.key= R-datalarge.key;low=large;/ 令 low 指向新的调整结点else break;/当前调整结点不小于其孩子结点的关键字,结束调整/endforR-datalow.key=R-data0.key;/ 将被调整结点放入最终的位置上/end of forend of HeapDelete24 .已知两个单链表中的元素递增有序, 试写一算法将这两个有序表归并成一个递增有序的单链表。 算法应 利用原有的链表结点空间。答:typedef struct nodeKeyType key; / 关键字域OtherInfoType

37、 info; / 其它信息域,struct node * next; / 链表中指针域RecNode; / 记录结点类型typedef RecNode * LinkList ; / 单链表用 LinkList 表示void mergesort(LinkList la,LinkList lb,LinkList lc)RecNode *p,*q,*s,*r;lc=la;p=la;/p 是 la 表扫描指针,指向待比较结点的前一位置q=lb-next;/q 是 lb 表扫描指针,指向比较的结点while(p-next)&(q)if (p-next-keykey)p=p-next;else s=q;q

38、=q-next;s-next=p-next;p-next=s;/ 将 s 结点插入至U p 结点后p=s;if (!p-next) p-next=q;free(lb);O(n)25 .设向量A0.n-1中存有n个互不相同的整数,且每个元素的值均在。至U n-1之间。试写一时间为的算法将向量A 排序,结果可输出到另一个向量B0.n-1 中。答:sort(int *A,int *B)/ 将向量 A 排序后送入 B 向量中int i;for(i=0;i=n-1;i+)BAi=Ai;d 个字母。*26. 写一组英文单词按字典序排列的基数排序算法。设单词均由大写字母构成,最长的单词有提示:所有长度不足

39、d 个字母的单词都在尾处补足空格,排序时设置27 个箱子,分别与空格, A , B.Z对应。答:#define KeySize 10 / 设关键字位数 d=10#define Radix 27 / 基数 rd 为 27typedef RecType DataType;/ 将队列中结点数据类型改为 RecType 类型typedef struct nodechar keyKeySize; / 关键字域OtherInfoType info; / 其它信息域,RecType; / 记录结点类型typedef RecType seqlistn+1;void RadixSort(seqlist R)LinkQueue BRadix;int i;for(i=0;i=0;i-)/ 从

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 科普知识


经营许可证编号:宁ICP备18001539号-1