前面几篇文章介绍的是排序算法,现在让我们开始排序算法的专项练习。
目录
- 判断题
- 选择题
- 填空题
- 1.插入排序
- 2.另类选择排序
- 3.冒泡排序
- 4.快速查找第K大元
判断题
1.希尔排序是稳定的算法。(错)
解析:稳定性是指如果两个元素在排序前后的相对顺序保持不变,那么这个排序算法就是稳定的。对于具有相同关键字的元素,排序后它们的相对位置应该保持不变。
2.仅基于比较的算法能得到的最好的“最坏时间复杂度”是O(NlogN)。(对)
3.对N个记录进行归并排序,归并趟数的数量级是O(NlogN)。(错)
答案:O(logN)
4.对N个不同的数据采用冒泡排序进行从大到小的排序,当元素基本有序时交换元素次数肯定最多。(错)
解析:当元素已经基本有序时,冒泡排序的时间复杂度会变得比较低,因为只需要进行少量的交换操作就可以将序列排好序。
5.插入排序算法在每一趟都能选取出一个元素放在其最终的位置上。 (错)
解析:每次插入操作只会将一个元素插入到已经排序好的子序列中,而不是所有元素都放到最终位置上。
6.对N个记录进行简单选择排序,比较次数和移动次数分别为O(N^2)和O(N)。(对)
解析:简单选择排序的基本思想是:每一轮从待排序的序列中选取最小的元素,将其与序列的第一个元素交换位置,然后在剩余的元素中继续寻找最小值,重复上述过程直到序列排好序为止。
7.对N个记录进行快速排序,在最坏的情况下,其时间复杂度是O(NlogN)。(错)
在最好情况和平均情况下,快速排序算法时间复杂性为O(NlogN);在最坏的情况下,其时间复杂度是O(N^2)
8.采用递归方式对顺序表进行快速排序,每次划分后,先处理较短的分区可以减少递归次数。(错)
解析:快速排序的性能与划分后两个子序列的大小无关,在最坏的情况下,仍然可能出现O(N^2)的时间复杂度。
9.空间复杂度:堆排序<快速排序<归并排序(对)
10.堆排序的时间复杂度为O(nlogn),空间复杂度为O(1)(对)
11.要从50个键值中找出最大的3个值,选择排序比堆排序快。(对)
12.计数排序是一个广泛使用的排序算法。对n个分布在[0, m]的整数进行计数排序,时间复杂度为 ()
A.O(m)
B.O(n logn)
C.O(n)
D.O(m+n)
选C
13.在简单选择排序过程中,关键字比较的次数与记录的初始排列次序无关。(对)
选择题
1.有组记录的排序码为{46,79,56,38,40,84 },采用快速排序(以位于最左位置的对象为基准)得到的第一次划分结果为:
A.{40,38,46,56,79,84}
B.{38,46,56,79,40,84}
C.{38,79,56,46,40,84}
D.{38,46,79,56,40,84}
选A,解析:
46,79,56,38,40,84
l r
因为以46为基准,所以l不动,对r进行分析
84大于46,所以不用动
接着r--,对应40
46,79,56,38,40,84
l r
40小于46,所以将40替换46
40,79,56,38,——,84
l r
接着l++
40,79,56,38,——,84
l r
l对应79,大于40,所以79替换到r的地方
40,——,56,38,79,84
l r
接着r--,对应38
40,——,56,38,79,84
l r
38小于40,所以38替换到l的地方
40,38,56,——,79,84
l r
接着l++
40,38,56,——,79,84
l r
l对应56,大于40,所以56替换到r处
40,38,——,56,79,84
l r
接着r--
此时l与r位置相同
所以不用替换,直接把基准值46填进去就行
2.使用快速排序算法对数据进行升序排序,若经过一次划分后得到的数据序列是 68, 11, 70, 23, 80, 77, 48, 81, 93, 88,则该次划分的枢轴是:
A.81
B.70
C.80
D.11
选A,解析:枢轴的左边比它小,右边比它大。
3.在基于比较的排序算法中,哪种算法的最坏情况下的时间复杂度不高于O(NlogN)?
A.冒泡排序
B.希尔排序
C.快速排序
D.归并排序
选D,上文讲过了。
4.在快速排序的一趟划分过程中,当遇到与基准数相等的元素时,如果左右指针都会停止移动,那么当所有元素都相等时,算法的时间复杂度是多少?
A.O(N)
B.O(NlogN)
C.O(logN)
D.O(N2)
选A,解析:指针停止就会不断交换左右指针的元素,这样虽然多余的交换次数变多,但让子序列的元素相对平均,所以一共有logN次划分,时间复杂度是O(N)。
5.对数据进行排序时,若采用直接插入排序而不采用快速排序,则可能的原因是
I. 大部分元素已有序
II. 待排序元素数量很少
III. 要求空间复杂度为O(1)
IV. 要求排序算法是稳定的
二者区别如下:直接插入排序是一种简单的排序算法,它的思想是将待排序序列分为已排序和未排序两部分,每次从未排序部分取出一个元素,插入到已排序部分的合适位置。快速排序是一种分治法的排序算法,它通过选择一个基准值,将序列划分为比基准值小和比基准值大的两部分,然后对这两部分进行递归排序。
直接插入排序是稳定的排序算法,相等元素的相对顺序不会改变。快速排序是不稳定的排序算法,相等元素的相对顺序可能会改变。
故本题选I、II、III、IV
6.采用递归方式对顺序表进行快速排序,下列关于递归次数的叙述中,正确的是:
A.每次划分后,先处理较长的分区可以减少递归次数
B.递归次数与初始数据的排列次序无关
C.递归次数与每次划分后得到的分区处理顺序无关
D.每次划分后,先处理较短的分区可以减少递归次数
选C,解析:无论是先处理长分区还是先处理短分区,递归次数均不变。
7.选择一个排序算法时,除算法的时空效率外,下列因素中,还需要考虑的是:
- I、数据的规模
- II、数据的存储方式
- III、算法的稳定性
- IV、数据的初始状态
答案:全选。
8.在快速排序的一趟划分过程中,当遇到与基准数相等的元素时,如果左指针停止移动,而右指针在同样情况下却不停止移动,那么当所有元素都相等时,算法的时间复杂度是多少?
答案:O(N^2)
比如说
1 1 1 1 1 1 1 1 .... 1 1 1(共n个)
i j
由于i不动,所以j一直左移,左移n-1次
第一次完成后变为
1 1 1 1 1 1 1 1 .... 1 1 1(共n个)
i j
由于i不动,所以j一直左移,左移n-2次
由此一直递归
则次数为
n-1 + n-2 + n-3 + n-4 + n-5 + n-6 + ....
9.排序过程中,对尚未确定最终位置的所有元素进行一遍处理称为一“趟”。下列序列中,不可能是快速排序第二趟结果的是:
A.5, 2, 12, 28, 16, 32, 72, 60
B.5, 2, 16, 12, 28, 60, 32, 72
C.2, 16, 5, 28, 12, 60, 32, 72
D.2, 12, 16, 5, 28, 32, 72, 60
答案选A
解析
先按升序和降序排序
2 5 12 16 28 32 60 72
72 60 32 28 16 12 5 2
因为这题的答案趋势为小的数在左边,大的数在右边
所以我们将升序序列与答案作比较
经过两次快速排序之后,可能的是:
1.产生两个基准,第一个基准要不然在最左要不然在最右,剩下一个基准任意
2.产生三个基准,第一个基准在中间,剩下两个分别在两边
2 5 12 16 28 32 60 72
A(5, 2, 12, 28, 16, 32, 72, 60)
我们发现A选项有12、32与升序序列是对应的
可12和32都不在最左或最右,所以A错
接着看B
2 5 12 16 28 32 60 72
B.5, 2, 16, 12, 28, 60, 32, 72
我们发现B选项有28、72与升序序列是对应的
所以B可能对
看C
2 5 12 16 28 32 60 72
C.2, 16, 5, 28, 12, 60, 32, 72
C中有2、72是对应的,同理C可能正确
看D
2 5 12 16 28 32 60 72
D.2, 12, 16, 5, 28, 32, 72, 60
D中有2、28、32是对应的,同理D可能正确
10.设数组 S[ ]={93, 946, 372, 9, 146, 151, 301, 485, 236, 327, 43, 892},采用最低位优先(LSD)基数排序将 S 排列成升序序列。第 1 趟分配、收集后,元素 372 之前、之后紧邻的元素分别是:
A.485,301
B.301,892
C.236,301
D.43,892
基数排序是一种稳定的排序方法。由于采用最低位优先(LSD) 的基数排序,即第1趟对个位进行分配和收集的操作(按最低位进行排序),因此第一趟 分配和收集后的结果是{151, 301, 372, 892, 93, 43,485, 946, 146, 236, 327,9},元素372之前、之后紧邻的元素分别是301和892,故选B。
11.使用二路归并排序对含 n 个元素的数组 M 进行排序时,二路归并操作的功能是:
A.将两个有序表合并为一个新的有序表
B.将 M 划分为两部分,两部分的元素个数大致相等
C.将 M 划分为两部分,一部分元素的值均小于另一部分元素的值
D.将 M 划分为 n 个部分,每个部分中仅含有一个元素
选A,解析:二路归并排序(Two-way Merge Sort)是归并排序的一种常见实现方式。它将待排序序列不断地划分成两个子序列,然后对每个子序列进行排序,并最后将两个有序的子序列合并起来,从而得到完全有序的序列。
12.给定初始待排序列{ 15,9,7,8,20,-1,4 }。如果希尔排序第一趟结束后得到序列为{ 15,-1,4,8,20,9,7 },则该趟增量为:
A.1
B.4
C.2
D.3
选B,解析:序列中相距4个位置相对应的元素为{ 15,20 }、{ 9,-1 }、{ 7,4 }、{ 8, }。通过比较和交换操作,可将这些元素序列调整为{ 15,-1,4,8,20,9,7 }。
13.对于7个数进行冒泡排序,需要进行的比较次数为:
A.7
B.14
C.21
D.49
选C,解析:冒泡排序的比较次数可以通过以下公式计算:(n-1) + (n-2) + … + 2 + 1 = n*(n-1)/2,故本题比较次数为21。
14.对于10个数的简单选择排序,最坏情况下需要交换元素的次数为:
A.100
B.45
C.36
D.9
选D,解析:简单选择排序在最坏情况下,会经过n-1次选取最值,才能完成排序。
选择排序图示:
15.对一组包含10个元素的非递减有序序列,采用直接插入排序排成非递增序列,其可能的比较次数和移动次数分别是:
A.100, 100
B.54, 63
C.100, 54
D.45, 44
选D,解析:当元素均为逆序时,插入排序执行的比较和交换次数为n*(n-1)/2,但本题可以考虑有两个元素相同的情况,所以移动次数可以比45少1。
16.对初始数据序列{ 8, 3, 9, 11, 2, 1, 4, 7, 5, 10, 6 }进行希尔排序。若第一趟排序结果为( 1, 3, 7, 5, 2, 6, 4, 9, 11, 10, 8 ),第二趟排序结果为( 1, 2, 6, 4, 3, 7, 5, 8, 11, 10, 9 ),则两趟排序采用的增量(间隔)依次是:
A.5, 2
B.5, 3
C.3, 2
D.3, 1
选B,解析如下:
17.对N个不同的数据采用冒泡算法进行从大到小的排序,下面哪种情况下肯定交换元素次数最多?
A.从大到小排好的
B.元素无序
C.元素基本有序
D.从小到大排好的
选D,解析:当元素基本有序时,交换元素元素较少,冒泡排序交换次数较少。同理可知,当元素从小到大排好时冒泡排序处于最坏情况。
18.对于序列{ 49,38,65,97,76,13,27,50 },按由小到大进行排序,下面哪一个是初始步长为4的希尔排序法第一趟的结果?
A.97,76,65,50,49,38,27,13
B.49,13,27,50,76,38,65,97
C.49,76,65,13,27,50,97,38
D.13,27,38,49,50,65,76,97
选B,解析:按步长为4划分,则有{49,76},{38,13},{65,27},{97,50}
组内排序得到{49,76},{13,38},{27,65},{50,97}
故第一趟的结果为B
19.输入10^6个只有一位数字的整数,可以用O(N)复杂度将其排序的算法是:(桶排序)
解析:桶排序所需的时间复杂度为O(N)
20.若数据元素序列{ 12, 13, 8, 11, 5, 16, 2, 9 }是采用下列排序方法之一得到的第一趟排序后的结果,则该排序算法只能是:(归并排序)
A. 快速排序
B. 选择排序
C. 堆排序
D. 归并排序
解析:排除选择排序,因为选择排序后,最前面一定是最小的或最大的;排除快速排序,因为找不到枢纽值;排除堆排序,建堆后可看出不符合
21.在内部排序时,若选择了归并排序而没有选择插入排序,则可能的理由是:(3)
1 归并排序的程序代码更短
2 归并排序占用的空间更少
3 归并排序的运行效率更高
22.设有1000个元素的有序序列,如果用二分插入排序再插入一个元素,则最大比较次数是:
A.10
B.500
C.1000
D.999
选A,解析:2^10=1024>1000
23.对N个记录进行归并排序,空间复杂度为:O(N)(对)
24.令 n 表征问题规模,下列程序段的时间复杂度是( )。
x=0;
while((x+1)*(x+1)<=n^3)
x=x+1;
A.O(log n)
B.O(n^(3/2))
C.O(n^2)
D.O(n)
选B,x+1<=n^(3/2)
25.解析:2^11=2048
26.计数排序O(n),归并排序O(nlogn)
所以A
填空题
{46 79 56 38 40 84}以46为基准进行快速排序,则第一次的结果为?
46与84换 得到
84 79 56 38 40 46
接着左指针从84开始向右找比46大的数 右指针从46开始向左找比46小的数
故84与40换 得到
40 79 56 38 84 46
接着79与38换
40 38 56 79 84 46
现在两个指针都在56 不需要换
因此将46插入38后面即可得到第一次的结果
1.插入排序
排序方法中,从未排序序列中依次取出元素与已排序序列中的元素进行比较,将其放入已排序序列的正确位置的方法称为:(插入排序)
2.另类选择排序
3.冒泡排序
本题要求用冒泡排序将一组整数按增序排序。冒泡排序每次从头到尾扫描待排序列,检查相邻两数的顺序,如果顺序不对就交换。请补全下列冒泡排序的代码。
typedef struct node *nodeptr;
struct node{
int value;
nodeptr next;
/* 一些其他的项,在此忽略 */
};
nodeptr BubbleSort (nodeptr h)
{/* h 是带空头结点的链表的头指针 */
nodeptr p, q;
int flag_swap;
if (!h->next) return h;
do{
flag_swap = 0;
p = h;
while (p->next->next){
if ( p->next->value>p->next->next->value (3分) ){
flag_swap++;
q = p->next;
p->next=q->next (3分);
q->next=p->next->next (3分);
p->next->next=q (3分);
}
else p = p->next;
}
} while (flag_swap > 0);
return h;
}
4.快速查找第K大元
本函数的功能是从有N
个元素的线性表A
中查找第K
大的元素。函数的初始调用为Qselect(A, K, 0, N-1)
。请完成下列填空。
ElementType Qselect( ElementType A[], int K, int Left, int Right )
{
ElementType Pivot = A[Left];
int L = Left, R = Right+1;
while (1) {
while ( A[++L] > Pivot ) ;
________________________
//填while ( A[--R] < Pivot )
if ( L < R ) Swap( &A[L], &A[R] );
else break;
}
Swap( &A[Left], &A[R] );
if ( K < (L-Left) )
return Qselect(A, K, Left, R-1);
else if ( K > (L-Left) )
________________________
//填return Qselect(A, K-(L-Left), L, Right)
else
return Pivot;
}
至此,我们完成了排序算法的排序、选择、填空的相关练习,在下一篇文章中我们将进行排序算法编程题的练习。